Browse Source

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

lmstack 3 years ago
parent
commit
fe3c901744

+ 215 - 0
LIB/MIDDLE/CellStateEstimation/BatSafetyAlarm/V1_0_1/CBMSSafetyAlarm.py

@@ -0,0 +1,215 @@
+import pandas as pd
+import numpy as np
+import datetime
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class SafetyAlarm:
+    def __init__(self,sn,celltype,df_bms,df_bms_ram):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_bms=df_bms
+        self.df_bms_ram=df_bms_ram
+        df_bms['时间戳']=pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+
+        if not df_bms_ram.empty:
+            self.df_bms=self.df_bms[self.df_bms['时间戳'] > df_bms_ram.iloc[-1]['time']]    #滤除原始数据中的重复数据
+            self.df_bms.reset_index(inplace=True,drop=True)     #重置索引
+        
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bmstime= df_bms['时间戳']
+
+        self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        othertemp=['其他温度'+str(x) for x in range(1,self.param.OtherTempNums+1)]
+        celltemp=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.celltemp_name=celltemp+othertemp
+
+    
+    def diag(self):
+        if self.celltype<=50:
+            df_res=self._ncm_diag()
+            return df_res    
+        else:
+            df_res=self._ncm_diag()
+            return df_res
+        
+
+    #定义滑动滤波函数.............................................................................................
+    def _np_move_avg(self,a, n, mode="same"): 
+        return (np.convolve(a, np.ones((n,)) / n, mode=mode))
+    
+    #寻找当前行数据的所有温度值...................................................................................
+    def _celltemp_get(self,num):   
+        celltemp = list(self.df_bms.loc[num,self.celltemp_name])
+        return celltemp
+
+    #获取当前行所有电压数据............................................................................................
+    def _cellvolt_get(self,num): 
+        cellvolt = list(self.df_bms.loc[num,self.cellvolt_name]/1000)
+        return cellvolt
+
+    #..........................................三元电池诊断功能..................................................................
+    def _ncm_diag(self):
+
+        column_name=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice']
+        df_res=pd.DataFrame(columns=column_name)
+
+        end_time='0000-00-00 00:00:00'
+        celltemprise=0
+        celltemphigh=0
+        cellvoltfall=0
+        cellvoltdiff=0
+        packvoltfall=0
+            
+        for i in range(len(self.df_bms)):
+            
+            #温度诊断功能.............................................................................................................
+            temp2=np.array(self._celltemp_get(i))
+            celltempmin=min(temp2)
+            celltempmax=max(temp2)
+            #温度有效性判断...........................................................................
+            if celltempmax>self.param.CellTempUpLmt or celltempmin<self.param.CellTempLwLmt:
+                celltempvalid=0
+            else:   #不作处理
+                celltempvalid=1
+
+            if celltempvalid==1:
+                
+                #过温判断............................................................................................................................
+                if celltempmax>self.param.TrwTempHigh:
+                    celltemphigh=1
+                else:
+                    pass
+            
+                
+                #温升判断.............................................................................................................................
+                if i<1:
+                    if not self.df_bms_ram.empty:
+                        time1=self.df_bms_ram.iloc[-1]['time']
+                        time2=self.bmstime[i]
+                        temp1=np.array(self.df_bms_ram.iloc[-1]['celltemp'])
+
+                        delttime=(time2-time1).total_seconds()
+                        celltemp_rate=(max(temp2-temp1)*60)/delttime    #计算最大温升速率
+                        if celltemp_rate>self.param.TrwTempRate:
+                            celltemprise=1
+                        else:
+                            pass
+                    else:
+                        pass
+                else:
+                    time1=self.bmstime[i-1]
+                    time2=self.bmstime[i]
+                    temp1=np.array(self._celltemp_get(i-1))
+
+                    delttime=(time2-time1).total_seconds()
+                    celltemp_rate=(max(temp2-temp1)*60)/delttime    #计算最大温升速率
+                    if celltemp_rate>self.param.TrwTempRate:
+                        celltemprise=1
+                    else:
+                        pass
+            
+            else:
+                pass
+            
+            #电压诊断功能.........................................................................................................................................
+            cellvolt=self._cellvolt_get(i)
+            cellvolt2=np.array(cellvolt)
+            cellvoltmin=min(cellvolt)
+            cellvoltmax=max(cellvolt)
+            cellvoltmin_index=cellvolt.index(cellvoltmin)
+            cellvoltmax_index=cellvolt.index(cellvoltmax)
+
+            #电压有效性..........................................................................................................................................
+            if (cellvoltmin<2 and cellvoltmax>4.5 and (cellvoltmax_index-cellvoltmin_index)==1) or cellvoltmin<0.01:   #电压断线故障进入
+                cellvoltvalid=0
+            else:
+                cellvoltvalid=1
+   
+            if cellvoltvalid==1:
+                #单体电压跌落诊断...........................................................................................................................
+                if i<1:
+                    if not self.df_bms_ram.empty:
+                        time1=self.df_bms_ram.iloc[-1]['time']
+                        time2=self.bmstime[i]
+                        delttime=(time2-time1).total_seconds()
+                        cellvolt1=np.array(self.df_bms_ram.iloc[-1]['cellvolt'])
+                        if delttime<310:
+                            if self.packcrnt[i]<0.5 and max(cellvolt2-cellvolt1)>self.param.TrwCellVoltFall:
+                                cellvoltfall=1
+                            elif self.packcrnt[i]>0.5 and max(cellvolt2-cellvolt1)-self.packcrnt[i]*0.01>self.param.TrwCellVoltFall:
+                                cellvoltfall=1
+                            else:
+                                pass
+                        else:
+                            if min(cellvolt2)<self.param.TrwCellVoltLow:  #电压跌落至<1.5V
+                                cellvoltfall=1
+                            else:
+                                pass
+                    else:
+                        pass
+                else:
+                    delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+                    cellvolt1=np.array(self._cellvolt_get(i-1))
+                    if self.packcrnt[i]<0.5 and max(cellvolt2-cellvolt1)>self.param.TrwCellVoltFall:
+                        cellvoltfall=1
+                    elif self.packcrnt[i]>0.5 and max(cellvolt2-cellvolt1)-self.packcrnt[i]*0.01>self.param.TrwCellVoltFall:
+                        cellvoltfall=1
+                    else:
+                        pass
+                
+                #压差诊断........................................................................................................................................
+                if (max(cellvolt2)-min(cellvolt2))>self.param.TrwCellVoltDiff:
+                    cellvoltdiff=1
+                else:
+                    pass
+            
+            else:
+                pass
+                
+            #电池包诊断.....................................................................................................................................
+            if i<1:
+                if not self.df_bms_ram.empty:
+                    time1=self.df_bms_ram.iloc[-1]['time']
+                    time2=self.bmstime[i]
+                    delttime=(time2-time1).total_seconds()
+                    packvolt1=self.df_bms_ram.iloc[-1]['packvolt']
+                    packvolt2=self.packvolt[i]
+                    if delttime<310:
+                        if self.packcrnt[i]<5 and (packvolt2-packvolt1)>self.param.TrwPackVoltFall:
+                            packvoltfall=1
+                        else:
+                            pass
+                    else:
+                        pass
+                else:
+                    packvolt2=self.packvolt[i]
+            else:
+                packvolt1=self.packvolt[i-1]
+                packvolt2=self.packvolt[i]
+                if self.packcrnt[i]<5 and (packvolt2-packvolt1)>self.param.TrwPackVoltFall:
+                    packvoltfall=1
+                else:
+                    pass
+        
+        #热失控故障判断........................................................................................................................
+        df_bms_ram=pd.DataFrame(columns=['time', 'sn', 'packvolt',  'cellvolt', 'celltemp'])
+        df_bms_ram.loc[0]=[self.bmstime[0], self.sn, packvolt2, list(cellvolt2), list(temp2)]
+        if celltemprise==1 or celltemphigh==1:
+            trwtemp=1
+        else:
+            trwtemp=0
+
+        if cellvoltfall==1 or cellvoltdiff==1:
+            trwcellvolt=1
+        else:
+            trwcellvolt=0
+        
+        if trwtemp+trwcellvolt+packvoltfall>1.5:
+            fltcode=119
+            df_res.loc[0]=[self.bmstime[0], end_time, self.sn, fltcode, 5, '电池发生热失控', '立刻远离电池']
+            return df_res, df_bms_ram
+        else:
+            return pd.DataFrame(), df_bms_ram

