# 获取数据
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=30)
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')
