import pandas as pd
import numpy as np
import datetime
import bisect
import matplotlib.pyplot as plt
import BatParam

class BatSoh:
    def __init__(self,sn,celltype,df_bms,df_volt,df_temp,df_accum):  #参数初始化

        self.sn=sn
        self.celltype=celltype
        CellVoltNums=int(df_volt.loc[5,'单体电池总数'])
        if CellVoltNums==110:
            self.celltype=99
        else:
            self.celltype==100
        self.param=BatParam.BatParam(self.celltype)
        self.df_volt=df_volt
        self.df_temp=df_temp
        self.bmsstat=df_bms['充电状态']
        self.packcrnt=(df_volt['可充电储能装置电流(A)'].astype('float'))*self.param.PackCrntDec
        self.packvolt=df_volt['可充电储能装置电压(V)'].astype('float')
        self.bms_soc=df_bms['SOC']
        # self.bms_soh=df_volt['SOH[%]']
        self.bmstime= pd.to_datetime(df_volt['上报时间'], format='%Y-%m-%d %H:%M:%S')
        self.param.CellVoltNums=CellVoltNums
        self.param.CellTempNums=int(df_temp.loc[5,'可充电储能温度探针个数'])



    def batsoh(self):
        if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4 or self.celltype==100:
            df_res=self._ncmsoh_chrg()
            return df_res
            
        elif self.celltype==99:
            df_res=self._lfpsoh()
            return df_res

        else:
            return pd.DataFrame()

    
    #定义滑动滤波函数.........................................................................................................................
    def _np_move_avg(self,a, n, mode="same"):
        return (np.convolve(a, np.ones((n,)) / n, mode=mode))

    #寻找当前行数据的最小温度值.................................................................................................................
    def _celltemp_weight(self,num):   
        celltemp = []
        for j in range(1, self.param.CellTempNums+1):
            s = str(j)
            celltemp.append(self.df_temp.loc[num, s+'.0'])
        celltemp.remove(min(celltemp))
        self.celltemp=celltemp
        if self.celltype==99:
            if min(celltemp)>=20:
                self.tempweight=1
                self.StandardStandingTime=1800
            elif min(celltemp)>=10:
                self.tempweight=0.5
                self.StandardStandingTime=3600
            elif min(celltemp)>=5:
                self.tempweight=0
                self.StandardStandingTime=7200
            else:
                self.tempweight=0
                self.StandardStandingTime=10800
        else:
            if min(celltemp)>=20:
                self.tempweight=1
                self.StandardStandingTime=1800
            elif min(celltemp)>=10:
                self.tempweight=0.8
                self.StandardStandingTime=3600
            elif min(celltemp)>=5:
                self.tempweight=0.3
                self.StandardStandingTime=3600
            else:
                self.tempweight=0.1
                self.StandardStandingTime=7200

    #获取SOC差对应的SOH权重值...................................................................................................................
    def _deltsoc_weight(self,deltsoc):   
        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_volt.loc[num, s+'.0'])
        return cellvolt
    
    #筛选充电数据..............................................................................................................................
    def _chrgdata(self):    
        self.ChgStart=[]
        self.ChgEnd=[]
        if len(self.packvolt)>100:
            charging=0
            for i in range(3, len(self.bmstime) - 3):
                if charging==0:
                    if i==3 and self.bmsstat[i]=='停车充电' and self.bmsstat[i+1]=='停车充电':
                        self.ChgStart.append(i)
                        charging=1
                    elif self.bmsstat[i-1]!='停车充电' and self.bmsstat[i]=='停车充电':
                        self.ChgStart.append(i)
                        charging=1
                    else:
                        pass
                else:
                    if (self.bmsstat[i-1]=='停车充电' or '充电完成') and self.packcrnt[i]>0:
                        self.ChgEnd.append(i)
                        charging=0
                    elif i == (len(self.bmstime) - 4) and (self.bmsstat[i] == '停车充电' or '充电完成') and self.packcrnt[i]<-1:
                        self.ChgEnd.append(len(self.bmstime)-2)
                        charging=0
    
    #dvdq方法计算soh...........................................................................................................................
    def _dvdq_soh(self, chrg_st, chrg_end,cellvolt):    
        Ah = 0  #参数赋初始值
        Volt = cellvolt[chrg_st]
        DV_Volt=[]
        DQ_Ah = []
        DVDQ = []
        time2 = []
        soc2 = []
        Ah_tatal=[0]
        xvolt=[]
        #计算DV和DQ值
        for j in range(chrg_st,chrg_end):
            Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
            Ah=Ah-self.packcrnt[j]*Step/3600
            if (cellvolt[j]-Volt)>0.0019 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(float(self.bms_soc[j].strip('%')))

        #切片,去除前后10min的数据
        df_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=df_Data1.loc[0,'time']
        start_time=start_time+datetime.timedelta(seconds=900)
        end_time=df_Data1.loc[len(time2)-1,'time']
        end_time=end_time-datetime.timedelta(seconds=1200)
        if soc2[0]<36:
            df_Data1=df_Data1[(df_Data1['SOC']>40) & (df_Data1['SOC']<80)]
        else:
            df_Data1=df_Data1[(df_Data1['time']>start_time) & (df_Data1['SOC']<80)]
        df_Data1=df_Data1[(df_Data1['XVOLT']>self.param.PeakVoltLowLmt) & (df_Data1['XVOLT']<self.param.PeakVoltUpLmt)]

        # self._celltemp_weight(int((chrg_st+chrg_end)/2))
        # print(self.packcrnt[int((chrg_st+chrg_end)/2)], min(self.celltemp))
        # ax1 = plt.subplot(3, 1, 1)
        # plt.plot(df_Data1['XVOLT'],df_Data1['DVDQ'],'r*-')
        # plt.xlabel('Volt/V')
        # plt.ylabel('DV/DQ')
        # plt.legend()
        # ax1 = plt.subplot(3, 1, 2)
        # plt.plot(df_Data1['SOC'],df_Data1['XVOLT'],'y*-')
        # plt.xlabel('SOC/%')
        # plt.ylabel('Volt/V')
        # plt.legend()
        # ax1 = plt.subplot(3, 1, 3)
        # plt.plot(df_Data1['SOC'], df_Data1['DVDQ'], 'r*-')
        # plt.xlabel('SOC/%')
        # plt.ylabel('DV/DQ')
        # plt.legend()
        # plt.show()

        #寻找峰值并计算Soh
        if len(df_Data1)>1:
            PeakIndex=df_Data1['DVDQ'].idxmax()
            #筛选峰值点附近±0.5%SOC内的数据
            df_Data2=df_Data1[(df_Data1['SOC']>(df_Data1['SOC'][PeakIndex]-0.5)) & (df_Data1['SOC']<(df_Data1['SOC'][PeakIndex]+0.5))]
            if len(df_Data2)>1 and df_Data1.loc[PeakIndex,'XVOLT']<self.param.PeakVoltUpLmt-0.019:
                Ah_tatal1 = df_Data1['Ah_tatal']
                DVDQ = df_Data1['DVDQ']
                soc2 = df_Data1['SOC']
                xvolt = df_Data1['XVOLT']
                if soc2[PeakIndex]>40 and soc2[PeakIndex]<80:
                    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
                        return cellsoh_init
                    else:
                        return cellsoh_init
                else:
                    return 0
            else:
                df_Data1=df_Data1.drop([PeakIndex])
                PeakIndex = df_Data1['DVDQ'].idxmax()
                df_Data2 = df_Data1[(df_Data1['SOC'] > (df_Data1['SOC'][PeakIndex] - 0.5)) & (df_Data1['SOC'] < (df_Data1['SOC'][PeakIndex] + 0.5))]
                if len(df_Data2) > 1 and df_Data1.loc[PeakIndex,'XVOLT']<self.param.PeakVoltUpLmt-0.019:
                    Ah_tatal1 = df_Data1['Ah_tatal']
                    DVDQ = df_Data1['DVDQ']
                    soc2 = df_Data1['SOC']
                    xvolt = df_Data1['XVOLT']
                    if soc2[PeakIndex]>40 and soc2[PeakIndex]<80:
                        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
                            return cellsoh_init
                        else:
                            return cellsoh_init
                    else:
                        return 0
                else:
                    return 0
        else:
            return 0

    #两点法计算三元SOH.........................................................................................................................
    def _ncmsoh_twopoint(self):
        standingpoint_st=[]
        standingpoint_sp=[]
        tempweightlist=[]
        standingtime=0
        for i in range(3,len(self.df_volt)-3):

            if abs(self.packcrnt[i]) < 0.2 and abs(self.packcrnt[i-1]) < 0.2 and abs(self.packcrnt[i+1]) < 0.2:     #电流为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)     #获取当前行电压数据
                            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 3<max(cellvolt_now)<4.5 and 3<min(cellvolt_now)<4.5:
                                if abs(minocv_socst-minocv_socnow)>=30:   #当前时刻SOC与开始时刻SOC差>=40
                                    if abs(self.packcrnt[i+2])>=0.2:    #如果下一时刻电流>=0.5,则压入当前索引
                                        standingpoint_sp.append(i)
                                        standingpoint_st.append(i)
                                        tempweightlist.append(self.tempweight)
                                        standingtime=0
                                        continue
                                    else:
                                        if standingtime>7200 or i==len(self.df_volt)-2:   #仍处于静置,但静置时间>1h,则直接获取sp时刻,或者到了数据末尾
                                            standingpoint_sp.append(i)
                                            tempweightlist.append(self.tempweight)
                                            continue
                                else:
                                    if abs(self.packcrnt[i+2])>=0.2:
                                        standingtime=0
                                        if  minocv_socst<50 and minocv_socnow<minocv_socst:
                                            standingpoint_st[-1]=i
                                            continue
                                    elif abs(self.packcrnt[i+2])>=0.2:
                                        standingtime=0
                                        if minocv_socst>=50 and minocv_socnow>minocv_socst:
                                            standingpoint_st[-1]=i
                                            continue
                                    else:
                                        continue
                        else:
                            if abs(self.packcrnt[i+2])>=0.5:
                                cellvolt_now=self._cellvolt_get(i) 
                                if 3<max(cellvolt_now)<4.5 and 3<min(cellvolt_now)<4.5:
                                    standingpoint_st.append(i)
                                    standingtime=0
                                    continue
                            else:
                                continue
                    else:
                        if abs(self.packcrnt[i+2])>0.5:
                            cellvolt_now=self._cellvolt_get(i) 
                            if 3<max(cellvolt_now)<4.5 and 3<min(cellvolt_now)<4.5:
                                standingpoint_st.append(i)
                                standingtime=0
                                continue
                        else:
                            continue
                else:
                    continue
            else:
                standingtime=0
                continue

        #计算SOH......................................................................................................................
        if standingpoint_sp:
            column_name=['time_st','time_sp','sn','method','soh','cellsoh','detasoh']
            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 Step<60:
                        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.7
                # 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.1
            
                # 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=soh_weight1*0.5
                # else:
                #     if self.param.Capacity*0.7*0.4< abs(ah_packcrnt) <self.param.Capacity:
                #         soh_weight1=soh_weight1*0.3
                #     else:
                #         soh_weight1=0

                cellsoh=[]
                for j in range(self.param.CellVoltNums):    #计算每个电芯的SOH值
                    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*0.5
                    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 55<self.df_soh.loc[len(self.df_soh)-1,'soh']<120:
                    #             cellsoh_last=eval(self.df_soh.loc[len(self.df_soh)-1,'cellsoh'])
                    #             if soh_weight>1/abs(cellsoh_init-cellsoh_last[j]):
                    #                 soh_weight=1/abs(cellsoh_init-cellsoh_last[j])
                    #                 cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
                    #             else:
                    #                 cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
                    #         else:
                    #             cellsoh_cal=cellsoh_init*soh_weight+100*(1-soh_weight)
                    #     else:
                    #         cellsoh_last=eval(df_res.loc[len(df_res)-1,'cellsoh'])
                    #         if soh_weight>1/abs(cellsoh_init-cellsoh_last[j]):
                    #             soh_weight=1/abs(cellsoh_init-cellsoh_last[j])
                    #             cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
                    #         else:
                    #             cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
                    #     cellsoh_cal=eval(format(cellsoh_cal,'.1f'))
                    cellsoh.append(cellsoh_init)
                    # else:
                    #     cellsoh=[]
                    #     break
                if cellsoh:
                    soh=min(cellsoh)
                    soh_list=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1, soh, str(cellsoh),max(cellsoh)-min(cellsoh)]
                    df_res.loc[len(df_res)]=soh_list
                else:
                    continue
            if df_res.empty:
                return pd.DataFrame()
            else:
                return df_res
        return pd.DataFrame()
    
    def _ncmsoh_chrg(self):      
        self._chrgdata()
        print(self.ChgStart,self.ChgEnd)
        ChgStartValid=[]
        ChgEndValid=[]
        for i in range(min(len(self.ChgStart),len(self.ChgEnd))): 
            self._celltemp_weight(self.ChgEnd[i])               #获取温度对应的静置时间及权重            
   
            #筛选满足2点法计算的数据
            StandingTime=0
            StandingTime1=0
            for m in range(max(len(self.packcrnt)-self.ChgEnd[i]-2,self.ChgStart[i]-2)):
                if self.ChgStart[i] - m - 1>0 and 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 self.ChgEnd[i] + m + 1<len(self.packcrnt) and 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:  #筛选静置时间>15min且慢充过程丢失数据少
                    ChgStartValid.append(self.ChgStart[i])
                    ChgEndValid.append(self.ChgEnd[i]+m)
                    break
                if abs(self.packcrnt[self.ChgStart[i] - m - 2])>0.5 and abs(self.packcrnt[self.ChgEnd[i] + m + 2])>0.5:
                    StandingTime=0
                    StandingTime1=0
                    break

        print(ChgStartValid,ChgEndValid)
        if len(ChgStartValid)>0:   #两点法计算Soh
            df_res=pd.DataFrame(columns=('time','sn','soh','cellsoh','deltsoh'))
            soh2=[]

            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()
                    if Step<120:
                        Ah=Ah-self.packcrnt[j+1]*Step/3600
                
                if Ah>10:
                    for j in range(1, self.param.CellVoltNums+1):    #计算每个电芯的Soh
                        s = str(j)
                        OCVStart=self.df_volt.loc[ChgStartValid[i]-1,s+'.0']
                        OCVEnd=self.df_volt.loc[ChgEndValid[i],s+'.0']
                        #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)
                    delasoh=max(soh2)-min(soh2)
                    df_res.loc[len(df_res)]=[self.bmstime[ChgStartValid[i]],self.sn,soh1,soh2,delasoh]
            return df_res

        return pd.DataFrame()

    #两点法和DVDQ法计算磷酸铁锂电池SOH..................................................................................................................
    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_volt)-3):

            #获取两点法法所需数据-开始.................................................................................................................
            if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1 and abs(self.packcrnt[i+1]) < 0.1:     #判断非平台区静置状态
                delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
                standingtime=standingtime+delttime
                self._celltemp_weight(i)     #获取不同温度对应的静置时间

                if standingtime>self.StandardStandingTime:  #静置时间满足要求
                    if 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
                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 charging==0:
                if self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]<=-1 and float(self.bms_soc[i].strip('%'))<40:     #充电开始
                    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: #充电中
                if (self.bmstime[i+1]-self.bmstime[i]).total_seconds()>180 or (self.packcrnt[i]>self.param.Capacity/3 and self.packcrnt[i+1]>self.param.Capacity/3):  #如果充电过程中时间间隔>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:   #判断充电结束
                    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)-4 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:
                    continue 
        
        #开始计算SOH.............................................................................................................................................
        if standingpoint_sp or chrg_end:       
            # self.getdata()  #获取已计算的soh
            column_name=['time_st','time_sp','sn','method','soh','cellsoh']
            df_res=pd.DataFrame(columns=column_name)
        
            #两点法计算SOH........................................................................................................................................
            if standingpoint_sp:    
                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 Step<60:
                            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=ah_packcrnt

                    # 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>60 and cellsoh_init<115:    #判断soh值的有效区间
                        soh_list=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1, cellsoh_init, cellsoh_init]
                        df_res.loc[len(df_res)]=soh_list
                    else:
                        pass
            else:
                pass

            #DVDQ法计算SOH.......................................................................................................................................
            if chrg_end:
                for i in range(len(chrg_end)):
                    cellvolt_max = self.df_volt[ str(cellmaxvolt_number2[i]+1)+'.0']    #获取最大电压
                    cellvolt=self._np_move_avg(cellvolt_max, 3, mode="same")     #对电压进行滑动平均滤

                    cellsoh_init=self._dvdq_soh(chrg_start[i],chrg_end[i],cellvolt)     #dvdq计算soh

                    soh_weight=tempweightlist2[i]*0.25
                    if cellsoh_init>60 and cellsoh_init<115:    #判断soh值的有效区间
                        soh_list=[self.bmstime[chrg_start[i]], self.bmstime[chrg_end[i]], self.sn, 2, cellsoh_init, str(cellsoh_init),soh_weight]
                        df_res.loc[len(df_res)]=soh_list
                    else:
                        pass
            
            #对SOH结果进行滤波处理................................................................................................................................
            return df_res

        return pd.DataFrame()