+ 132 - 0
LIB/MIDDLE/CellStateEstimation/BatSafetyAlarm/main.py

@@ -0,0 +1,132 @@
+import CBMSSafetyAlarm
+import datetime
+import pandas as pd
+import multiprocessing
+from LIB.BACKEND import DBManager, Log
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def diag_cal(sn_list, df_diag_ram, df_bms_ram):
+    
+    start=time.time()
+    now_time=datetime.datetime.now()
+    start_time=now_time-datetime.timedelta(seconds=70)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=now_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    for sn in sn_list:
+        if 'PK500' in sn:
+            celltype=1 #6040三元电芯
+        elif 'PK502' in sn:
+            celltype=2 #4840三元电芯
+        elif 'K504B' in sn:
+            celltype=99    #60ah林磷酸铁锂电芯
+        elif 'MGMLXN750' in sn:
+            celltype=3 #力信50ah三元电芯
+        elif 'MGMCLN750' or 'UD' in sn: 
+            celltype=4 #CATL 50ah三元电芯
+        else:
+            print('SN:{},未找到对应电池类型!!!'.format(sn))
+            continue
+            # sys.exit()
+
+        #读取原始数据库数据........................................................................................................................................................
+        dbManager = DBManager.DBManager()
+        df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms'])
+        df_bms = df_data['bms']
+        # print(df_bms)
+
+        #电池诊断................................................................................................................................................................
+        if not df_bms.empty:
+            df_diag_ram_sn=df_diag_ram[df_diag_ram['product_id']==sn]
+            df_bms_ram_sn=df_bms_ram[df_bms_ram['sn']==sn]
+            if df_diag_ram_sn.empty:
+                SafetyAlarm=CBMSSafetyAlarm.SafetyAlarm(sn,celltype,df_bms, df_bms_ram_sn)
+                df_diag_res, df_bms_res=SafetyAlarm.diag() 
+
+                #更新bms的ram数据 和 diag的Ram数据
+                sn_index=df_bms_ram.loc[df_bms_ram['sn']==sn].index
+                df_bms_ram=df_bms_ram.drop(index=sn_index)
+                df_bms_ram=df_bms_ram.append(df_bms_res)
+
+                sn_index=df_diag_ram.loc[df_diag_ram['product_id']==sn].index
+                df_diag_ram=df_diag_ram.drop(index=sn_index)
+                df_diag_ram=df_diag_ram.append(df_diag_res)
+                df_diag_ram.reset_index(inplace=True,drop=True)     #重置索引
+
+                #当前热失控故障写入数据库
+                if not df_diag_res.empty:
+                    with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\06BatSafetyAlarm\热失控.txt','a') as file:
+                        file.write(str(tuple(df_diag_res.iloc[-1]))+'\n')
+                
+            #当前热失控已超过三天变为历史故障并写入数据库,并删除原有数据库中的当前故障和ram中的当前故障
+            elif (now_time-df_bms_ram_sn.iloc[-1]['time']).total_seconds()>3*24*3600:
+                df_diag_ram=df_diag_ram.drop(df_diag_ram['sn']==sn)    #删除ram中的当前故障
+                df_bms_ram_sn.iloc[-1]['end_time']=now_time
+                with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\06BatSafetyAlarm\热失控.txt','a') as file:
+                        file.write(str(tuple(df_diag_res.iloc[-1]))+'\n')
+
+
+
+        #故障处理........................................................................................................................................................
+
+        end=time.time()
+        print(end-start)
+        # print(df_soh)
+
+#...................................................主进程...........................................................................................................
+def mainprocess():
+    global SNnums
+    global df_diag_ram
+    global df_bms_ram
+    process = 2
+    pool = multiprocessing.Pool(processes = process)
+
+    for i in range(process):
+        sn_list = SNnums[i]
+        pool.apply_async(diag_cal, (sn_list,df_diag_ram,df_bms_ram))
+
+    pool.close()
+    pool.join()
+
+
+#...............................................主函数起定时作用.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\sn-20210903.xlsx'
+    SNdata_6060 = pd.read_excel(excelpath, sheet_name='科易6060')
+    SNdata_6040 = pd.read_excel(excelpath, sheet_name='科易6040')
+    SNdata_4840 = pd.read_excel(excelpath, sheet_name='科易4840')
+    SNdata_L7255 = pd.read_excel(excelpath, sheet_name='格林美-力信7255')
+    SNdata_C7255 = pd.read_excel(excelpath, sheet_name='格林美-CATL7255')
+    SNdata_U7255 = pd.read_excel(excelpath, sheet_name='优旦7255')
+    SNnums_6060=SNdata_6060['SN号'].tolist()
+    SNnums_6040=SNdata_6040['SN号'].tolist()
+    SNnums_4840=SNdata_4840['SN号'].tolist()
+    SNnums_L7255=SNdata_L7255['SN号'].tolist()
+    SNnums_C7255=SNdata_C7255['SN号'].tolist()
+    SNnums_U7255=SNdata_U7255['SN号'].tolist()
+    SNnums=[SNnums_L7255 + SNnums_C7255 + SNnums_U7255, SNnums_6040 + SNnums_4840 + SNnums_6060]
+    # SNnums=['PK50201A000002201']
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取...................................
+    result=pd.read_excel(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\06BatSafetyAlarm\result.xlsx')
+    df_diag_ram=result[(result['end_time']=='0000-00-00 00:00:00') & (result['code']==119)]
+    df_bms_ram=pd.DataFrame(columns=['time', 'sn', 'packvolt', 'cellvolt', 'celltemp'])
+
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(mainprocess, 'interval', seconds=60, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 14 - 1
LIB/MIDDLE/CellStateEstimation/Common/V1_0_1/BatParam.py

@@ -1,6 +1,5 @@
 
 #定义电池参数
-
 class BatParam:
     def __init__(self,celltype):
 
@@ -15,6 +14,15 @@ class BatParam:
         self.CellTempDiffLv2=15
         self.CellTempRate=5
 
+       #热失控参数
+        self.TrwTempHigh=60
+        self.TrwTempRate=20
+        self.TrwTempDiff=15
+        self.TrwCellVoltDiff=2.5
+        self.TrwCellVoltFall=1
+        self.TrwCellVoltLow=1.5
+        self.TrwPackVoltFall=2
+
         self.SocJump=3
         self.SocClamp=0.1
         self.SocLow=3
@@ -43,6 +51,7 @@ class BatParam:
             self.CellFullChrgCrnt=-15
             self.CellVoltNums=17
             self.CellTempNums=4
+            self.OtherTempNums=5
             self.FullChrgSoc=98
             self.PackCrntDec=1
             self.BalCurrent=0.015
@@ -74,6 +83,7 @@ class BatParam:
             self.CellFullChrgCrnt=-15
             self.CellVoltNums=14
             self.CellTempNums=4
+            self.OtherTempNums=4
             self.FullChrgSoc=98
             self.PackCrntDec=1
             self.BalCurrent=0.015
@@ -105,6 +115,7 @@ class BatParam:
             self.CellFullChrgCrnt=-15
             self.CellVoltNums=20
             self.CellTempNums=4
+            self.OtherTempNums=4
             self.FullChrgSoc=98
             self.PackCrntDec=1
             self.BalCurrent=0.015
@@ -136,6 +147,7 @@ class BatParam:
             self.CellFullChrgCrnt=-15
             self.CellVoltNums=20
             self.CellTempNums=2
+            self.OtherTempNums=0
             self.FullChrgSoc=98
             self.PeakSoc=57
             self.PackCrntDec=-1
@@ -175,6 +187,7 @@ class BatParam:
             self.SocInflexion3=70
             self.CellVoltNums=20
             self.CellTempNums=4
+            self.OtherTempNums=5
             self.FullChrgSoc=98
             self.PeakSoc=59
             self.PeakVoltLowLmt=3.35