shangguanlie23 преди 2 години
родител
ревизия
c4de2722a2
променени са 59 файла, в които са добавени 9479 реда и са изтрити 0 реда
  1. 129 0
      USER/LZX/01算法开发/01电压排序/01算法/BatParam.py
  2. 276 0
      USER/LZX/01算法开发/01电压排序/01算法/CBMSBatChrg.py
  3. 276 0
      USER/LZX/01算法开发/01电压排序/01算法/CBMSBatChrgcopy.py
  4. 157 0
      USER/LZX/01算法开发/01电压排序/01算法/QX_BatteryParam.py
  5. 24 0
      USER/LZX/01算法开发/01电压排序/01算法/log.py
  6. 58 0
      USER/LZX/01算法开发/01电压排序/01算法/main.py
  7. 161 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopy.py
  8. 274 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopycopy.py
  9. 95 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopycopycopy.py
  10. 101 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopyvoltrange.py
  11. 71 0
      USER/LZX/01算法开发/01电压排序/01算法/mainvoltrange.py
  12. 14 0
      USER/LZX/01算法开发/01电压排序/01算法/test.py
  13. 61 0
      USER/LZX/01算法开发/01电压排序/01算法/voltrange.py
  14. 29 0
      USER/LZX/01算法开发/01电压排序/01算法/voltrangecopy.py
  15. 24 0
      USER/LZX/01算法开发/02析锂检测/01下载数据/log.py
  16. 84 0
      USER/LZX/01算法开发/02析锂检测/01下载数据/main.py
  17. 78 0
      USER/LZX/01算法开发/02析锂检测/01下载数据/plot.py
  18. 132 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/chrgr_soc_confrm.py
  19. 329 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/data_analy.py
  20. 24 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/log.py
  21. 101 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/main.py
  22. 728 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/chrgr_state.ipynb
  23. 128 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/chrgr_statics_pack.py
  24. 24 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/log.py
  25. 105 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/main.py
  26. 133 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/soc_total.py
  27. 221 0
      USER/LZX/01算法开发/02析锂检测/liplated/BatParam.py
  28. 557 0
      USER/LZX/01算法开发/02析锂检测/liplated/CBMSBatDiag.py
  29. 168 0
      USER/LZX/01算法开发/02析锂检测/liplated/Li_plated.py
  30. 84 0
      USER/LZX/01算法开发/02析锂检测/liplated/SC_SamplingSafty.py
  31. 185 0
      USER/LZX/01算法开发/02析锂检测/liplated/liplated_range.py
  32. 316 0
      USER/LZX/01算法开发/02析锂检测/liplated/liplited_test.py
  33. 24 0
      USER/LZX/01算法开发/02析锂检测/liplated/log.py
  34. 100 0
      USER/LZX/01算法开发/02析锂检测/liplated/main.py
  35. 71 0
      USER/LZX/01算法开发/02析锂检测/析锂检测/liplated_test.ipynb
  36. 65 0
      USER/LZX/01算法开发/02析锂检测/析锂检测/liplated_test2.ipynb
  37. 52 0
      USER/LZX/01算法开发/03电压信息熵/01算法开发/entropy.ipynb
  38. 208 0
      USER/LZX/01算法开发/04故障诊断/BatParam.py
  39. 557 0
      USER/LZX/01算法开发/04故障诊断/CBMSBatDiag.py
  40. 63 0
      USER/LZX/01算法开发/04故障诊断/FeiShuData.py
  41. 66 0
      USER/LZX/01算法开发/04故障诊断/GetFeiShuData.py
  42. 157 0
      USER/LZX/01算法开发/04故障诊断/QX_BatteryParam.py
  43. 84 0
      USER/LZX/01算法开发/04故障诊断/SC_SamplingSafty.py
  44. 491 0
      USER/LZX/01算法开发/04故障诊断/diagfault/CBMSBatDiag.py
  45. 84 0
      USER/LZX/01算法开发/04故障诊断/diagfault/SC_SamplingSafty.py
  46. 164 0
      USER/LZX/01算法开发/04故障诊断/diagfault/main.py
  47. 224 0
      USER/LZX/01算法开发/04故障诊断/main.py
  48. 235 0
      USER/LZX/01算法开发/04故障诊断/maincopy.py
  49. 178 0
      USER/LZX/01算法开发/04故障诊断/maincopy_v1.py
  50. 55 0
      USER/LZX/01算法开发/04故障诊断/test.py
  51. 24 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/log.py
  52. 108 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/main.py
  53. 124 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/sor_est.py
  54. 204 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/sor_est_v0301.py
  55. 275 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/vol_sor_est.ipynb
  56. 24 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/log.py
  57. 165 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/main.py
  58. 275 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/vol_sor_est.ipynb
  59. 255 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/vol_sor_est.py

+ 129 - 0
USER/LZX/01算法开发/01电压排序/01算法/BatParam.py

@@ -0,0 +1,129 @@
+
+#定义电池参数
+from types import CellType
+import sys
+
+class BatParam:
+
+    def __init__(self,celltype):
+
+        # 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 'MGMLXN750' in sn:
+        #     self.celltype=3 #力信50ah三元电芯
+        # elif 'MGMCLN750' in sn: 
+        #     self.celltype=4 #CATL 50ah三元电芯
+        # else:
+        #     print('未找到对应电池编号!!!')
+        #     sys.exit()
+
+        if 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.PackCrntDec=1
+            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,   105]
+            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, 4.263]
+        
+        elif 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.PackCrntDec=1
+            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,   105]
+            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, 4.263]
+        
+        elif celltype==3:   #力信50ah三元电芯
+            self.Capacity = 51
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.357, 	3.455, 	3.493, 	3.540, 	3.577, 	3.605, 	3.622, 	3.638, 	3.655, 	3.677, 	3.707, 	3.757, 	3.815, 	3.866, 	3.920, 	3.976, 	4.036, 	4.099, 	4.166, 	4.237, 	4.325, 4.415]
+        
+        elif celltype==4:   #CATL 50ah三元电芯
+            self.Capacity = 50
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=2
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=-1
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.152, 	3.397, 	3.438, 	3.481, 	3.523, 	3.560, 	3.586, 	3.604, 	3.620, 	3.638, 	3.661, 	3.693, 	3.748, 	3.803, 	3.853, 	3.903, 	3.953, 	4.006, 	4.063, 	4.121, 	4.183, 4.253]
+        
+        elif 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=60.5
+            self.PeakCellVolt=[3.357,3.358,3.359,3.36,3.361]
+            self.PackCrntDec=1
+            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 celltype==100:   #CATL 102ah三元电芯
+            self.Capacity = 102
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=96
+            self.CellTempNums=16
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100]
+            self.LookTab_OCV = [3.397,	3.429,	3.462,	3.507,	3.551,	3.575,	3.600,	3.617,	3.633,	3.658,	3.683,	3.735,	3.786,	3.836,	3.887,	3.939,	3.992,	4.053,	4.113,	4.195,	4.277]
+
+            self.CellTempHighLv1=45
+            self.CellTempHighLv2=50
+            self.CellTempLowLv1=-20
+            self.CellTempLowLv2=-25
+            self.CellTempDiffLv1=10
+            self.CellTempDiffLv2=15
+            self.CellTempRate=0.99
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=1.5*self.Capacity
+            self.PackDisChgOc=3*self.Capacity
+
+            self.SocJump=3
+            self.SocClamp=3
+
+        else:
+            print('未找到对应电池编号!!!')
+            # sys.exit()
+

+ 276 - 0
USER/LZX/01算法开发/01电压排序/01算法/CBMSBatChrg.py

@@ -0,0 +1,276 @@
+import pandas as pd
+import numpy as np
+import bisect
+import datetime
+import matplotlib.pyplot as plt
+import matplotlib.dates as mdates
+import BatParam
+
+class BatChrg:
+    def __init__(self,sn,celltype,df_bms,df_volt,df_temp,df_accum):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_volt=df_volt
+        self.df_temp=df_temp
+        self.df_bms=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.bmsstat=df_bms['充电状态']
+        self.bmstime= pd.to_datetime(df_volt['上报时间'], format='%Y-%m-%d %H:%M:%S')
+        self.param.CellVoltNums=int(df_volt.loc[5,'单体电池总数'])
+        self.param.CellTempNums=int(df_temp.loc[5,'可充电储能温度探针个数'])
+        self.param.PackVoltOvLv1=self.param.CellOvLv1*self.param.CellVoltNums
+        self.param.PackVoltOvLv2=self.param.CellOvLv2*self.param.CellVoltNums
+        self.param.PackVoltUvLv1=self.param.CellUvLv1*self.param.CellVoltNums
+        self.param.PackVoltUvLv2=self.param.CellUvLv2*self.param.CellVoltNums
+    
+    def chrg(self):
+        if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4 or self.celltype==100:
+            df_res=self._ncm_chrg()
+            return df_res
+            
+        elif self.celltype==99:
+            df_res=self._lfp_diag()
+            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_get(self,num):   
+        celltemp = []
+        for j in range(1, self.param.CellTempNums+1):
+            celltemp.append(self.df_temp.loc[num,str(j)+'.0'])
+        return celltemp
+
+    #获取当前行所有电压数据........................................................................................
+    def _cellvolt_get(self,num): 
+        cellvolt=[]
+        for j in range(1, self.param.CellVoltNums+1): 
+            cellvolt.append(self.df_volt.loc[num, str(j)+'.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.002 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=600)
+        # 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['time']<end_time)]
+        # df_Data1=df_Data1[(df_Data1['XVOLT']>self.param.PeakVoltLowLmt) & (df_Data1['XVOLT']<self.param.PeakVoltUpLmt)]
+
+        # plt.figure()
+        # 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(2, 1, 1)
+        plt.plot(df_Data1['SOC'],df_Data1['XVOLT'],'y*-')
+        plt.xlabel('SOC/%')
+        plt.ylabel('Volt/V')
+        plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
+        plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        ax1 = plt.subplot(2, 1, 2)
+        plt.plot(df_Data1['SOC'], df_Data1['DVDQ'], 'r*-')
+        plt.xlabel('SOC/%')
+        plt.ylabel('析锂指标')
+        plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
+        plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        # plt.show()
+
+    #..........................................三元电池充电画像.....................。。。......................................
+    def _ncm_chrg(self):
+        
+        
+        if not self.df_volt.empty:
+            self._chrgdata()
+            print(self.ChgStart,self.ChgEnd)
+            # name=str(self.sn)
+            # with pd.ExcelWriter(r'D:\00WorkSpace\01Python\data_analyze_platform\USER\03hezhong\99Result\\'+name+'.xlsx') as writer:
+            
+            for i in range(len(self.ChgStart)):
+                # df_chgvolt=pd.DataFrame()
+                # chrg_time=self.df_volt['上报时间'][self.ChgStart[i]:self.ChgEnd[i]]
+                # chrg_soc=self.df_bms['SOC'][self.ChgStart[i]:self.ChgEnd[i]]
+                # chrg_crnt=self.df_bms['总电流(A)'][self.ChgStart[i]:self.ChgEnd[i]]
+                for k in range(1, self.param.CellVoltNums+1):
+                    s = str(k)
+                    cellvolt = self.df_volt[s+'.0']
+                    self._dvdq_soh(self.ChgStart[i],self.ChgEnd[i],cellvolt)     #dvdq计算soh
+                plt.show()
+                    
+                    # plt.figure(figsize=(20,10))
+                    # ax1 = plt.subplot(3, 1, 1)
+                    # plt.plot(chrg_soc,'y*-')
+                    # plt.ylabel('SOC/A')
+                    # plt.legend()
+                    # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+
+                    # ax2 = plt.subplot(3, 1, 2)
+                    # plt.plot(chrg_crnt,'y*-')
+                    # plt.ylabel('Crnt/A')
+                    # plt.legend()
+
+                    # for j in range(1, self.param.CellTempNums+1):
+                    #     celltemp=self.df_temp[str(j)+'.0'][self.ChgStart[i]:self.ChgEnd[i]]
+                    #     ax3 = plt.subplot(3, 1, 3)
+                    #     plt.plot(celltemp,'y*-')
+                    #     plt.xlabel('time')
+                    #     plt.ylabel('Temp/℃')
+                    #     plt.legend()
+                    # plt.savefig('./'+str(self.sn)+str(i)+'电流温度.png')
+                    
+                    # plt.figure()
+                    # for j in range(1, self.param.CellVoltNums+1): 
+                    #     cellvolt=self.df_volt[str(j)+'.0'][self.ChgStart[i]:self.ChgEnd[i]]
+                    #     df_chgvolt[j]=cellvolt
+                    # df_chgvolt.plot(linestyle=':',marker='*', figsize=(30,10))
+                    # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+                    # plt.savefig('./'+str(self.sn)+str(i)+'电压.png')
+
+
+                    #     if j <13:
+                    #         color1='r'
+                    #     elif j<25:
+                    #         color1='orange'
+                    #     elif j<37:
+                    #         color1='y'
+                    #     elif j<49:
+                    #         color1='g'
+                    #     elif j<61:
+                    #         color1='c'
+                    #     elif j<73:
+                    #         color1='b'
+                    #     elif j<85:
+                    #         color1='m'
+                    #     else:
+                    #         color1='pink'
+
+                    #     cellvolt=self.df_volt[str(j)+'.0'][self.ChgStart[i]:self.ChgEnd[i]]
+                    #     # ax1 = plt.subplot(3, 1, 1)
+                    #     plt.plot(chrg_time,cellvolt,color=color1,linestyle='-',marker='*')
+                    # plt.xlabel('SOC/%')
+                    # plt.ylabel('Volt/V')
+                    # plt.legend(loc='upper left')
+                    # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+
+                    # 标准差计算及电芯电压排序...................................................................................
+            #         std_error=[]
+            #         df_rank=pd.DataFrame(columns=list(range(1,self.param.CellVoltNums+1)))
+            #         for j in range(self.ChgStart[i],self.ChgEnd[i]):
+            #             cellvolt=self._cellvolt_get(j)
+            #             std_error.append(np.std(cellvolt,ddof=1))   #标准差计算
+
+            #             cellvolt=pd.Series(cellvolt)
+            #             cellvolt_rank=(cellvolt.rank(method='min')).tolist()
+            #             df_rank.loc[len(df_rank)]=cellvolt_rank
+            #         for j in range(1,self.param.CellVoltNums+1):
+            #             df_rank[j].plot(linestyle='-',marker='*')
+            #             # plt.legend()
+            #             # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+            #             # plt.savefig('./'+str(self.sn)+str(i)+'电压排名.png')
+            #             # plt.show() 
+                    
+            #         sheetname=str(self.df_volt.loc[self.ChgStart[i],'上报时间']).replace(':','-')
+            #         df_rank.to_excel(writer,sheet_name=sheetname)
+                
+            # writer.save()
+            # writer.close()
+
+            
+                # plt.figure(figsize=(20,10))
+                # plt.plot(std_error,'r*-')
+                # plt.xlabel('time')
+                # plt.ylabel('std_error')
+                # plt.legend()
+                # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+                # plt.savefig('./'+str(self.sn)+str(i)+'标准差.png')
+
+
+                
+
+                
+                    
+               
+        
+        return pd.DataFrame()
+                
+
+
+
+                
+
+
+                
+
+

+ 276 - 0
USER/LZX/01算法开发/01电压排序/01算法/CBMSBatChrgcopy.py

@@ -0,0 +1,276 @@
+import pandas as pd
+import numpy as np
+import bisect
+import datetime
+import matplotlib.pyplot as plt
+import matplotlib.dates as mdates
+import BatParam
+
+class BatChrg:
+    def __init__(self,sn,celltype,df_bms,df_volt,df_temp,df_accum):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_volt=df_volt
+        self.df_temp=df_temp
+        self.df_bms=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.bmsstat=df_bms['充电状态']
+        self.bmstime= pd.to_datetime(df_volt['上报时间'], format='%Y-%m-%d %H:%M:%S')
+        self.param.CellVoltNums=int(df_volt.loc[5,'单体电池总数'])
+        self.param.CellTempNums=int(df_temp.loc[5,'可充电储能温度探针个数'])
+        self.param.PackVoltOvLv1=self.param.CellOvLv1*self.param.CellVoltNums
+        self.param.PackVoltOvLv2=self.param.CellOvLv2*self.param.CellVoltNums
+        self.param.PackVoltUvLv1=self.param.CellUvLv1*self.param.CellVoltNums
+        self.param.PackVoltUvLv2=self.param.CellUvLv2*self.param.CellVoltNums
+    
+    def chrg(self):
+        if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4 or self.celltype==100:
+            df_res=self._ncm_chrg()
+            return df_res
+            
+        elif self.celltype==99:
+            df_res=self._lfp_diag()
+            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_get(self,num):   
+        celltemp = []
+        for j in range(1, self.param.CellTempNums+1):
+            celltemp.append(self.df_temp.loc[num,str(j)+'.0'])
+        return celltemp
+
+    #获取当前行所有电压数据........................................................................................
+    def _cellvolt_get(self,num): 
+        cellvolt=[]
+        for j in range(1, self.param.CellVoltNums+1): 
+            cellvolt.append(self.df_volt.loc[num, str(j)+'.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.002 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=600)
+        # 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['time']<end_time)]
+        # df_Data1=df_Data1[(df_Data1['XVOLT']>self.param.PeakVoltLowLmt) & (df_Data1['XVOLT']<self.param.PeakVoltUpLmt)]
+
+        # plt.figure()
+        # 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(2, 1, 1)
+        plt.plot(df_Data1['SOC'],df_Data1['XVOLT'],'y*-')
+        plt.xlabel('SOC/%')
+        plt.ylabel('Volt/V')
+        plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
+        plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        ax1 = plt.subplot(2, 1, 2)
+        plt.plot(df_Data1['SOC'], df_Data1['DVDQ'], 'r*-')
+        plt.xlabel('SOC/%')
+        plt.ylabel('析锂指标')
+        plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
+        plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        # plt.show()
+
+    #..........................................三元电池充电画像.....................。。。......................................
+    def _ncm_chrg(self):
+        
+        
+        if not self.df_volt.empty:
+            self._chrgdata()
+            print(self.ChgStart,self.ChgEnd)
+            # name=str(self.sn)
+            # with pd.ExcelWriter(r'D:\00WorkSpace\01Python\data_analyze_platform\USER\03hezhong\99Result\\'+name+'.xlsx') as writer:
+            
+            for i in range(len(self.ChgStart)):
+                # df_chgvolt=pd.DataFrame()
+                # chrg_time=self.df_volt['上报时间'][self.ChgStart[i]:self.ChgEnd[i]]
+                # chrg_soc=self.df_bms['SOC'][self.ChgStart[i]:self.ChgEnd[i]]
+                # chrg_crnt=self.df_bms['总电流(A)'][self.ChgStart[i]:self.ChgEnd[i]]
+                for k in range(1, self.param.CellVoltNums+1):
+                    s = str(k)
+                    cellvolt = self.df_volt[s+'.0']
+                    self._dvdq_soh(self.ChgStart[i],self.ChgEnd[i],cellvolt)     #dvdq计算soh
+                plt.show()
+                    
+                    # plt.figure(figsize=(20,10))
+                    # ax1 = plt.subplot(3, 1, 1)
+                    # plt.plot(chrg_soc,'y*-')
+                    # plt.ylabel('SOC/A')
+                    # plt.legend()
+                    # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+
+                    # ax2 = plt.subplot(3, 1, 2)
+                    # plt.plot(chrg_crnt,'y*-')
+                    # plt.ylabel('Crnt/A')
+                    # plt.legend()
+
+                    # for j in range(1, self.param.CellTempNums+1):
+                    #     celltemp=self.df_temp[str(j)+'.0'][self.ChgStart[i]:self.ChgEnd[i]]
+                    #     ax3 = plt.subplot(3, 1, 3)
+                    #     plt.plot(celltemp,'y*-')
+                    #     plt.xlabel('time')
+                    #     plt.ylabel('Temp/℃')
+                    #     plt.legend()
+                    # plt.savefig('./'+str(self.sn)+str(i)+'电流温度.png')
+                    
+                    # plt.figure()
+                    # for j in range(1, self.param.CellVoltNums+1): 
+                    #     cellvolt=self.df_volt[str(j)+'.0'][self.ChgStart[i]:self.ChgEnd[i]]
+                    #     df_chgvolt[j]=cellvolt
+                    # df_chgvolt.plot(linestyle=':',marker='*', figsize=(30,10))
+                    # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+                    # plt.savefig('./'+str(self.sn)+str(i)+'电压.png')
+
+
+                    #     if j <13:
+                    #         color1='r'
+                    #     elif j<25:
+                    #         color1='orange'
+                    #     elif j<37:
+                    #         color1='y'
+                    #     elif j<49:
+                    #         color1='g'
+                    #     elif j<61:
+                    #         color1='c'
+                    #     elif j<73:
+                    #         color1='b'
+                    #     elif j<85:
+                    #         color1='m'
+                    #     else:
+                    #         color1='pink'
+
+                    #     cellvolt=self.df_volt[str(j)+'.0'][self.ChgStart[i]:self.ChgEnd[i]]
+                    #     # ax1 = plt.subplot(3, 1, 1)
+                    #     plt.plot(chrg_time,cellvolt,color=color1,linestyle='-',marker='*')
+                    # plt.xlabel('SOC/%')
+                    # plt.ylabel('Volt/V')
+                    # plt.legend(loc='upper left')
+                    # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+
+                    # 标准差计算及电芯电压排序...................................................................................
+            #         std_error=[]
+            #         df_rank=pd.DataFrame(columns=list(range(1,self.param.CellVoltNums+1)))
+            #         for j in range(self.ChgStart[i],self.ChgEnd[i]):
+            #             cellvolt=self._cellvolt_get(j)
+            #             std_error.append(np.std(cellvolt,ddof=1))   #标准差计算
+
+            #             cellvolt=pd.Series(cellvolt)
+            #             cellvolt_rank=(cellvolt.rank(method='min')).tolist()
+            #             df_rank.loc[len(df_rank)]=cellvolt_rank
+            #         for j in range(1,self.param.CellVoltNums+1):
+            #             df_rank[j].plot(linestyle='-',marker='*')
+            #             # plt.legend()
+            #             # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+            #             # plt.savefig('./'+str(self.sn)+str(i)+'电压排名.png')
+            #             # plt.show() 
+                    
+            #         sheetname=str(self.df_volt.loc[self.ChgStart[i],'上报时间']).replace(':','-')
+            #         df_rank.to_excel(writer,sheet_name=sheetname)
+                
+            # writer.save()
+            # writer.close()
+
+            
+                # plt.figure(figsize=(20,10))
+                # plt.plot(std_error,'r*-')
+                # plt.xlabel('time')
+                # plt.ylabel('std_error')
+                # plt.legend()
+                # plt.title(str(self.sn)+str(self.df_volt.loc[self.ChgStart[i],'上报时间']))
+                # plt.savefig('./'+str(self.sn)+str(i)+'标准差.png')
+
+
+                
+
+                
+                    
+               
+        
+        return pd.DataFrame()
+                
+
+
+
+                
+
+
+                
+
+

+ 157 - 0
USER/LZX/01算法开发/01电压排序/01算法/QX_BatteryParam.py

@@ -0,0 +1,157 @@
+class BatteryInfo():
+    def __init__(self,celltype):
+        self.CellMaxUSBTemp=55
+        self.AllowChgMinTemp=0
+        self.AllowDsChgTemp=-5
+        self.AvgVolGap=1
+        self.AvgCellTempGap=10
+        self.AvgOtherTempGap=30
+        self.PackOTlmt=65
+        self.PackUTlmt=-20
+        self.OtherOTlmt=91
+        self.OtherUTlmt=-20        
+        self.FaultCount=100
+
+
+
+        if celltype==1: #6040
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=17
+            self.CellTempNums=4
+            self.OtherTempNums=5
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+            self.BLVol = 3
+            self.CellOVlmt=4#原为5
+            self.CellUVlmt=3.7#原为2
+            self.CantChrgVol=3
+          
+        elif celltype==2: #4840
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=14
+            self.CellTempNums=4
+            self.OtherTempNums=5            
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3        
+
+        elif  celltype==3:   #力信50ah三元电芯
+            self.Capacity = 51
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.OtherTempNums=1
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.357, 	3.455, 	3.493, 	3.540, 	3.577, 	3.605, 	3.622, 	3.638, 	3.655, 	3.677, 	3.707, 	3.757, 	3.815, 	3.866, 	3.920, 	3.976, 	4.036, 	4.099, 	4.166, 	4.237, 	4.325, 4.415]
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3
+
+        elif celltype==4:   #CATL 50ah三元电芯
+            self.Capacity = 50
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=2
+            self.OtherTempNums=0
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=-1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.152, 	3.397, 	3.438, 	3.481, 	3.523, 	3.560, 	3.586, 	3.604, 	3.620, 	3.638, 	3.661, 	3.693, 	3.748, 	3.803, 	3.853, 	3.903, 	3.953, 	4.006, 	4.063, 	4.121, 	4.183, 4.253]
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3
+          
+
+        elif 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.OtherTempNums=5 
+            self.FullChrgSoc=98
+            self.PeakSoc=59
+            self.PeakVoltLowLmt=3.35
+            self.PeakVoltUpLmt=3.4
+            self.PeakCellVolt=[3.362,3.363,3.365,3.366,3.367]
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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]
+            self.BLVol = 3
+            self.CellOVlmt=4
+            self.CellUVlmt=2
+            self.CantChrgVol=2.6
+ 
+        elif celltype==100:
+            self.Capacity = 14
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=10
+            self.CellTempNums=1
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.LookTab_SOC = [0,	1,	2,	3,	4,	5,	6,	7,	8,	9,	10,	11,	12,	13,	14,	15,	16,	17,	18,	19,	20,	21,	22,	23,	24,	25,	26,	27,	28,	29,	30,	31,	32,	33,	34,	35,	36,	37,	38,	39,	40,	41,	42,	43,	44,	45,	46,	47,	48,	49,	50,	51,	52,	53,	54,	55,	56,	57,	58,	59,	60,	61,	62,	63,	64,	65,	66,	67,	68,	69,	70,	71,	72,	73,	74,	75,	76,	77,	78,	79,	80,	81,	82,	83,	84,	85,	86,	87,	88,	89,	90,	91,	92,	93,	94,	95,	96,	97,	98,	100]
+            self.LookTab_OCV = [2.841,	3.064,	3.181,	3.261,	3.322,	3.372,	3.413,	3.445,	3.464,	3.475,	3.482,	3.489,	3.495,	3.502,	3.51,	3.519,	3.529,	3.537,	3.545,	3.553,	3.562,	3.57,	3.578,	3.586,	3.594,	3.602,	3.611,	3.621,	3.631,	3.642,	3.655,	3.668,	3.681,	3.694,	3.708,	3.722,	3.735,	3.748,	3.761,	3.771,	3.782,	3.791,	3.799,	3.807,	3.81,	3.814,	3.82,	3.826,	3.832,	3.836,	3.841,	3.847,	3.852,	3.856,	3.861,	3.866,	3.871,	3.875,	3.88,	3.885,	3.891,	3.896,	3.903,	3.91,	3.917,	3.926,	3.936,	3.944,	3.953,	3.961,	3.969,	3.976,	3.983,	3.991,	3.997,	4.004,	4.01,	4.016,	4.022,	4.026,	4.03,	4.034,	4.037,	4.041,	4.044,	4.048,	4.052,	4.056,	4.06,	4.064,	4.069,	4.075,	4.081,	4.088,	4.097,	4.106,	4.116,	4.129,	4.145,	4.164]
+
+            self.CellTempHighLv1=45
+            self.CellTempHighLv2=50
+            self.CellTempLowLv1=-20
+            self.CellTempLowLv2=-25
+            self.CellTempDiffLv1=10
+            self.CellTempDiffLv2=15
+            self.CellTempRate=0.99
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=1.5*self.Capacity
+            self.PackDisChgOc=3*self.Capacity
+
+            self.SocJump=3
+            self.SocClamp=3
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3
+        else:
+            print('未找到对应电池编号!!!')
+            # sys.exit()

+ 24 - 0
USER/LZX/01算法开发/01电压排序/01算法/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=r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 58 - 0
USER/LZX/01算法开发/01电压排序/01算法/main.py

@@ -0,0 +1,58 @@
+import CBMSBatChrg
+import log
+#coding=utf-8
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from sqlalchemy import create_engine
+import time, datetime
+import os
+
+dbManager = DBManager.DBManager()
+if __name__ == "__main__":
+    filepath=r'D:\00WorkSpace\01Python\data_analyze_platform\USER\03hezhong\98Download'
+    files=os.listdir(filepath)
+
+    # 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)
+    # start_time=str(start_time)
+
+    #log信息配置
+    mylog=log.Mylog('log.txt','error')
+    mylog.logcfg()
+
+    for filename in files:
+        try:
+            # filename=files[0]
+            print(filename)
+            sn=filename[0:23]
+            celltype=100
+            start_time='2021-04-01 19:12:26'
+            end_time='2021-09-02 19:12:26'
+            df_volt = pd.read_excel(filepath+'\\'+filename,sheet_name='单体电池电压数据')
+            df_temp = pd.read_excel(filepath+'\\'+filename,sheet_name='单体电池温度数据')
+            df_bms = pd.read_excel(filepath+'\\'+filename,sheet_name='整车数据')
+            df_volt.columns=df_volt.loc[0].astype('str')
+            df_temp.columns=df_temp.loc[0].astype('str')
+            df_volt=df_volt.drop(0,axis=0)
+            df_temp=df_temp.drop(0,axis=0)
+            df_volt=df_volt.reset_index(drop=True)
+            df_temp=df_temp.reset_index(drop=True)
+            
+            df_accum=pd.DataFrame()
+
+            # df_volt.to_excel(r'D:\00WorkSpace\01Python\data_analyze_platform\USER\03hezhong\99Result\\'+'CBMS_v_'+sn+'.xlsx')
+            # df_temp.to_excel(r'D:\00WorkSpace\01Python\data_analyze_platform\USER\03hezhong\99Result\\'+'CBMS_t_'+sn+'.xlsx')
+            # print(df_volt['1.0'])
+
+            BatChrg=CBMSBatChrg.BatChrg(sn,celltype,df_bms,df_volt,df_temp,df_accum)
+            df_res=BatChrg.chrg()
+            # df_res.to_excel(r'D:\00WorkSpace\01Python\data_analyze_platform\USER\03hezhong\99Result\\'+'CBMS_diag_'+sn+'.xlsx')
+            print(sn,'done!!!')
+             
+        except IndexError as e:
+            print(repr(e))
+            mylog.logopt(sn,e)
+            pass

+ 161 - 0
USER/LZX/01算法开发/01电压排序/01算法/maincopy.py

@@ -0,0 +1,161 @@
+import CBMSBatChrgcopy
+import log
+#coding=utf-8
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+# from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from sqlalchemy import create_engine
+import time, datetime
+import os
+import numpy as np
+from apscheduler.schedulers.blocking import BlockingScheduler
+import QX_BatteryParam
+import pymysql
+import matplotlib.pyplot as plt
+#-------------------------------------------新建电压排序函数--------------------------------------------
+# def CellVolt_rang():
+#     global SNnums
+#     global df_Diag_Ram
+#     start=time.time()
+#     end_time=datetime.datetime.now()
+#     start_time=end_time-datetime.timedelta(seconds=720)
+#     start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+#     end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+print('---------------计算中-------------------------')
+for sn in SNnums:
+    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()
+    param=QX_BatteryParam.BatteryInfo(celltype) 
+    #读取结果数据库数据........................................................................................................................................................
+    host='47.97.96.242'
+    port=3306
+    db='didi'
+    user='root'
+    password='qx123456'
+    tablename='didi_data'
+    param='date,device_id,bat_model,position,current,soc,celltemp,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9'
+    mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+    cursor = mysql.cursor()
+    sql = "select %s from %s where device_id='%s'" %(param,tablename,sn)
+    cursor.execute(sql)
+    res = cursor.fetchall()
+    df_bms= pd.DataFrame(res,columns=param.split(','))
+    cursor.close()
+    mysql.close()
+    # mode=1
+    # # tablename4='cellstateestimation_intershort'
+    # DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)  #mode==1取数据库最后一行数据
+    # with DBRead as DBRead:
+    #     df_data=DBRead.getdata('date,device_id,position,current,soc,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9', tablename=tablename, sn=sn, timename='date', st=start_time, sp=end_time)  
+    # df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\origin_data\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+    #电压排序................................................................................................................................................................
+    df_temp = df_bms[df_bms['position']==2]#筛选充电数据
+    df_chrgr = df_temp.reset_index(drop=True)
+    df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+    df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+    df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+    df_cellvolt_sort_dif = np.diff(df_chrgr_cellvolt_sort)#一次微分
+    df_cellvolt_sort_dif_confir = np.nonzero(df_cellvolt_sort_dif)#取非0值
+    Cell_num = set(df_cellvolt_sort_dif_confir[1])#寻找哪号电芯序号异常np.unique
+    X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+    #df_cellvolt_sort_difdif = np.diff(df_cellvolt_sort_dif)#二次微分
+    problem_data = pd.DataFrame()
+    temp_list = []
+
+    for item in Cell_num:
+        temp_list.append(np.sum(df_cellvolt_sort_dif_confir[1]==item) > X_col/20)
+    
+    if any(temp_list):#序号变化的电芯
+        data_temp = pd.DataFrame(df_chrgr_cellvolt_sort)
+        problem_data = pd.concat([df_chrgr,data_temp], axis = 1)
+    
+    problem_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+    # volt_column = ['0','1','2','3','4','5','6','7']
+    # fig = plt.figure(figsize=(20,10))
+    # length = len(problem_data)
+    # for column in volt_column:
+    #     plt.scatter([x for x in range(0, length)], problem_data[column][0:length], label=column)
+    # plt.legend()
+    # title = problem_data['device_id'][0]
+    # plt.title(title)
+    # plt.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+title+'.png', dpi=300)
+    # plt.show()
+    # fig = plt.figure()
+    # #ax = plt.subplot()
+    # plt.scatter(problem_data['date'], problem_data['0'], c='black',marker='o',alpha=0.5, label = "2#电芯")
+    # plt.scatter(problem_data['date'], problem_data['1'], c='green', marker='o',alpha=0.5, label = "3#电芯")
+    # plt.scatter(problem_data['date'], problem_data['2'], c='red',marker='o', alpha=0.5, label = "4#电芯") 
+    # plt.scatter(problem_data['date'], problem_data['3'], c='black',marker='o',alpha=0.5, label = "5#电芯")
+    # plt.scatter(problem_data['date'], problem_data['4'], c='green', marker='o',alpha=0.5, label = "6#电芯")
+    # plt.scatter(problem_data['date'], problem_data['5'], c='red',marker='o', alpha=0.5, label = "7#电芯")  
+    # plt.scatter(problem_data['date'], problem_data['6'], c='black',marker='o',alpha=0.5, label = "8#电芯")
+    # plt.scatter(problem_data['date'], problem_data['7'], c='green', marker='o',alpha=0.5, label = "9#电芯") 
+    # plt.xlabel("时间", fontsize=15)
+    # plt.ylabel("电压排序", fontsize=15)
+    # title = problem_data['device_id'][0]
+    # plt.title(title, fontsize=20)
+    # plt.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+title+'.png', dpi=300)
+    # plt.show()
+    #print(problem_data)
+
+    end=time.time()
+    print('--------------计算时间:------------')
+    print(end-start)
+    # print(df_soh)
+        
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\sn.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')
+    SNdata_didi = pd.read_excel(excelpath, sheet_name='sn')
+    SNdata_didi_trw = pd.read_excel(excelpath, sheet_name='sn')
+    # 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_didi = SNdata_didi['device_id'].tolist()
+    SNnums_didi_trw = SNdata_didi_trw['device_id'].tolist()
+    # SNnums=SNnums_L7255 + SNnums_C7255 + SNnums_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['BAA3219081550897']
+    SNnums = SNnums_didi_trw
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    #result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\result.csv',encoding='gbk')
+    
+    #df_Diag_Ram=result[result['end_time']=='0000-00-00 00:00:00']
+    print('----------------输入--------')
+    #定时任务.......................................................................................................................................................................
+    # scheduler = BlockingScheduler()
+    # scheduler.add_job(CellVolt_rang, 'interval', seconds=720, id='diag_job')
+
+    # try:  
+    #     scheduler.start()
+    # except Exception as e:
+    #     scheduler.shutdown()
+    #     print(repr(e))
+    #     mylog.logopt(e)

+ 274 - 0
USER/LZX/01算法开发/01电压排序/01算法/maincopycopy.py

@@ -0,0 +1,274 @@
+import CBMSBatChrgcopy
+import log
+#coding=utf-8
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+# from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from sqlalchemy import create_engine
+import time, datetime
+import os
+import numpy as np
+from apscheduler.schedulers.blocking import BlockingScheduler
+import QX_BatteryParam
+import pymysql
+import matplotlib.pyplot as plt
+#-------------------------------------------新建电压排序函数--------------------------------------------
+# def CellVolt_rang():
+#     global SNnums
+#     global df_Diag_Ram
+#     start=time.time()
+#     end_time=datetime.datetime.now()
+#     start_time=end_time-datetime.timedelta(seconds=720)
+#     start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+#     end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+# print('---------------计算中-------------------------')
+# for sn in SNnums:
+#     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()
+#     param=QX_BatteryParam.BatteryInfo(celltype) 
+#     #读取结果数据库数据........................................................................................................................................................
+#     host='47.97.96.242'
+#     port=3306
+#     db='didi'
+#     user='root'
+#     password='qx123456'
+#     tablename='didi_data'
+#     param='date,device_id,bat_model,position,current,soc,celltemp,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9'
+#     mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+#     cursor = mysql.cursor()
+#     sql = "select %s from %s where device_id='%s'" %(param,tablename,sn)
+#     cursor.execute(sql)
+#     res = cursor.fetchall()
+#     df_bms= pd.DataFrame(res,columns=param.split(','))
+#     cursor.close()
+#     mysql.close()
+#     # mode=1
+#     # # tablename4='cellstateestimation_intershort'
+#     # DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)  #mode==1取数据库最后一行数据
+#     # with DBRead as DBRead:
+#     #     df_data=DBRead.getdata('date,device_id,position,current,soc,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9', tablename=tablename, sn=sn, timename='date', st=start_time, sp=end_time)  
+#     # df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\origin_data\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+#     #电压排序................................................................................................................................................................
+#     df_temp = df_bms[df_bms['position']==2]#筛选充电数据
+#     df_chrgr = df_temp.reset_index(drop=True)
+#     df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+#     df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+#     df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+#     df_cellvolt_sort_dif = np.diff(df_chrgr_cellvolt_sort)#一次微分
+#     df_cellvolt_sort_dif_confir = np.nonzero(df_cellvolt_sort_dif)#取非0值
+#     Cell_num = set(df_cellvolt_sort_dif_confir[1])#寻找哪号电芯序号异常np.unique
+#     X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+#     #df_cellvolt_sort_difdif = np.diff(df_cellvolt_sort_dif)#二次微分
+#     problem_data = pd.DataFrame()
+#     temp_list = []
+
+#     for item in Cell_num:
+#         temp_list.append(np.sum(df_cellvolt_sort_dif_confir[1]==item) > X_col/20)
+    
+#     if any(temp_list):#序号变化的电芯
+#         data_temp = pd.DataFrame(df_chrgr_cellvolt_sort)
+#         problem_data = pd.concat([df_chrgr,data_temp], axis = 1)
+    
+#     problem_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+#     # volt_column = ['0','1','2','3','4','5','6','7']
+#     # fig = plt.figure(figsize=(20,10))
+#     # length = len(problem_data)
+#     # for column in volt_column:
+#     #     plt.scatter([x for x in range(0, length)], problem_data[column][0:length], label=column)
+#     # plt.legend()
+#     # title = problem_data['device_id'][0]
+#     # plt.title(title)
+#     # plt.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+title+'.png', dpi=300)
+#     # plt.show()
+#     # fig = plt.figure()
+#     # #ax = plt.subplot()
+#     # plt.scatter(problem_data['date'], problem_data['0'], c='black',marker='o',alpha=0.5, label = "2#电芯")
+#     # plt.scatter(problem_data['date'], problem_data['1'], c='green', marker='o',alpha=0.5, label = "3#电芯")
+#     # plt.scatter(problem_data['date'], problem_data['2'], c='red',marker='o', alpha=0.5, label = "4#电芯") 
+#     # plt.scatter(problem_data['date'], problem_data['3'], c='black',marker='o',alpha=0.5, label = "5#电芯")
+#     # plt.scatter(problem_data['date'], problem_data['4'], c='green', marker='o',alpha=0.5, label = "6#电芯")
+#     # plt.scatter(problem_data['date'], problem_data['5'], c='red',marker='o', alpha=0.5, label = "7#电芯")  
+#     # plt.scatter(problem_data['date'], problem_data['6'], c='black',marker='o',alpha=0.5, label = "8#电芯")
+#     # plt.scatter(problem_data['date'], problem_data['7'], c='green', marker='o',alpha=0.5, label = "9#电芯") 
+#     # plt.xlabel("时间", fontsize=15)
+#     # plt.ylabel("电压排序", fontsize=15)
+#     # title = problem_data['device_id'][0]
+#     # plt.title(title, fontsize=20)
+#     # plt.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+title+'.png', dpi=300)
+#     # plt.show()
+#     #print(problem_data)
+
+#     end=time.time()
+#     print('--------------计算时间:------------')
+#     print(end-start)
+#     # print(df_soh)
+        
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\sn.csv'
+    # 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')
+    # SNdata_didi = pd.read_csv(excelpath, encoding='gbk')
+    SNdata_didi_trw = pd.read_csv(excelpath, encoding='gbk')
+    # 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_didi = SNdata_didi['device_id'].tolist()
+    SNnums_didi_trw = SNdata_didi_trw['device_id'].tolist()
+    # SNnums=SNnums_L7255 + SNnums_C7255 + SNnums_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['BAA3219081550897']
+    SNnums = SNnums_didi_trw
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    #result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\result.csv',encoding='gbk')
+    
+    #df_Diag_Ram=result[result['end_time']=='0000-00-00 00:00:00']
+    print('----------------输入--------')
+    #定时任务.......................................................................................................................................................................
+    # scheduler = BlockingScheduler()
+    # scheduler.add_job(CellVolt_rang, 'interval', seconds=720, id='diag_job')
+
+    # try:  
+    #     scheduler.start()
+    # except Exception as e:
+    #     scheduler.shutdown()
+    #     print(repr(e))
+    #     mylog.logopt(e)
+    print('---------------计算中-------------------------')
+    start=time.time()
+    for sn in SNnums:
+        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()
+        param=QX_BatteryParam.BatteryInfo(celltype) 
+        #读取结果数据库数据........................................................................................................................................................
+        host='47.97.96.242'
+        port=3306
+        db='didi'
+        user='root'
+        password='qx123456'
+        tablename='didi_data'
+        param='date,device_id,bat_model,position,current,soc,celltemp,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9'
+        mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+        cursor = mysql.cursor()
+        sql = "select %s from %s where device_id='%s'" %(param,tablename,sn)
+        cursor.execute(sql)
+        res = cursor.fetchall()
+        df_bms= pd.DataFrame(res,columns=param.split(','))
+        cursor.close()
+        mysql.close()
+        # mode=1
+        # # tablename4='cellstateestimation_intershort'
+        # DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)  #mode==1取数据库最后一行数据
+        # with DBRead as DBRead:
+        #     df_data=DBRead.getdata('date,device_id,position,current,soc,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9', tablename=tablename, sn=sn, timename='date', st=start_time, sp=end_time)  
+        # df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\origin_data\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+        #电压排序................................................................................................................................................................
+        df_temp_crnt = df_bms[df_bms['current']>1]#筛选充电数据
+        df_temp = df_temp_crnt[df_temp_crnt['position']==2]#筛选充电数据
+        df_chrgr = df_temp.reset_index(drop=True)
+        df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+        df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+        df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+        df_cellvolt_sort_dif = np.diff(df_chrgr_cellvolt_sort,axis=0)#一次微分
+        df_cellvolt_sort_dif_confir = np.nonzero(df_cellvolt_sort_dif)#取非0值
+        Cell_num = set(df_cellvolt_sort_dif_confir[1])#寻找哪号电芯序号异常np.unique
+        X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+        #df_cellvolt_sort_difdif = np.diff(df_cellvolt_sort_dif)#二次微分
+        problem_data = pd.DataFrame()
+        temp_list = []
+
+        for item in Cell_num:
+            temp_list.append(np.sum(df_cellvolt_sort_dif_confir[1]==item) > X_col/20)
+        
+        if any(temp_list):#序号变化的电芯
+            data_temp = pd.DataFrame(df_chrgr_cellvolt_sort)
+            #problem_data = pd.concat([df_chrgr,data_temp], axis = 1)
+            problem_data = data_temp
+        sn=sn.replace('/','')
+        
+        # volt_column = [0,1,2,3,4,5,6,7]
+        # fig = plt.figure(figsize=(20,10))
+        # length = len(problem_data)
+        # num_length = np.arange(length)
+        # for column in volt_column:
+        #     plt.scatter(num_length, problem_data[column], label=column)
+        # plt.legend()
+        # # title = problem_data['device_id'][0]
+        # plt.title(sn)
+        # plt.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+sn+'.png', dpi=300)
+        # plt.show()
+        if not problem_data.empty:
+            problem_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+            print(problem_data)
+            ax=problem_data.plot(marker='*',markersize=15, figsize=(16,9))
+            plt.xlabel('时间', fontsize=20)
+            plt.ylabel('排序变化', fontsize=20)
+            plt.xticks(fontsize=15)
+            plt.yticks(fontsize=15)
+            # plt.ylim(-30,30)
+            plt.title(str(sn),fontsize=25)
+            plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
+            plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+            plt.legend(bbox_to_anchor=(1, 0), loc=3, fontsize=14)
+            plt.show()
+            fig = ax.get_figure()
+            fig.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+str(sn)+'电压排序.png')
+        # fig = plt.figure()
+        # #ax = plt.subplot()
+        # plt.scatter(problem_data['date'], problem_data['0'], c='black',marker='o',alpha=0.5, label = "2#电芯")
+        # plt.scatter(problem_data['date'], problem_data['1'], c='green', marker='o',alpha=0.5, label = "3#电芯")
+        # plt.scatter(problem_data['date'], problem_data['2'], c='red',marker='o', alpha=0.5, label = "4#电芯") 
+        # plt.scatter(problem_data['date'], problem_data['3'], c='black',marker='o',alpha=0.5, label = "5#电芯")
+        # plt.scatter(problem_data['date'], problem_data['4'], c='green', marker='o',alpha=0.5, label = "6#电芯")
+        # plt.scatter(problem_data['date'], problem_data['5'], c='red',marker='o', alpha=0.5, label = "7#电芯")  
+        # plt.scatter(problem_data['date'], problem_data['6'], c='black',marker='o',alpha=0.5, label = "8#电芯")
+        # plt.scatter(problem_data['date'], problem_data['7'], c='green', marker='o',alpha=0.5, label = "9#电芯") 
+        # plt.xlabel("时间", fontsize=15)
+        # plt.ylabel("电压排序", fontsize=15)
+        # title = problem_data['device_id'][0]
+        # plt.title(title, fontsize=20)
+        # plt.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+title+'.png', dpi=300)
+        # plt.show()
+        #print(problem_data)
+
+        end=time.time()
+        print('--------------计算时间:------------')
+        print(end-start)
+        # print(df_soh)

+ 95 - 0
USER/LZX/01算法开发/01电压排序/01算法/maincopycopycopy.py

@@ -0,0 +1,95 @@
+import CBMSBatChrgcopy
+import log
+#coding=utf-8
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+# from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from sqlalchemy import create_engine
+import time, datetime
+import os
+import numpy as np
+from apscheduler.schedulers.blocking import BlockingScheduler
+import QX_BatteryParam
+import pymysql
+import matplotlib.pyplot as plt
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\sn.csv'
+
+    SNdata_didi_trw = pd.read_csv(excelpath, encoding='gbk')
+
+    SNnums_didi_trw = SNdata_didi_trw['device_id'].tolist()
+
+    SNnums = SNnums_didi_trw
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #print('---------------计算中-------------------------')
+    start=time.time()
+    for sn in SNnums:
+        
+        #读取结果数据库数据........................................................................................................................................................
+        host='47.97.96.242'
+        port=3306
+        db='didi'
+        user='root'
+        password='qx123456'
+        tablename='didi_data'
+        param='date,device_id,bat_model,position,current,soc,celltemp,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9'
+        mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+        cursor = mysql.cursor()
+        sql = "select %s from %s where device_id='%s'" %(param,tablename,sn)
+        cursor.execute(sql)
+        res = cursor.fetchall()
+        df_bms= pd.DataFrame(res,columns=param.split(','))
+        cursor.close()
+        mysql.close()
+        #电压排序................................................................................................................................................................
+        df_temp_crnt = df_bms[df_bms['current']>1]#筛选充电数据
+        df_temp = df_temp_crnt[df_temp_crnt['position']==2]#筛选充电数据
+        df_chrgr = df_temp.reset_index(drop=True)
+        df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+        df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+        df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+        df_cellvolt_sort_dif = np.diff(df_chrgr_cellvolt_sort,axis=0)#一次微分
+        df_cellvolt_sort_dif_confir = np.nonzero(df_cellvolt_sort_dif)#取非0值
+        Cell_num = set(df_cellvolt_sort_dif_confir[1])#寻找哪号电芯序号异常np.unique
+        X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+        #df_cellvolt_sort_difdif = np.diff(df_cellvolt_sort_dif)#二次微分
+        problem_data = pd.DataFrame()
+        temp_list = []
+
+        for item in Cell_num:
+            temp_list.append(np.sum(df_cellvolt_sort_dif_confir[1]==item) > X_col/20)
+        
+        if any(temp_list):#序号变化的电芯
+            data_temp = pd.DataFrame(df_chrgr_cellvolt_sort)
+            #problem_data = pd.concat([df_chrgr,data_temp], axis = 1)
+            problem_data = data_temp
+        sn=sn.replace('/','')
+        
+        if not problem_data.empty:
+            problem_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+            #print(problem_data)
+            # ax=problem_data.plot(marker='*',markersize=15, figsize=(16,9))
+            # plt.xlabel('时间', fontsize=20)
+            # plt.ylabel('排序变化', fontsize=20)
+            # plt.xticks(fontsize=15)
+            # plt.yticks(fontsize=15)
+            # # plt.ylim(-30,30)
+            # plt.title(str(sn),fontsize=25)
+            # plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
+            # plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+            # plt.legend(bbox_to_anchor=(1, 0), loc=3, fontsize=14)
+            # plt.show()
+            # fig = ax.get_figure()
+            # fig.savefig(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+str(sn)+'电压排序.png')
+
+        end=time.time()
+        print('--------------计算时间:------------')
+        print(end-start)
+        # print(df_soh)

+ 101 - 0
USER/LZX/01算法开发/01电压排序/01算法/maincopyvoltrange.py

@@ -0,0 +1,101 @@
+import CBMSBatChrgcopy
+import log
+#coding=utf-8
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+# from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from sqlalchemy import create_engine
+import time, datetime
+import os
+import numpy as np
+from apscheduler.schedulers.blocking import BlockingScheduler
+import QX_BatteryParam
+import pymysql
+import matplotlib.pyplot as plt
+#-------------------------------------------新建电压排序函数--------------------------------------------
+def CellVolt_rang():
+#     global df_Diag_Ram
+#     end_time=datetime.datetime.now()
+#     start_time=end_time-datetime.timedelta(seconds=720)
+#     start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+#     end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+# print('---------------计算中-------------------------')
+    for sn in SNnums:
+        #读取结果数据库数据........................................................................................................................................................
+        host='47.97.96.242'
+        port=3306
+        db='didi'
+        user='root'
+        password='qx123456'
+        tablename='didi_data'
+        param='date,device_id,bat_model,position,current,soc,celltemp,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9'
+        mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+        cursor = mysql.cursor()
+        sql = "select %s from %s where device_id='%s'" %(param,tablename,sn)
+        cursor.execute(sql)
+        res = cursor.fetchall()
+        df_bms= pd.DataFrame(res,columns=param.split(','))
+        cursor.close()
+        mysql.close()
+        # mode=1
+        # # tablename4='cellstateestimation_intershort'
+        # DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)  #mode==1取数据库最后一行数据
+        # with DBRead as DBRead:
+        #     df_data=DBRead.getdata('date,device_id,position,current,soc,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9', tablename=tablename, sn=sn, timename='date', st=start_time, sp=end_time)  
+        # df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\origin_data\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+        #电压排序................................................................................................................................................................
+        df_temp_crnt = df_bms[df_bms['current']>1]#筛选充电数据
+        df_temp = df_temp_crnt[df_temp_crnt['position']==2]#筛选充电数据
+        df_chrgr = df_temp.reset_index(drop=True)
+        df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+        df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+        df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+        df_cellvolt_sort_dif = np.diff(df_chrgr_cellvolt_sort,axis=0)#一次微分
+        df_cellvolt_sort_dif_confir = np.nonzero(df_cellvolt_sort_dif)#取非0值
+        Cell_num = set(df_cellvolt_sort_dif_confir[1])#寻找哪号电芯序号异常np.unique
+        X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+        #df_cellvolt_sort_difdif = np.diff(df_cellvolt_sort_dif)#二次微分
+        problem_data = pd.DataFrame()
+        sn_choose = pd.DataFrame()
+        temp_list = []
+
+        for item in Cell_num:
+            temp_list.append(np.sum(df_cellvolt_sort_dif_confir[1]==item) > X_col/20)
+        
+        if any(temp_list):#序号变化的电芯
+            data_temp = pd.DataFrame(df_chrgr_cellvolt_sort)
+            problem_data = pd.concat([df_chrgr,data_temp], axis = 1)
+            sn_choose.append(sn)
+
+        
+        #df_chrgr_cellvolt_sort.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+        #保存数据这个位置改为保存sn号
+        end=time.time()
+        # print('--------------计算时间:------------')
+        # print(end-start)
+        # print(df_soh)
+    return sn_choose
+        
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\sn.xlsx'
+    SNdata_didi_trw = pd.read_excel(excelpath, sheet_name='sn')
+    SNnums_didi_trw = SNdata_didi_trw['device_id'].tolist()
+    SNnums = SNnums_didi_trw
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+#..............................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(CellVolt_rang, 'interval', seconds=720, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 71 - 0
USER/LZX/01算法开发/01电压排序/01算法/mainvoltrange.py

@@ -0,0 +1,71 @@
+import pandas as pd
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from sqlalchemy import create_engine
+import pymysql
+import matplotlib.pyplot as plt
+import voltrange
+import time, datetime
+#--------------------------------------主函数------------------------------------------
+if __name__ == "__main__":
+
+    #读取SN号
+    SNnums_df=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\didi_test_short.csv',encoding='GB18030')
+    SNnums=SNnums_df['sn'].tolist()
+    data_save1 = pd.DataFrame()
+    # data_save2 = pd.DataFrame()
+    # data_save3 = pd.DataFrame()
+    # data_save4 = pd.DataFrame()
+    start = time.time()
+    k = 1
+
+    for sn in SNnums:
+        try:
+            start1 = time.time()
+            host='47.97.96.242'
+            port=3306
+            db='didi'
+            user='root'
+            password='qx123456'
+            tablename='didi_data'
+            param='date,device_id,bat_model,position,current,soc,celltemp,cellvolt_2,cellvolt_3,cellvolt_4,cellvolt_5,cellvolt_6,cellvolt_7,cellvolt_8,cellvolt_9'
+            mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+            cursor = mysql.cursor()
+            sql = "select %s from %s where device_id='%s'" %(param,tablename,sn)
+            cursor.execute(sql)
+            res = cursor.fetchall()
+            df_bms= pd.DataFrame(res,columns=param.split(','))
+            cursor.close()
+            mysql.close()
+
+            #log信息配置
+            mylog=log.Mylog('log.txt','error')
+            mylog.logcfg()
+            print(sn)
+            if not df_bms.empty:
+                data_save_temp1 = voltrange.cellVolt_rang(sn,df_bms)
+                # data_save_temp1,data_save_temp2,data_save_temp3,data_save_temp4 = voltrange.cellVolt_rang(sn,df_bms)
+                #print(data_save_temp)
+                if not data_save_temp1.empty:
+                    data_save1 = pd.concat([data_save1,data_save_temp1])
+                # if not data_save_temp2.empty:
+                #     data_save2 = pd.concat([data_save2,data_save_temp2])
+                # if not data_save_temp3.empty:
+                #     data_save3 = pd.concat([data_save3,data_save_temp3])
+                # if not data_save_temp4.empty:
+                #     data_save4 = pd.concat([data_save4,data_save_temp4])
+                #print(data_save)
+            end1 = time.time()
+            print(end1-start1)
+            print(k)
+            k = k+1
+     
+        except IndexError as e:
+            print(repr(e))
+            mylog.logopt(sn,e)
+            pass
+    data_save1.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'筛选1.csv')
+    # data_save2.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'筛选2.csv')
+    # data_save3.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'筛选3.csv')
+    # data_save4.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'筛选4.csv')
+    end = time.time()
+    print(end-start)

+ 14 - 0
USER/LZX/01算法开发/01电压排序/01算法/test.py

@@ -0,0 +1,14 @@
+import pandas as pd
+df1 = pd.DataFrame()
+list1 = [1,2,3,4,5]
+df2 = pd.DataFrame(list1)
+test_df=pd.DataFrame({'name':['张三','李四','王五','张三','李四','王五','张三','六六'],
+                     'level':[10,3,8,14,2,3,18,2],
+                      'info':['吵闹','安静','中等','吵闹','安静','安静','吵闹','闲散'],
+                      'change_times':[1,2,3,1,2,4,9,12]
+                     })
+print(df1.append(df2))
+temp = df1.append(df2)
+df3 = pd.DataFrame([7,8,9,8,8])
+print(temp.append(df3))
+print(df1.append(test_df))

+ 61 - 0
USER/LZX/01算法开发/01电压排序/01算法/voltrange.py

@@ -0,0 +1,61 @@
+
+import pandas as pd
+from sqlalchemy import create_engine
+import numpy as np
+def cellVolt_rang(sn,df_bms):
+    #电压排序................................................................................................................................................................
+    print('--------计算中----------')
+    sn_choose1 = []
+    # sn_choose2 = []
+    # sn_choose3 = []
+    # sn_choose4 = []
+    temp1 = pd.DataFrame()
+    # temp2 = pd.DataFrame()
+    # temp3 = pd.DataFrame()
+    # temp4 = pd.DataFrame()
+    df_temp_crnt = df_bms[df_bms['current']>1]#筛选充电数据
+    df_temp = df_temp_crnt[df_temp_crnt['position']==2]#筛选充电数据
+    if not df_temp.empty:
+        df_chrgr = df_temp.reset_index(drop=True)
+        df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+        df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+        df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+        df_sort_change = pd.DataFrame(df_chrgr_cellvolt_sort)
+        df_sort_set = df_sort_change.apply(pd.value_counts)#计算各列出现排列序号的次数
+        df_sort_set.fillna(0, inplace=True)#Na值填充0
+        df_sort_set_change = np.array(df_sort_set)
+        df_sort_set_change_sort = np.sort(df_sort_set_change, axis = 0)#计算各电芯出现排列序号的次数
+        X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+        if X_col > 0:
+            temp_list1 = df_sort_set_change_sort[:,7] > 0.5*X_col
+            temp_list2 = df_sort_set_change_sort[:,6] > 0.4*X_col
+            # temp_list1 = np.max(df_sort_set,axis=0)
+            # temp_list = temp_list1 < X_col/2
+            # for i in range(0,8):
+            #     temp_list1 = (max(df_sort_set[i]) < 2*X_col/3)
+            #     temp_list = temp_list1.append(temp_list1)
+
+
+        if np.count_nonzero(temp_list1 & temp_list2) >= 2:#序号变化的电芯
+            # data_temp = pd.DataFrame(df_chrgr_cellvolt_sort)
+            # problem_data = pd.concat([df_chrgr,data_temp], axis = 1)
+            sn_choose1.append(sn)
+            temp1 = pd.DataFrame(sn_choose1)
+        # if any(temp_list2):
+        #     sn_choose2.append(sn)
+        #     temp2 = pd.DataFrame(sn_choose2)
+        # if any(temp_list1 & temp_list2):
+        #     sn_choose3.append(sn)
+        #     temp3 = pd.DataFrame(sn_choose3)
+        # if any(temp_list3):
+        #     sn_choose4.append(sn)
+        #     temp4 = pd.DataFrame(sn_choose4)
+
+    
+    #df_chrgr_cellvolt_sort.to_csv(r'D:\Work\Code_write\data_analyze_platform\test\lzx\01Qixiang\01电压排序\01算法\DBDownload\\'+'CBMS_diag_'+sn+'.csv',encoding='gbk')
+    #保存数据这个位置改为保存sn号
+    #end=time.time()
+    # print('--------------计算时间:------------')
+    # print(end-start)
+    # print(df_soh)
+    return temp1#,temp2,temp3,temp4

+ 29 - 0
USER/LZX/01算法开发/01电压排序/01算法/voltrangecopy.py

@@ -0,0 +1,29 @@
+
+import pandas as pd
+from sqlalchemy import create_engine
+import numpy as np
+def cellVolt_rang(sn,df_bms):
+    #电压排序................................................................................................................................................................
+    print('--------计算中----------')
+    sn_choose1 = []
+    temp1 = pd.DataFrame()
+    df_temp_crnt = df_bms[df_bms['current']>1]#筛选充电数据
+    df_temp = df_temp_crnt[df_temp_crnt['position']==2]#筛选充电数据
+    if not df_temp.empty:
+        df_chrgr = df_temp.reset_index(drop=True)
+        df_chrgr_cellvolt = df_chrgr[['cellvolt_2','cellvolt_3','cellvolt_4','cellvolt_5','cellvolt_6','cellvolt_7','cellvolt_8','cellvolt_9']]
+        df_chrgr_cellvolt_change = np.array(df_chrgr_cellvolt)#转数组
+        df_chrgr_cellvolt_sort = np.argsort(df_chrgr_cellvolt_change)#取排序号
+        df_sort_change = pd.DataFrame(df_chrgr_cellvolt_sort)
+        df_sort_set = df_sort_change.apply(pd.value_counts)#计算各列出现排列序号的次数
+        df_sort_set.fillna(0, inplace=True)#Na值填充0
+        X_col=np.size(df_chrgr_cellvolt,0)  #计算 X 的列数
+        if X_col > 0:
+            temp_list1 = np.max(df_sort_set,axis=0)
+            temp_list = temp_list1 < X_col/2
+
+        if any(temp_list):#序号变化的电芯
+            sn_choose1.append(sn)
+            temp1 = pd.DataFrame(sn_choose1)
+
+    return temp1#,temp2,temp3,temp4

+ 24 - 0
USER/LZX/01算法开发/02析锂检测/01下载数据/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=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 84 - 0
USER/LZX/01算法开发/02析锂检测/01下载数据/main.py

@@ -0,0 +1,84 @@
+import pandas as pd
+import datetime
+import pymysql
+import log
+from LIB.BACKEND import DBManager, Log
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+
+
+if __name__ == "__main__":
+    end_time=datetime.datetime.now()-datetime.timedelta(seconds=10)
+    start_time=end_time-datetime.timedelta(seconds=12000)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+    start_time = pd.to_datetime('2021-09-01 12:00:00',format='%Y-%m-%d %H:%M:%S')
+    end_time = pd.to_datetime('2021-11-01 12:00:00',format='%Y-%m-%d %H:%M:%S')
+    excelpath=r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\01算法开发\00项目sn号\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_6060#SNnums_L7255 + SNnums_C7255 + SNnums_U7255, SNnums_6040 + SNnums_4840 + SNnums_6060
+    SNnums=['PK504B00100004003']
+    # SNnums_data = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\SNnums_C7255析锂情况析锂排序.csv',encoding='GB18030')
+    # SNnums_len = len(SNnums_data)
+    # SNnums = SNnums_data['sn'][SNnums_len-11:SNnums_len]
+
+    #log信息配置
+    mylog=log.Mylog('log.txt','error')
+    mylog.logcfg()
+    # df_li_plated = pd.DataFrame(columns = ['sn','time','liplated','liplated_amount'])
+
+    k = 1
+    for sn in SNnums:
+        try:
+            # celltype=4
+            # sn=SNnums[2]
+            print('下载数据中,第' + str(k) + '个:' + sn)
+            
+            #下载数据库..........................................................................................................................................
+            # host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+            # port=3306
+            # db='qx_cas'
+            # user='qx_algo_readonly'
+            # password='qx@123456'
+            # mode = 2
+            # tablename='cellstateestimation_soh'
+            # DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)
+            # with DBRead as DBRead:
+            #     df_cell_soh=DBRead.getdata(param='sn,time_sp,soh,cellsoh', tablename=tablename, sn=sn, timename='time_sp', st=start_time, sp=end_time)
+            # # df_li_plated = df_li_plated.append(df_cell_li_plated)
+            # if not df_cell_soh.empty:
+            #     df_cell_soh.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\析锂排序后10模组的soh\\'+ sn + '.csv', encoding='GB18030')
+    
+            #下载原始数据------------------------------------------------------------------------------------------------------------------------------------
+            start_time = '2021-11-01 00:00:00'
+            end_time = '2021-12-04 00:00:00'
+            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']
+            # df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\金茂\原始数据\\'+sn+'.csv', encoding='GB18030')
+            df_bms.to_csv(r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\02问题查询\PK504B\PK504B00100004003.csv', encoding='GB18030')
+            
+            k = k + 1
+
+            # if not df_bms.empty:
+            #     BatInterShort=CBMSBatInterShort.BatInterShort(sn,celltype,df_bms)
+            #     df_res=BatInterShort.intershort()
+                #df_res.to_excel(r'D:\00WorkSpace\01Python\data_analyze_platform\USER\04didi\99Result\\'+'CBMS_InterShort'+sn[3:10]+'.xlsx')
+            # print(sn,'done!!!')
+            print(sn)
+             
+        except IndexError as e:
+            print(repr(e))
+            mylog.logopt(sn,e)
+            pass
+    # df_li_plated.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\析锂状态.csv', encoding='GB18030')

+ 78 - 0
USER/LZX/01算法开发/02析锂检测/01下载数据/plot.py

@@ -0,0 +1,78 @@
+from ctypes import Structure
+from re import M
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+from scipy.signal import savgol_filter
+from sklearn.linear_model import LinearRegression
+import os
+import log
+
+    
+def get_file():                   #创建一个空列表
+    files =os.listdir(path)
+    files.sort() #排序
+    file_list= []
+    for file in files:
+        if not  os.path.isdir(path +file):  #判断该文件是否是一个文件夹       
+            f_name = str(file)        
+#             print(f_name)
+            tr = '\\'   #多增加一个斜杠
+            filename = path + tr + f_name        
+            file_list.append(filename)  
+    return file_list 
+
+mylog=log.Mylog('log_diag.txt','error')
+mylog.logcfg()
+
+fig = plt.figure(figsize=(20,15))
+path = r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\析锂前后五电池的soh'
+file_list = get_file()
+a1 = []
+b1 = []
+for file in file_list:
+    df_time = []
+    data = pd.read_csv(file,encoding='GB18030')
+        # fig = plt.figure(figsize=(20,10))
+    df_fig = data
+    df_fig = df_fig.reset_index(drop=True)
+    length = len(df_fig)
+    df_soh_temp = df_fig['soh']
+    df_soh = savgol_filter(df_soh_temp, 11, 3)
+    df_hms_temp = pd.to_datetime(df_fig['time_sp'])#转换时间格式
+    # df_hms = df_hms_temp.dt.time#仅保留时分秒
+    df_hms_fig = df_hms_temp.apply(lambda x:x.strftime('%Y-%m-%d')) 
+    temp = file.split('\\')
+    sn_name = temp[-1].split('.')[0]
+    title = sn_name
+    time_reshape = np.array(df_hms_temp).reshape(-1,1)
+    soh_reshape = df_soh.reshape(-1,1)
+    delta_time = (np.diff(df_hms_temp)/pd.Timedelta(1, 'days'))#计算时间差
+    df_time_len = len(delta_time) 
+    for i in range(df_time_len):
+        df_time.append(sum(delta_time[0:i]))
+    soh_reshape = np.delete(soh_reshape, [-1])
+    # b1.append(lineModel.intercept_[0])#对应sn
+        #新建一个线性回归模型,并把数据放进去对模型进行训练
+    lineModel = LinearRegression()
+    lineModel.fit(np.array(df_time).reshape(-1,1), soh_reshape)
+    # a1.append(lineModel.coef_[0][0])#拟合系数
+    fit_soh = lineModel.predict(np.array(df_time).reshape(-1,1))
+    fit_soh = 100*fit_soh/fit_soh[0]
+        # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+    plt.plot(df_time, fit_soh,linewidth = 2, linestyle = '-', marker = 's',label=title)
+    mpl.rcParams['font.sans-serif']=['KaiTi']
+    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    plt.legend(fontsize=20)
+    plt.xlabel('时间(天)', fontsize=26)
+    plt.ylabel('soh随时间演化', fontsize=26)
+    plt.xticks(range(1,len(df_time),5),rotation=45, fontsize=26)
+    plt.yticks(fontsize=26)
+    # plt.xlim((df_hms_temp[0]-datetime.timedelta(minutes=5)).dt.time,(df_hms_temp[0] + datetime.timedelta(hours=1.5)).dt.time)
+    # plt.ylim(-2.5,0.5)
+    plt.title('析锂量前5与后5的电池包soh演化', fontsize=28)
+    # plt.show()
+plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\soh图片\\'+'析锂量前5与后5电池包的soh.png', dpi=300)

+ 132 - 0
USER/LZX/01算法开发/02析锂检测/03车辆分析/chrgr_soc_confrm.py

@@ -0,0 +1,132 @@
+from ctypes import Structure
+from re import M
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+from scipy.signal import savgol_filter
+from scipy import interpolate
+import os
+import log
+from LIB.MIDDLE.SaftyCenter.Common import QX_BatteryParam as BatParam
+
+class chrgrsoc_test:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatteryInfo(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.LookTab_SOC = self.param.LookTab_SOC
+        self.LookTab_OCV = self.param.LookTab_OCV
+
+        self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+#.............................................充电截止SOC............................................................................
+    def chrgrsoc_detect(self):
+        data = self.df_bms
+        chrgr_soc = pd.DataFrame()
+        if len(data) > 1:
+            df_soc = data['SOC[%]']
+            df_soc_len = len(df_soc)
+            df_soc_add = df_soc.iloc[df_soc_len-3:df_soc_len-1]#由于对SOC二次微分,增加两行数据
+            df_soc_new = df_soc.append(df_soc_add)
+            df_soc_new_dif = np.diff(df_soc_new,axis=0)#电压一次微分,判断升降
+            df_soc_new_dif = pd.DataFrame(df_soc_new_dif)
+            df_soc_new_dif[df_soc_new_dif > 0] = 1#SOC升高
+            df_soc_new_dif[df_soc_new_dif == 0] = 0#SOC升高或静置
+            df_soc_new_dif[df_soc_new_dif < 0] = -1#SOC下降
+            df_soc_dif_arr = np.array(df_soc_new_dif)
+            pos_change = nonzero(df_soc_dif_arr)#寻找非零元素位置
+            value_change = df_soc_dif_arr[pos_change[0]]#非零元素数值
+            value_change_dif = np.diff(value_change)#对非零元素值二次微分
+            peak_pos = np.where(value_change_dif == -2)#充电结束点
+            bot_pos = np.where(value_change_dif == 2)#放电结束点
+            #-------------------------------------------------------利用soc的升降判断充放电---------------------------------------------------------
+            pos_change_dif = np.diff(pos_change[0])#计算SOC变化时的位置信息
+            pos_change_del_temp = np.where(pos_change_dif < 10)
+            pos_change_del = pos_change_del_temp[0] + 1
+            value_change_new = np.delete(value_change[:,0], pos_change_del)#SOC发生变化数值
+            pos_change_new = np.delete(pos_change[0], pos_change_del)#SOC发生变化位置
+            value_change_new_dif = np.diff(value_change_new)#寻找充电或放电结束位置
+            value_change_new_dif = np.insert(value_change_new_dif, 0, value_change_new_dif[0])
+            chrgr_dischrgr_pos_temp = np.where(abs(value_change_new_dif) == 2)#寻找充电或放电结束位置
+            splice_num = []
+            if len(chrgr_dischrgr_pos_temp[0]) >= 1:
+                chrgr_dischrgr_pos = pos_change_new[chrgr_dischrgr_pos_temp[0]]#原数据中充电或放电结束位置
+                chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, 0, 0)
+                data_len = len(df_soc)#数据长度
+                pos_len = len(chrgr_dischrgr_pos)#切片长度
+                chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, pos_len, data_len-1)#
+                for item in range(0,len(chrgr_dischrgr_pos)-1):
+                    splice_num.extend(item*np.ones(chrgr_dischrgr_pos[item +1]-chrgr_dischrgr_pos[item]))
+                splice_num = np.insert(splice_num, data_len-2, item)
+            else:
+                splice_num = np.zeros(len(df_soc))
+                # pos_ful = np.array([0])
+            data['stat'] = splice_num
+            #--------------------------------------------------------筛选充电数据与放电数据-------------------------------------
+            chrgr_data = pd.DataFrame()
+            dischrgr_data = pd.DataFrame()
+            for num_chrgr in range(0,len(chrgr_dischrgr_pos)-1):
+                df_data_temp = data.loc[(data['stat'] == num_chrgr)]
+                data_splice_len = len(df_data_temp)
+                if np.count_nonzero(df_data_temp['总电流[A]'] > 0) > 0.3*data_splice_len:
+                    chrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] >= 0]#筛选具有充电电流的充电数据
+                    chrgr_data = chrgr_data.append(chrgr_data_temp)
+                    chrgr_data = chrgr_data.reset_index(drop = True)
+                else:
+                    dischrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] <= 0]#筛选具有放电电流的放电数据
+                    dischrgr_data = dischrgr_data.append(dischrgr_data_temp)
+                    dischrgr_data = dischrgr_data.reset_index(drop = True)
+            if len(chrgr_data) > 1:
+                chrgr_num_difference = np.unique(chrgr_data['stat'])
+                #--------------------------------------------------------统计充电截止电压、充电SOC区间---------------------------------------------------------
+
+                cell_name = ['单体电压'+str(x) for x in range(1,21)]#电芯电压名称
+                chrgr_volt = pd.DataFrame()
+                chrgr_fin_volt = pd.DataFrame()
+                
+                f = interpolate.interp1d(self.LookTab_OCV, self.LookTab_SOC, kind = 'quadratic')#差值函数
+                for chrgr_num in chrgr_num_difference:
+                    data_temp = chrgr_data.loc[chrgr_data['stat'] == chrgr_num]#该片段数据
+                    chrgr_crnt_data = data_temp.loc[data_temp['总电流[A]'] > 0]#充电数据中有电流部分,充电时电流为正
+                    chrgr_crnt_data = chrgr_crnt_data.reset_index(drop = True)
+                    chrgr_crnt_zero_before = data_temp.loc[data_temp['时间戳'] < chrgr_crnt_data['时间戳'][0]]#充电数据中出现电流前数据
+                    chrgr_crnt_zero_after = data_temp.loc[data_temp['时间戳'] > chrgr_crnt_data.iloc[-1]['时间戳']]#充电数据中出现电流前数据
+                    chrgr_crnt_zero_before = chrgr_crnt_zero_before.reset_index(drop = True)
+                    chrgr_crnt_zero_after = chrgr_crnt_zero_after.reset_index(drop = True)
+                    time_before = pd.to_datetime(chrgr_crnt_zero_before['时间戳'])
+                    time_after = pd.to_datetime(chrgr_crnt_zero_after['时间戳'])
+                    chrgr_rest_len = len(time_after)
+                    if chrgr_rest_len > 1:
+                        if (time_after[chrgr_rest_len - 1] - time_after[0])/pd.Timedelta(1, 'min') > 10:
+                            # chrgr_volt = chrgr_volt.append(chrgr_crnt_zero_before.iloc[-1])#充电开始前静置电压
+                            chrgr_volt = chrgr_volt.append(chrgr_crnt_zero_after.iloc[-1])#充电结束静置电压
+                for cell_num in cell_name:#获取各个电芯充电结束后的SOC
+                    chrgr_cellsoc = f(chrgr_volt[cell_num]/1000)
+                    chrgr_cellsoc_temp = pd.DataFrame(chrgr_cellsoc)
+                    chrgr_soc = pd.concat([chrgr_soc, chrgr_cellsoc_temp], axis = 1)#按列合并各个电芯
+                chrgr_soc = chrgr_soc.reset_index(drop = True)
+                chrgr_soc.columns = cell_name
+                chrgr_soc['time'] = list(chrgr_volt['时间戳'])
+                chrgr_soc['stat'] = list(chrgr_volt['stat'])
+                chrgr_soc['soc_delta'] =  np.max(chrgr_soc[cell_name], axis = 1) - np.min(chrgr_soc[cell_name], axis = 1)
+                chrgr_soc['sn'] = self.sn
+    #返回诊断结果...........................................................................................................
+        if not chrgr_soc.empty:
+            return chrgr_soc
+        else:
+            return pd.DataFrame()

+ 329 - 0
USER/LZX/01算法开发/02析锂检测/03车辆分析/data_analy.py

@@ -0,0 +1,329 @@
+from ctypes import Structure
+from re import M
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+from scipy.signal import savgol_filter
+import os
+import log
+
+path = r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\原始数据'
+    
+def get_file():                   #创建一个空列表
+    files =os.listdir(path)
+    files.sort() #排序
+    file_list= []
+    for file in files:
+        if not  os.path.isdir(path +file):  #判断该文件是否是一个文件夹       
+            f_name = str(file)        
+#             print(f_name)
+            tr = '\\'   #多增加一个斜杠
+            filename = path + tr + f_name        
+            file_list.append(filename)  
+    return file_list 
+
+mylog=log.Mylog('log_diag.txt','error')
+mylog.logcfg()
+
+file_list = get_file()
+for file in file_list:
+    data = pd.read_csv(file,encoding='GB18030')
+    #----------------------------------------定义滤波函数-----------------------------------------------------------------------
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+    #----------------------------------------区分充放电数据----------------------------------------------------------------------
+    df_soc = data['SOC[%]']
+    df_soc_len = len(df_soc)
+    df_soc_add = df_soc.iloc[df_soc_len-3:df_soc_len-1]#由于对SOC二次微分,需要增加两行数据
+    df_soc_new = df_soc.append(df_soc_add)
+    df_soc_new_dif = np.diff(df_soc_new,axis=0)#电压一次微分,判断升降
+    df_soc_new_dif = pd.DataFrame(df_soc_new_dif)
+    df_soc_new_dif[df_soc_new_dif >= 0] = 1#SOC升高或静置
+    df_soc_new_dif[df_soc_new_dif < 0] = -1#SOC下降
+    df_soc_new_difdif = np.diff(df_soc_new_dif,axis=0)#三次微分,利用-2,2判断充电-静置与放电-静置的区别
+    df_soc_new_difdif = pd.DataFrame(df_soc_new_difdif)
+    peak_pos = np.where(df_soc_new_difdif == -2)
+    bot_pos = np.where(df_soc_new_difdif == 2)
+    
+    
+    chrgr_rest_data_temp = data.loc[((data['充电状态'] == 0) & (data['SOC[%]'] > 98) & (data['总电流[A]'] == 0))| 
+                                               ((data['充电状态'] == 2) & (data['SOC[%]'] > 98) & (data['总电流[A]'] == 0))]#接近慢充后静置数据
+    chrgr_rest_data = chrgr_rest_data_temp.reset_index(drop=True)
+    temp_rest_time = chrgr_rest_data['时间戳'].reset_index(drop=True)
+    rest_time = pd.to_datetime(temp_rest_time)
+    # rest_chrg_time = datetime(rest_time)
+    # delta_time = np.diff(rest_chrg_time)
+    delta_time = (np.diff(rest_time)/pd.Timedelta(1, 'min'))#计算时间差的分钟数
+    pos = np.where(delta_time > 30)
+    pos_ful_tem = np.insert(pos, 0, 0)
+    pos_len = len(pos_ful_tem)
+    data_len = len(rest_time)
+    pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
+    splice_num = []
+    if len(pos[0]) >= 1:
+        pos_ful_tem = np.insert(pos, 0, 0)
+        pos_len = len(pos_ful_tem)
+        data_len = len(rest_time)
+        pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
+        for item in range(0,len(pos_ful)-1):
+            splice_num.extend(item*np.ones(pos_ful[item +1]-pos_ful[item]))
+        splice_num = np.insert(splice_num, 0, 0)
+    else:
+        splice_num = np.zeros(len(temp_rest_time))
+        pos_ful = np.array([0])
+    chrgr_rest_data['chrgr_rest'] = splice_num
+    #---------------------------判断数据点数大于30的数据段,对电压微分并画图--------------------------------------------
+    cellvolt_name=['单体电压'+str(x) for x in range(1,21)]
+    cellvolt_list = cellvolt_name
+    chrgr_rest_check_data = chrgr_rest_data.drop(['GSM信号','故障等级','故障代码','单体压差','绝缘电阻','总电流[A]','总电压[V]','充电状态','单体压差','SOC[%]'],axis=1,inplace=False)
+    chrgr_rest_check_data.fillna(value=0)
+    df_rest_volt_diffdt = pd.DataFrame()
+    df_rest_volt_smooth = pd.DataFrame()
+    df_ini_volt_total = pd.DataFrame()
+    k = 0
+    for j in range(0,len(pos_ful)-1):#len(pos_ful)-1#有几段充电后静置数据
+        df_test_rest_data = chrgr_rest_check_data.loc[chrgr_rest_check_data['chrgr_rest'] == j]
+        df_rest_volt_smooth = pd.DataFrame()
+        df_ini_volt = pd.DataFrame()
+        df_test_rest_time = pd.to_datetime(df_test_rest_data['时间戳'],format='%Y-%m-%d %H:%M:%S')
+        df_test_rest_time = df_test_rest_time.reset_index(drop=True)
+        df_data_length = len(df_test_rest_time)
+        if (df_data_length > 30) & ((df_test_rest_time[df_data_length - 1] - df_test_rest_time[0])/pd.Timedelta(1, 'min') > 40):#静置时间大于40min
+            df_test_rest_time_dif_temp = np.diff(df_test_rest_time)/pd.Timedelta(1, 'min')
+            num_list = []
+            data_jump_pos = np.where(df_test_rest_time_dif_temp > 3)
+            if len(data_jump_pos[0]) > 0:
+                if data_jump_pos[0][0] > 100:
+                    for i in range(0,data_jump_pos[0][0],15):##采样密集时每隔10行取数据
+                        num_list.append(i)
+                    df_rest_data_temp = df_test_rest_data.iloc[num_list]
+                    df_test_rest_data_choose = pd.DataFrame(df_rest_data_temp)
+                    df_test_rest_data_choose_else = df_test_rest_data.iloc[data_jump_pos[0][0]+1:len(df_test_rest_data)-1]
+                    df_rest_data_recon_temp = df_test_rest_data_choose.append(df_test_rest_data_choose_else)
+                    df_rest_data_recon =df_rest_data_recon_temp.reset_index(drop=True)
+                else:
+                    df_rest_data_recon = df_test_rest_data
+            else:
+                df_rest_data_recon = df_test_rest_data
+            df_rest_time = pd.to_datetime(df_rest_data_recon['时间戳'],format='%Y-%m-%d %H:%M:%S')
+            df_rest_time = df_rest_time.reset_index(drop=True)
+            df_rest_time_dif_temp = np.diff(df_rest_time)/pd.Timedelta(1, 'min')
+            df_rest_volt = df_rest_data_recon[cellvolt_list]
+            for item in cellvolt_list:
+                window_temp = int(len(df_rest_volt[item])/3)
+                if window_temp%2:#滤波函数的窗口长度需为奇数
+                    window = window_temp
+                else:
+                    window = window_temp - 1
+                step = min(int(window/3),5)
+                df_volt_smooth = savgol_filter(df_rest_volt[item],window,step)
+                df_rest_volt_smooth[item] = df_volt_smooth
+            df_ini_volt = df_ini_volt.append(df_rest_volt_smooth)
+            df_ini_volt.columns = cellvolt_list
+            df_test_rest_volt_diff_temp = np.diff(df_rest_volt_smooth,axis=0)
+            df_test_rest_time_dif = pd.DataFrame(df_rest_time_dif_temp)
+            df_test_rest_volt_diff = pd.DataFrame(df_test_rest_volt_diff_temp)
+            df_test_rest_volt_diffdt_temp = np.divide(df_test_rest_volt_diff,df_test_rest_time_dif)#电压对时间的微分
+            df_test_rest_volt_diffdt = pd.DataFrame(df_test_rest_volt_diffdt_temp)
+            df_test_rest_volt_diffdt = df_test_rest_volt_diffdt.append(df_test_rest_volt_diffdt.iloc[len(df_test_rest_volt_diffdt)-1])
+            df_test_rest_volt_diffdt.columns = cellvolt_list
+            if len(df_test_rest_volt_diffdt) > 25:
+                for item in cellvolt_list:
+                    df_volt_diffdt_smooth = savgol_filter(df_test_rest_volt_diffdt[item],13,3)
+                    df_test_rest_volt_diffdt[item] = df_volt_diffdt_smooth
+                df_test_rest_volt_diffdt['chrgr_rest'] = k
+                df_test_rest_volt_diffdt['时间戳'] = list(df_rest_time)
+                df_ini_volt['chrgr_rest'] = k
+                df_ini_volt['时间戳'] = list(df_rest_time)
+                k = k+1
+                df_rest_volt_diffdt = df_rest_volt_diffdt.append(df_test_rest_volt_diffdt)#电压对时间的一次微分
+                df_rest_volt_diffdt.reset_index()
+                df_ini_volt_total = df_ini_volt_total.append(df_ini_volt)
+                df_ini_volt_total.reset_index()
+    #--------------------------------------------------------确认是否析锂----------------------------------------------------------------------------
+    # df_lipltd_data = pd.DataFrame(columns=['sn','date','liplated'])
+    m_num = 0
+    df_fig_dvdtdata = pd.DataFrame()
+    df_fig_voltdata = pd.DataFrame()
+    for item in range(0,k):
+        lipltd_confirm = []
+        lipltd_amount = []
+        df_check_liplated_temp = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == item].reset_index(drop = True)
+        df_check_volt_temp = df_ini_volt_total.loc[df_ini_volt_total['chrgr_rest'] == item].reset_index(drop = True)
+        df_lipltd_volt_temp = df_check_liplated_temp[cellvolt_list]
+        df_lipltd_volt_len = len(df_lipltd_volt_temp)
+        df_data_temp_add = df_lipltd_volt_temp.iloc[df_lipltd_volt_len-3:df_lipltd_volt_len-1]#电压对时间的一次微分
+        df_lipltd_volt_temp_add = df_lipltd_volt_temp.append(df_data_temp_add)
+        # df_lipltd_volt_temp_dif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压一次微分,计算dv/dt
+        # df_lipltd_volt_temp_dif = pd.DataFrame(df_lipltd_volt_temp_dif)
+        # df_lipltd_volt_temp_dif.columns = cellvolt_list
+        df_lipltd_volt_temp_difdif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压二次微分,判断升降
+        df_lipltd_volt_temp_difdif = pd.DataFrame(df_lipltd_volt_temp_difdif)
+        df_lipltd_volt_temp_difdif.columns = cellvolt_list
+        df_lipltd_volt_temp_difdif_temp = df_lipltd_volt_temp_difdif
+        df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp >= 0] = 1
+        df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp < 0] = -1
+        df_lipltd_volt_temp_difdifdif = np.diff(df_lipltd_volt_temp_difdif_temp,axis=0)#三次微分,利用-2,2判断波分和波谷
+        df_lipltd_volt_difdifdif = pd.DataFrame(df_lipltd_volt_temp_difdifdif)
+        df_lipltd_volt_difdifdif.columns = cellvolt_list
+        df_lipltd_volt_difdifdif['chrgr_rest'] = k
+        df_lipltd_volt_difdifdif['时间戳'] = list(df_check_liplated_temp['时间戳'])
+        df_lipltd_volt_difdifdif = df_lipltd_volt_difdifdif.reset_index(drop = True)
+        df_lipltd_data_temp = df_lipltd_volt_difdifdif.loc[df_lipltd_volt_difdifdif['时间戳'] < (df_check_liplated_temp['时间戳'][0] + datetime.timedelta(minutes=90))]
+        for cell_name in cellvolt_list:#对每个电芯判断
+            df_check_plated_data = df_lipltd_data_temp[cell_name]
+            peak_pos = np.where(df_check_plated_data == -2)
+            bot_pos = np.where(df_check_plated_data == 2)
+            if len(bot_pos[0]) & len(peak_pos[0]):
+                ini_dvdt = df_check_liplated_temp[cell_name][0]
+                peak_dvdt = df_check_liplated_temp[cell_name][peak_pos[0][0] + 1]
+                bot_dvdt = df_check_liplated_temp[cell_name][bot_pos[0][0] + 1]
+                peak_hight = peak_dvdt - ini_dvdt
+                peak_bot_hight = peak_dvdt - bot_dvdt
+                liplted_amount_temp = (df_check_liplated_temp['时间戳'][bot_pos[0][0] + 1] - df_check_liplated_temp['时间戳'][0])/pd.Timedelta(1, 'min')
+                if ((bot_pos[0][0] - peak_pos[0][0]) > 3) & (df_check_liplated_temp[cell_name][peak_pos[0][0] + 1] < 0) & (peak_bot_hight > 0.05*peak_hight) & (liplted_amount_temp > 15):
+                    lipltd_confirm.append(1)#1为析锂,0为非析锂
+                    lipltd_amount.append(liplted_amount_temp)
+                else:
+                    lipltd_confirm.append(0)
+                    lipltd_amount.append(0)
+            else:
+                lipltd_confirm.append(0)
+                lipltd_amount.append(0)
+        if any(lipltd_confirm):
+            temp = file.split('\\')
+            sn_name = temp[11].split('.')[0]
+            df_lipltd_confir_temp = pd.DataFrame({"sn":[sn_name], "time":[df_check_liplated_temp['时间戳'][0]], "liplated":[str(lipltd_confirm)], "liplated_amount":[str(lipltd_amount)]})
+            df_lipltd_data = df_lipltd_data.append(df_lipltd_confir_temp)
+            df_lipltd_data = df_lipltd_data.reset_index(drop = True)
+            df_lipltd_data.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+            df_fig_dvdtdata_temp = df_check_liplated_temp
+            df_fig_dvdtdata_temp['chrgr_rest'] = m_num
+            df_fig_dvdtdata = df_fig_dvdtdata.append(df_fig_dvdtdata_temp)#电压对时间微分数据
+            df_fig_dvdtdata = df_fig_dvdtdata.reset_index(drop = True)
+            df_fig_voltdata_temp = df_check_volt_temp
+            df_fig_voltdata_temp['chrgr_rest'] = m_num
+            df_fig_voltdata = df_fig_voltdata.append(df_fig_voltdata_temp)#原始电压数据
+            df_fig_voltdata = df_fig_voltdata.reset_index(drop = True)
+            m_num = m_num + 1
+            df_lipltd_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\析锂检测结果\MGMCLN750N215N155.csv',index=False,encoding='GB18030')
+            df_fig_dvdtdata.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\析锂检测结果\微分电压曲线.csv',index=False,encoding='GB18030')
+            df_fig_voltdata.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\析锂检测结果\电压曲线.csv',index=False,encoding='GB18030')
+    
+    for i in range(0,m_num):
+        fig = plt.figure(figsize=(20,10))
+        df_fig_temp = df_fig_dvdtdata.loc[df_fig_dvdtdata['chrgr_rest'] == i]
+        df_fig_temp = df_fig_temp.reset_index(drop=True)
+        df_fig = df_fig_temp.loc[df_fig_temp['时间戳'] < (df_fig_temp['时间戳'][0] + datetime.timedelta(hours=1))]
+        length = len(df_fig)
+        df_hms_temp = pd.to_datetime(df_fig['时间戳'])#转换时间格式
+        df_hms = df_hms_temp.dt.time#仅保留时分秒
+        df_hms_fig = df_hms.apply(lambda x:x.strftime('%H:%M:%S'))
+        for volt_num in cellvolt_name[0:10]:
+            # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+            plt.plot(df_hms_fig, df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+        mpl.rcParams['font.sans-serif']=['KaiTi']
+        mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        temp = file.split('\\')
+        sn_name = temp[-1].split('.')[0]
+        title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+        plt.xlabel('时间', fontsize=16)
+        plt.ylabel('电压的时间微分(mv/min)', fontsize=16)
+        plt.xticks(range(1,len(df_hms_fig),5),rotation=45, fontsize=16)
+        plt.yticks(fontsize=16)
+        # plt.xlim((df_hms_temp[0]-datetime.timedelta(minutes=5)).dt.time,(df_hms_temp[0] + datetime.timedelta(hours=1.5)).dt.time)
+        # plt.ylim(-2.5,0.5)
+        plt.title(title, fontsize=20)
+        # plt.show()
+        plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\析锂分析画图\析锂微分电压曲线\\'+title+'前.png', dpi=300)
+    for i in range(0,m_num):
+        fig = plt.figure(figsize=(20,10))
+        df_fig_temp = df_fig_dvdtdata.loc[df_fig_dvdtdata['chrgr_rest'] == i]
+        df_fig_temp = df_fig_temp.reset_index(drop=True)
+        df_fig = df_fig_temp.loc[df_fig_temp['时间戳'] < (df_fig_temp['时间戳'][0] + datetime.timedelta(hours=1))]
+        length = len(df_fig)
+        df_hms_temp = pd.to_datetime(df_fig['时间戳'])#转换时间格式
+        df_hms = df_hms_temp.dt.time#仅保留时分秒
+        df_hms_fig = df_hms.apply(lambda x:x.strftime('%H:%M:%S'))
+        for volt_num in cellvolt_name[10:21]:
+            # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+            plt.plot(df_hms_fig, df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+        mpl.rcParams['font.sans-serif']=['KaiTi']
+        mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        temp = file.split('\\')
+        sn_name = temp[-1].split('.')[0]
+        title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+        plt.xlabel('时间', fontsize=16)
+        plt.ylabel('电压的时间微分(mv/min)', fontsize=16)
+        plt.xticks(range(1,len(df_hms_fig),5),rotation=45, fontsize=16)
+        plt.yticks(fontsize=16)
+        # plt.xlim((df_hms_temp[0]-datetime.timedelta(minutes=5)).dt.time,(df_hms_temp[0] + datetime.timedelta(hours=1.5)).dt.time)
+        # plt.ylim(-2.5,0.5)
+        plt.title(title, fontsize=20)
+        # plt.show()
+        plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\析锂分析画图\析锂微分电压曲线\\'+title+'后.png', dpi=300)
+    #-------------------------------------原始电压变化曲线-------------------------------------------------
+    fig = plt.figure(figsize=(20,15))
+    for i in range(0,m_num):#0,k
+        # fig = plt.figure(figsize=(20,10))
+        df_fig = df_fig_voltdata.loc[df_fig_voltdata['chrgr_rest'] == i]
+        df_fig = df_fig.reset_index(drop=True)
+        length = len(df_fig)
+        temp = file.split('\\')
+        sn_name = temp[-1].split('.')[0]
+        title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+        plt_data_len = len(df_fig)
+        # for volt_num in cellvolt_name[5:6]:
+            # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+        # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+        plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[2]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+        # plt.plot(df_fig['时间戳'], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)#cellvolt_name[5]
+    mpl.rcParams['font.sans-serif']=['KaiTi']
+    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    plt.legend(fontsize=24)
+    plt.xlabel('采样点', fontsize=24)
+    plt.ylabel('电压(mV)', fontsize=24)
+    plt.xticks(fontsize=20)
+    plt.yticks(fontsize=20)
+    
+    # plt.xlim(df_fig['时间戳'][0]-datetime.timedelta(minutes=5),df_fig['时间戳'][0] + datetime.timedelta(hours=1.5))
+    # plt.xlim(0, 30)
+    # plt.ylim(4120, 4200)
+        # plt.ylim(-2.5,0.5)
+    plt.title('3#电芯不同时刻电压曲线', fontsize=30)
+    plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\格林美-Catl7255\析锂分析画图\充电后静置电压曲线\\'+'3#电芯不同时刻电压曲线'+'.png', dpi=300)
+#     # plt.show()
+    # fig = plt.figure(figsize=(20,10))
+    # for i in range(3,4):#0,k
+    #     # fig = plt.figure(figsize=(20,10))
+    #     df_fig = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == i]
+    #     df_fig = df_fig.reset_index(drop=True)
+    #     length = len(df_fig)
+    #     temp = file.split('\\')
+    #     sn_name = temp[9].split('.')[0]
+    #     title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+    #     plt_data_len = len(df_fig)
+    #     # for volt_num in cellvolt_name[5:6]:
+    #         # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+    #     # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+    #     # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[2]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+    #     plt.plot(df_fig['时间戳'], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = cellvolt_name[5])
+    #     mpl.rcParams['font.sans-serif']=['SimHei']
+    #     mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    #     plt.legend()
+    #     plt.xlabel('采样点', fontsize=14)
+    #     plt.ylabel('电压的时间微分(mv/min)', fontsize=14)
+    #     plt.xlim(df_fig['时间戳'][0]-datetime.timedelta(minutes=5),df_fig['时间戳'][0] + datetime.timedelta(hours=5))
+    #     # plt.xlim(0, 60)
+    #         # plt.ylim(-2.5,0.5)
+    #     plt.title('6#电芯不同时间电压微分曲线')
+    #     plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\MGMCLN750N215N049\\'+'6#电芯析锂'+'.png', dpi=300)
+    # plt.show()
+    

+ 24 - 0
USER/LZX/01算法开发/02析锂检测/03车辆分析/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=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\03车辆分析\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 101 - 0
USER/LZX/01算法开发/02析锂检测/03车辆分析/main.py

@@ -0,0 +1,101 @@
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+import log
+from pandas.core.frame import DataFrame
+import chrgr_soc_confrm
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def cell_chrgrsoc_test():
+    global SNnums
+    global df_chrgrsoc
+    start=time.time()
+    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=3)
+    end_time=str(now_time)
+    start_time=str(start_time)
+    k = 1
+    for sn in SNnums:
+        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三元电芯
+        elif 'TJMCL' in sn: 
+            celltype=100 #金茂电芯
+        else:
+            print('SN:{},未找到对应电池类型!!!'.format(sn))
+            continue
+            # sys.exit()
+        print('计算的第' + str(k) + '个:' + sn)
+        k = k + 1
+        #读取原始数据库数据........................................................................................................................................................
+        start_time = '2021-9-01 00:00:00'
+        end_time = '2021-10-01 00:00:00'
+        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']
+        df_Diag_chrgrsoc_add = pd.DataFrame()
+
+        #析锂诊断................................................................................................................................................................
+        if not df_bms.empty:
+            Diag_chrgrsoc_temp = chrgr_soc_confrm.chrgrsoc_test(sn,celltype,df_bms)#充电SOC
+            df_Diag_chrgrsoc_add = Diag_chrgrsoc_temp.chrgrsoc_detect()        
+        if len(df_Diag_chrgrsoc_add) > 0:
+            df_chrgrsoc = df_chrgrsoc.append(df_Diag_chrgrsoc_add)
+            df_chrgrsoc = df_chrgrsoc.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)
+            df_chrgrsoc.sort_values(by = ['sn'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+            df_chrgrsoc.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\03车辆分析\低析锂量电池的充电截止SOC.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    global SNnums
+    global df_chrgrsoc
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\00项目sn号\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['TJMCL120502305010','TJMCL120502305012','TJMCL120502305048','TJMCL120502305044','TJMCL120502305026','TJMCL120502305022','TJMCL120502305032','TJMCL120502305038']
+    # SNnums = ['MGMCLN750N215N155']#['MGMCLN750N215N049'] #SNnums_6040 #SNnums_C7255 #SNnums_6040['MGMCLN750N215N049'] 
+    SNnums_data = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\SNnums_C7255析锂情况析锂排序.csv',encoding='GB18030')
+    snnums_len = len(SNnums_data)
+    SNnums = SNnums_data['sn'][snnums_len-11:snnums_len]
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    df_chrgrsoc = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\03车辆分析\充电截止SOC.csv',encoding='GB18030')
+
+    print('----------------输入--------')
+    print('-------计算中-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(cell_chrgrsoc_test, 'interval', seconds=10, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 728 - 0
USER/LZX/01算法开发/02析锂检测/04充电行为/chrgr_state.ipynb

@@ -0,0 +1,728 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from ctypes import Structure\n",
+    "from re import M\n",
+    "import pandas as pd\n",
+    "import numpy as np\n",
+    "import datetime\n",
+    "import time, datetime\n",
+    "import matplotlib.pyplot as plt\n",
+    "from pylab import*\n",
+    "from scipy.signal import savgol_filter\n",
+    "import os\n",
+    "\n",
+    "path = r'D:\\Work\\Code_write\\data_analyze_platform\\USER\\lzx\\05问题查询\\PK504B00100004003内阻可疑-211206\\原始数据'\n",
+    "    \n",
+    "def get_file():                   #创建一个空列表\n",
+    "    files =os.listdir(path)\n",
+    "    files.sort() #排序\n",
+    "    file_list= []\n",
+    "    for file in files:\n",
+    "        if not  os.path.isdir(path +file):  #判断该文件是否是一个文件夹       \n",
+    "            f_name = str(file)        \n",
+    "#             print(f_name)\n",
+    "            tr = '\\\\'   #多增加一个斜杠\n",
+    "            filename = path + tr + f_name        \n",
+    "            file_list.append(filename)  \n",
+    "    return file_list \n",
+    "\n",
+    "file_list = get_file()\n",
+    "for file in file_list:\n",
+    "    data = pd.read_csv(file,encoding='GB18030')\n",
+    "    #----------------------------------------定义滤波函数-----------------------------------------------------------------------\n",
+    "    def moving_average(interval, windowsize):\n",
+    "        window = np.ones(int(windowsize)) / float(windowsize)\n",
+    "        re = np.convolve(interval, window, 'same')\n",
+    "        return re\n",
+    "    #----------------------------------------区分充放电数据----------------------------------------------------------------------\n",
+    "    df_soc = data['SOC[%]']\n",
+    "    # df_soc[df_soc >= 99] = 100\n",
+    "    # df_soc_flt = moving_average(df_soc, 3)#SOC滤波\n",
+    "    df_soc_len = len(df_soc)\n",
+    "    df_soc_add = df_soc.iloc[df_soc_len-3:df_soc_len-1]#由于对SOC二次微分,增加两行数据\n",
+    "    df_soc_new = df_soc.append(df_soc_add)\n",
+    "    # df_soc_cal = savgol_filter(df_soc_new, 13, 3)\n",
+    "    df_soc_new_dif = np.diff(df_soc_new,axis=0)#电压一次微分,判断升降\n",
+    "    df_soc_new_dif = pd.DataFrame(df_soc_new_dif)\n",
+    "    df_soc_new_dif[df_soc_new_dif > 0] = 1#SOC升高\n",
+    "    df_soc_new_dif[df_soc_new_dif == 0] = 0#SOC升高或静置\n",
+    "    df_soc_new_dif[df_soc_new_dif < 0] = -1#SOC下降\n",
+    "    df_soc_dif_arr = np.array(df_soc_new_dif)\n",
+    "    pos_change = nonzero(df_soc_dif_arr)#寻找非零元素位置\n",
+    "    value_change = df_soc_dif_arr[pos_change[0]]#非零元素数值\n",
+    "    value_change_dif = np.diff(value_change)#对非零元素值二次微分\n",
+    "    peak_pos = np.where(value_change_dif == -2)#充电结束点\n",
+    "    bot_pos = np.where(value_change_dif == 2)#放电结束点\n",
+    "    # df_soc_new_difdif = np.diff(df_soc_new_dif,axis=0)#三次微分,利用-2,2判断充电-静置与放电-静置的区别\n",
+    "    # df_soc_new_difdif = pd.DataFrame(df_soc_new_difdif)\n",
+    "    # peak_pos = np.where(df_soc_new_difdif == -2)\n",
+    "    # bot_pos = np.where(df_soc_new_difdif == 2)\n",
+    "    print(pos_change)\n",
+    "    # print(df_soc)\n",
+    "    # print(df_soc_new_dif)\n",
+    "    print(value_change)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(array([ 6855,  6860,  9481,  9510,  9519,  9538,  9554,  9564,  9618,\n",
+      "        9637,  9681,  9687,  9694,  9704,  9722,  9752,  9812,  9845,\n",
+      "        9892,  9916,  9945,  9974, 10004, 10021, 10033, 10053, 10068,\n",
+      "       10123, 10138, 10150, 10184, 10271, 10374, 10387, 10406, 10449,\n",
+      "       10459, 10510, 10554, 10567, 10599, 10605], dtype=int64), array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
+      "       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
+      "      dtype=int64))\n",
+      "[[ 1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]\n",
+      " [-1]]\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(pos_change)\n",
+    "print(value_change)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(array([ 6855,  6860,  9481,  9510,  9519,  9538,  9554,  9564,  9618,\n",
+      "        9637,  9681,  9687,  9694,  9704,  9722,  9752,  9812,  9845,\n",
+      "        9892,  9916,  9945,  9974, 10004, 10021, 10033, 10053, 10068,\n",
+      "       10123, 10138, 10150, 10184, 10271, 10374, 10387, 10406, 10449,\n",
+      "       10459, 10510, 10554, 10567, 10599, 10605], dtype=int64), array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
+      "       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
+      "      dtype=int64))\n",
+      "[ 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
+      " -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1]\n",
+      "<class 'list'>\n"
+     ]
+    }
+   ],
+   "source": [
+    "#-------------------------------------------------------利用soc的升降判断充放电---------------------------------------------------------\n",
+    "pos_change_dif = np.diff(pos_change[0])#SOC变化时的位置信息\n",
+    "pos_change_del_temp = np.where(pos_change_dif < 10)\n",
+    "pos_change_del = pos_change_del_temp[0] + 1\n",
+    "value_change_new = np.delete(value_change[:,0], pos_change_del)#SOC发生变化数值\n",
+    "pos_change_new = np.delete(pos_change[0], pos_change_del)#SOC发生变化位置\n",
+    "print(pos_change)\n",
+    "print(value_change_new)\n",
+    "value_change_new_dif = np.diff(value_change_new)#寻找充电或放电结束位置\n",
+    "value_change_new_dif = np.insert(value_change_new_dif, 0, value_change_new_dif[0])\n",
+    "chrgr_dischrgr_pos_temp = np.where(abs(value_change_new_dif) == 2)#寻找充电或放电结束位置\n",
+    "splice_num = []\n",
+    "if len(chrgr_dischrgr_pos_temp[0]) >= 1:\n",
+    "    chrgr_dischrgr_pos = pos_change_new[chrgr_dischrgr_pos_temp[0]]#原数据中充电或放电结束位置\n",
+    "    chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, 0, 0)\n",
+    "    data_len = len(df_soc)#数据长度\n",
+    "    pos_len = len(chrgr_dischrgr_pos)#切片长度\n",
+    "    chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, pos_len, data_len-1)#\n",
+    "    print(type(splice_num))\n",
+    "    for item in range(0,len(chrgr_dischrgr_pos)-1):\n",
+    "        splice_num.extend(item*np.ones(chrgr_dischrgr_pos[item +1]-chrgr_dischrgr_pos[item]))\n",
+    "    splice_num = np.insert(splice_num, data_len-2, item)\n",
+    "else:\n",
+    "    splice_num = np.zeros(len(df_soc))\n",
+    "    pos_ful = np.array([0])\n",
+    "data['stat'] = splice_num"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "array([    0,  6855,  9481, 12141], dtype=int64)"
+      ]
+     },
+     "execution_count": 27,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "chrgr_dischrgr_pos"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#--------------------------------------------------------筛选充电数据与放电数据-------------------------------------\n",
+    "chrgr_data = pd.DataFrame()\n",
+    "dischrgr_data = pd.DataFrame()\n",
+    "for num_chrgr in range(0,len(chrgr_dischrgr_pos)-1):\n",
+    "    df_data_temp = data.loc[(data['stat'] == num_chrgr)]#筛选每段数据\n",
+    "    data_splice_len = len(df_data_temp)\n",
+    "    if np.count_nonzero(df_data_temp['总电流[A]'] > 0) > 0.3*data_splice_len:\n",
+    "        chrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] >= 0]#筛选具有充电电流的充电数据\n",
+    "        chrgr_data = chrgr_data.append(chrgr_data_temp)\n",
+    "        chrgr_data = chrgr_data.reset_index(drop = True)\n",
+    "    else:\n",
+    "        dischrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] <= 0]#筛选具有放电电流的放电数据\n",
+    "        dischrgr_data = dischrgr_data.append(dischrgr_data_temp)\n",
+    "        dischrgr_data = dischrgr_data.reset_index(drop = True)\n",
+    "chrgr_num_difference = np.unique(chrgr_data['stat'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>Unnamed: 0</th>\n",
+       "      <th>时间戳</th>\n",
+       "      <th>GSM信号</th>\n",
+       "      <th>故障等级</th>\n",
+       "      <th>故障代码</th>\n",
+       "      <th>总电流[A]</th>\n",
+       "      <th>总电压[V]</th>\n",
+       "      <th>外电压</th>\n",
+       "      <th>总输出状态</th>\n",
+       "      <th>上锁状态</th>\n",
+       "      <th>...</th>\n",
+       "      <th>单体温度1</th>\n",
+       "      <th>单体温度2</th>\n",
+       "      <th>单体温度3</th>\n",
+       "      <th>单体温度4</th>\n",
+       "      <th>其他温度1</th>\n",
+       "      <th>其他温度2</th>\n",
+       "      <th>其他温度3</th>\n",
+       "      <th>其他温度4</th>\n",
+       "      <th>其他温度5</th>\n",
+       "      <th>stat</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>9481</th>\n",
+       "      <td>9481</td>\n",
+       "      <td>2021-12-02 20:29:00</td>\n",
+       "      <td>19</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.2</td>\n",
+       "      <td>65.5</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>13</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>16</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>9483</th>\n",
+       "      <td>9483</td>\n",
+       "      <td>2021-12-02 20:29:44</td>\n",
+       "      <td>30</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.0</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>13</td>\n",
+       "      <td>18</td>\n",
+       "      <td>16</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>9484</th>\n",
+       "      <td>9484</td>\n",
+       "      <td>2021-12-02 20:29:54</td>\n",
+       "      <td>30</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.6</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>18</td>\n",
+       "      <td>16</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>9485</th>\n",
+       "      <td>9485</td>\n",
+       "      <td>2021-12-02 20:30:03</td>\n",
+       "      <td>31</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.5</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>18</td>\n",
+       "      <td>16</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>9486</th>\n",
+       "      <td>9486</td>\n",
+       "      <td>2021-12-02 20:30:13</td>\n",
+       "      <td>31</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.4</td>\n",
+       "      <td>65.7</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>13</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>18</td>\n",
+       "      <td>16</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>...</th>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "      <td>...</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>12137</th>\n",
+       "      <td>12137</td>\n",
+       "      <td>2021-12-03 23:55:59</td>\n",
+       "      <td>23</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.0</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>15</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>12138</th>\n",
+       "      <td>12138</td>\n",
+       "      <td>2021-12-03 23:56:59</td>\n",
+       "      <td>23</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.0</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>15</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>12139</th>\n",
+       "      <td>12139</td>\n",
+       "      <td>2021-12-03 23:57:59</td>\n",
+       "      <td>23</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.0</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>15</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>12140</th>\n",
+       "      <td>12140</td>\n",
+       "      <td>2021-12-03 23:58:59</td>\n",
+       "      <td>23</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.0</td>\n",
+       "      <td>65.6</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>15</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>12141</th>\n",
+       "      <td>12141</td>\n",
+       "      <td>2021-12-03 23:59:59</td>\n",
+       "      <td>23</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0</td>\n",
+       "      <td>0.0</td>\n",
+       "      <td>65.5</td>\n",
+       "      <td>0</td>\n",
+       "      <td>3</td>\n",
+       "      <td>0</td>\n",
+       "      <td>...</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>14</td>\n",
+       "      <td>15</td>\n",
+       "      <td>15</td>\n",
+       "      <td>13</td>\n",
+       "      <td>15</td>\n",
+       "      <td>14</td>\n",
+       "      <td>2.0</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "<p>2590 rows × 47 columns</p>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "       Unnamed: 0                  时间戳  GSM信号  故障等级  故障代码  总电流[A]  总电压[V]  \\\n",
+       "9481         9481  2021-12-02 20:29:00     19     0     0     0.2    65.5   \n",
+       "9483         9483  2021-12-02 20:29:44     30     0     0     0.0    65.6   \n",
+       "9484         9484  2021-12-02 20:29:54     30     0     0     0.6    65.6   \n",
+       "9485         9485  2021-12-02 20:30:03     31     0     0     0.5    65.6   \n",
+       "9486         9486  2021-12-02 20:30:13     31     0     0     0.4    65.7   \n",
+       "...           ...                  ...    ...   ...   ...     ...     ...   \n",
+       "12137       12137  2021-12-03 23:55:59     23     0     0     0.0    65.6   \n",
+       "12138       12138  2021-12-03 23:56:59     23     0     0     0.0    65.6   \n",
+       "12139       12139  2021-12-03 23:57:59     23     0     0     0.0    65.6   \n",
+       "12140       12140  2021-12-03 23:58:59     23     0     0     0.0    65.6   \n",
+       "12141       12141  2021-12-03 23:59:59     23     0     0     0.0    65.5   \n",
+       "\n",
+       "       外电压  总输出状态  上锁状态  ...  单体温度1  单体温度2  单体温度3  单体温度4  其他温度1  其他温度2  其他温度3  \\\n",
+       "9481     0      3     0  ...     13     14     14     14     16     15     13   \n",
+       "9483     0      3     0  ...     14     14     14     13     18     16     13   \n",
+       "9484     0      3     0  ...     14     14     14     14     18     16     13   \n",
+       "9485     0      3     0  ...     14     14     14     14     18     16     13   \n",
+       "9486     0      3     0  ...     13     14     14     14     18     16     13   \n",
+       "...    ...    ...   ...  ...    ...    ...    ...    ...    ...    ...    ...   \n",
+       "12137    0      3     0  ...     14     14     14     14     15     15     13   \n",
+       "12138    0      3     0  ...     14     14     14     14     15     15     13   \n",
+       "12139    0      3     0  ...     14     14     14     14     15     15     13   \n",
+       "12140    0      3     0  ...     14     14     14     14     15     15     13   \n",
+       "12141    0      3     0  ...     14     14     14     14     15     15     13   \n",
+       "\n",
+       "       其他温度4  其他温度5  stat  \n",
+       "9481      15     14   2.0  \n",
+       "9483      15     13   2.0  \n",
+       "9484      15     14   2.0  \n",
+       "9485      15     14   2.0  \n",
+       "9486      15     14   2.0  \n",
+       "...      ...    ...   ...  \n",
+       "12137     15     14   2.0  \n",
+       "12138     15     14   2.0  \n",
+       "12139     15     14   2.0  \n",
+       "12140     15     14   2.0  \n",
+       "12141     15     14   2.0  \n",
+       "\n",
+       "[2590 rows x 47 columns]"
+      ]
+     },
+     "execution_count": 29,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "chrgr_data_temp"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "LookTab_SOC = [0.00, \t2.40, \t6.38, \t10.37, \t14.35, \t18.33, \t22.32, \t26.30, \t30.28, \t35.26, \t40.24, \t45.22, \t50.20, \t54.19, \t58.17, \t60.16, \t65.14, \t70.12, \t75.10, \t80.08, \t84.06, \t88.05, \t92.03, \t96.02, \t100.00, 105]\n",
+    "LookTab_OCV = [2.7151,\t3.0298,\t3.1935,\t3.2009,\t3.2167,\t3.2393,\t3.2561,\t3.2703,\t3.2843,\t3.2871,\t3.2874,\t3.2868,\t3.2896,\t3.2917,\t3.2967,\t3.3128,\t3.3283,\t3.3286,\t3.3287,\t3.3288,\t3.3289,\t3.3296,\t3.3302,\t3.3314,\t3.3429, 3.6]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "     单体电压1  单体电压2  单体电压3  单体电压4  单体电压5  单体电压6  单体电压7  单体电压8  单体电压9  单体电压10  \\\n",
+      "787  3.281  3.286  3.283  3.284  3.283  3.283  3.286  3.286  3.287   3.285   \n",
+      "\n",
+      "     单体电压11  单体电压12  单体电压13  单体电压14  单体电压15  单体电压16  单体电压17  单体电压18  单体电压19  \\\n",
+      "787   3.282   3.288   3.287   3.284   3.284   3.286   3.289   3.289   3.288   \n",
+      "\n",
+      "     单体电压20  \n",
+      "787   3.287  \n"
+     ]
+    }
+   ],
+   "source": [
+    "#--------------------------------------------------------统计充电截止电压、充电SOC区间---------------------------------------------------------\n",
+    "from scipy import interpolate\n",
+    "cell_name = ['单体电压'+str(x) for x in range(1,21)]#电芯电压名称\n",
+    "chrgr_volt = pd.DataFrame()\n",
+    "chrgr_fin_volt = pd.DataFrame()\n",
+    "chrgr_soc = pd.DataFrame()\n",
+    "f = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#差值函数\n",
+    "for chrgr_num in chrgr_num_difference:\n",
+    "    data_temp = chrgr_data.loc[chrgr_data['stat'] == chrgr_num]#该片段数据\n",
+    "    chrgr_crnt_data = data_temp.loc[data_temp['总电流[A]'] > 0]#充电数据中有电流部分,充电时电流为正\n",
+    "    chrgr_crnt_data = chrgr_crnt_data.reset_index(drop = True)\n",
+    "    chrgr_crnt_zero_before = data_temp.loc[data_temp['时间戳'] < chrgr_crnt_data['时间戳'][0]]#充电数据中出现电流前数据\n",
+    "    chrgr_crnt_zero_after = data_temp.loc[data_temp['时间戳'] > chrgr_crnt_data.iloc[-1]['时间戳']]#充电数据中出现电流前数据\n",
+    "    chrgr_crnt_zero_before = chrgr_crnt_zero_before.reset_index(drop = True)\n",
+    "    chrgr_crnt_zero_after = chrgr_crnt_zero_after.reset_index(drop = True)\n",
+    "    time_before = pd.to_datetime(chrgr_crnt_zero_before['时间戳'])\n",
+    "    time_after = pd.to_datetime(chrgr_crnt_zero_after['时间戳'])\n",
+    "    chrgr_rest_len = len(time_after)\n",
+    "    if chrgr_rest_len > 1:\n",
+    "        if (time_after[chrgr_rest_len - 1] - time_after[0])/pd.Timedelta(1, 'min') > 10:\n",
+    "            # chrgr_volt = chrgr_volt.append(chrgr_crnt_zero_before.iloc[-1])#充电开始前静置电压\n",
+    "            chrgr_volt = chrgr_volt.append(chrgr_crnt_zero_after.iloc[-1])#充电结束静置电压\n",
+    "            df_cell_volt = chrgr_volt[cell_name]/1000\n",
+    "            df_cell_volt[df_cell_volt >= 3.6] = 3.595\n",
+    "            df_cell_volt[df_cell_volt <= 2.715] = 2.72\n",
+    "            print(df_cell_volt)\n",
+    "            chrgr_soc = f(df_cell_volt)\n",
+    "# for cell_num in cell_name:#获取各个电芯充电结束后的SOC\n",
+    "#     chrgr_cellsoc = f(chrgr_volt[cell_num]/1000)\n",
+    "#     chrgr_cellsoc_temp = pd.DataFrame(chrgr_cellsoc)\n",
+    "#     chrgr_soc = pd.concat([chrgr_soc, chrgr_cellsoc_temp], axis = 1)#按列合并各个电芯\n",
+    "# chrgr_soc = chrgr_soc.reset_index(drop = True)\n",
+    "# chrgr_soc.columns = cell_name\n",
+    "# chrgr_soc['时间戳'] = list(chrgr_volt['时间戳'])\n",
+    "# chrgr_soc['stat'] = list(chrgr_volt['stat'])\n",
+    "# chrgr_soc['soc_delta'] =  np.max(chrgr_soc[cell_name], axis = 1) - np.min(chrgr_soc[cell_name], axis = 1)\n",
+    "# chrgr_soc['sn'] = 'sn'\n",
+    "# chrgr_soc.to_csv(r'D:\\Work\\Code_write\\data_analyze_platform\\USER\\lzx\\05问题查询\\PK504B00100004003内阻可疑-211206\\充电行为统计\\充电截止SOC.csv',index=False,encoding='GB18030')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0        0.0\n",
+      "1        0.0\n",
+      "2        0.0\n",
+      "3        0.0\n",
+      "4        0.0\n",
+      "        ... \n",
+      "12137    2.0\n",
+      "12138    2.0\n",
+      "12139    2.0\n",
+      "12140    2.0\n",
+      "12141    2.0\n",
+      "Name: stat, Length: 12142, dtype: float64\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(data['stat'])"
+   ]
+  }
+ ],
+ "metadata": {
+  "interpreter": {
+   "hash": "b3ba2566441a7c06988d0923437866b63cedc61552a5af99d1f4fb67d367b25f"
+  },
+  "kernelspec": {
+   "display_name": "Python 3.8.8 64-bit ('base': conda)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.8"
+  },
+  "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}

+ 128 - 0
USER/LZX/01算法开发/02析锂检测/04充电行为/chrgr_statics_pack.py

@@ -0,0 +1,128 @@
+from ctypes import Structure
+from re import M
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+from scipy.signal import savgol_filter
+from scipy import interpolate
+import os
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+class cell_statistic:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.LookTab_OCV = self.param.LookTab_OCV
+        self.LookTab_SOC = self.param.LookTab_SOC
+        self.packcrnt_flg = self.param.PackCrntDec#判断充放电电流方向,一般放电为正,充电为负
+        self.cellvolt_list=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+#.............................................充电行为统计............................................................................
+    def chrgr_sta(self):
+        start_time = time.time()
+        df_chrgr_soc = pd.DataFrame(columns = ['sn', 'crntstrt_time', 'splicestrt_time', 'crntend_time', 'spliceend_time', 'strt_soc', 'end_soc', 'delta_soc', 'state'])
+        data_temp = self.df_bms
+        data = data_temp.dropna(axis = 0, how = 'any', subset = ['总电流[A]', 'SOC[%]'])#删除电流与SOC中的nan值
+        #----------------------------------------区分充放电数据----------------------------------------------------------------------
+        df_soc = data['SOC[%]']
+        df_soc[df_soc > 98] = 100#满SOC
+        df_crnt = data['总电流[A]']
+        df_soc_len = len(df_soc)
+        df_soc_add = df_soc.iloc[df_soc_len-3:df_soc_len-1]#由于对SOC二次微分,增加两行数据
+        df_crnt_add = df_crnt.iloc[df_soc_len-2:df_soc_len-1]#由于对电流不做微分为匹配SOC的一次微分,增加一行数据
+        df_soc_new = df_soc.append(df_soc_add)
+        df_crnt_new = df_crnt.append(df_crnt_add)
+        df_soc_new_dif = np.diff(df_soc_new,axis=0)#SOC一次微分,判断升降
+        df_soc_new_dif = pd.DataFrame(df_soc_new_dif)
+        df_crnt_new = pd.DataFrame(df_crnt_new)
+        df_soc_new_dif[(df_soc_new_dif > 0)] = 1#SOC升高
+        # df_soc_new_dif[(df_soc_new_dif > 0) & (df_crnt_new > 0)] = 0#放电时SOC升高,将SOC差值置0
+        df_soc_new_dif[df_soc_new_dif == 0] = 0#SOC升高或静置
+        df_soc_new_dif[(df_soc_new_dif < 0)] = -1#SOC下降
+        df_soc_dif_arr = np.array(df_soc_new_dif)
+        pos_change = nonzero(df_soc_dif_arr)#寻找非零元素位置
+        value_change = df_soc_dif_arr[pos_change[0]]#非零元素数值
+        #-------------------------------------------------------利用soc的升降判断充放电---------------------------------------------------------
+        pos_change_dif = np.diff(pos_change[0])#计算SOC变化时的位置信息
+        pos_change_del_temp = np.where(pos_change_dif < 40)
+        pos_change_del = pos_change_del_temp[0] + 1
+        value_change_new = np.delete(value_change[:,0], pos_change_del)#SOC发生变化数值
+        pos_change_new = np.delete(pos_change[0], pos_change_del)#SOC发生变化位置
+        value_change_new_dif = np.diff(value_change_new)#寻找充电或放电结束位置
+        value_change_new_dif = np.insert(value_change_new_dif, 0, value_change_new_dif[0])
+        chrgr_dischrgr_pos_temp = np.where(abs(value_change_new_dif) == 2)#寻找充电或放电结束位置
+        splice_num = []
+        if len(chrgr_dischrgr_pos_temp[0]) >= 1:
+            chrgr_dischrgr_pos = pos_change_new[chrgr_dischrgr_pos_temp[0]]#原数据中充电或放电结束位置
+            chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, 0, 0)
+            # data_len = len(df_soc)#数据长度
+            pos_len = len(chrgr_dischrgr_pos)#切片长度
+            chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, pos_len, df_soc_len-1)#
+            for item in range(0,len(chrgr_dischrgr_pos)-1):
+                splice_num.extend(item*np.ones(chrgr_dischrgr_pos[item +1]-chrgr_dischrgr_pos[item]))
+            splice_num = np.insert(splice_num, df_soc_len-2, item)
+        else:
+            splice_num = np.zeros(df_soc_len)
+            # pos_ful = np.array([0])
+        data['stat'] = splice_num
+        #--------------------------------------------------------筛选充电数据与放电数据-------------------------------------
+        # chrgr_data = pd.DataFrame()
+        # dischrgr_data = pd.DataFrame()
+        # for num_chrgr in range(0,len(chrgr_dischrgr_pos)-1):
+        #     df_data_temp = data.loc[(data['stat'] == num_chrgr)]
+        #     df_data_temp = df_data_temp.reset_index(drop = True)
+        #     df_soc_temp = df_data_temp['SOC[%]']
+        #     if len(df_soc_temp) > 10:
+        #         if (df_soc_temp.iloc[-1] - df_soc_temp.iloc[0]) > 10:#筛选SOC增大的区间段,认为是一次充电
+        #             # chrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] >= 0]
+        #             chrgr_data = chrgr_data.append(df_data_temp)
+        #             chrgr_data = chrgr_data.reset_index(drop = True)
+        #         else:
+        #             # dischrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] <= 0]#筛选具有放电电流的放电数据
+        #             dischrgr_data = dischrgr_data.append(df_data_temp)
+        #             dischrgr_data = dischrgr_data.reset_index(drop = True)
+        #     else:
+        #         dischrgr_data = dischrgr_data.append(df_data_temp)
+        #         dischrgr_data = dischrgr_data.reset_index(drop = True)
+        if len(data) > 1:
+            process_difference = set(data['stat'])#充电数据在原数据中的段数
+            #---------------------------------------------------统计充电截止电压、充电SOC区间---------------------------------------------------------
+            if len(process_difference) > 0:
+                for chrgr_num in process_difference:
+                    data_temp = data.loc[(data['stat'] == (chrgr_num - 1))]#该片段数据
+                    crnt_data = data_temp.loc[data_temp['总电流[A]'] != 0]#充电数据中电流非零部分,充电时电流为负
+                    # chrgr_crnt_data = chrgr_crnt_data.reset_index(drop = True)
+                    crnt_zero = data_temp.loc[data_temp['总电流[A]'] == 0]#充电数据中电流为0数据
+                    # chrgr_crnt_zero = chrgr_crnt_zero.reset_index(drop = True)
+                    crnt_time = pd.to_datetime(crnt_data['时间戳'])
+                    crnt_zero_time = pd.to_datetime(crnt_zero['时间戳'])
+                    if (len(crnt_time) > 0) & (len(crnt_zero_time) > 0):
+                        delta_soc = crnt_data['SOC[%]'].iloc[-1] - crnt_data['SOC[%]'].iloc[0]
+                        if delta_soc > 0:
+                            chrgr_sta = ['charged']
+                        else:
+                            chrgr_sta = ['discharged']
+                        df_chrgr_soc_temp = pd.DataFrame({"sn":[self.sn], "crntstrt_time":[crnt_time.iloc[0]], "splicestrt_time":[data_temp['时间戳'].iloc[0]], "crntend_time":[crnt_time.iloc[-1]], 
+                                                "spliceend_time":[data_temp['时间戳'].iloc[-1]], "strt_soc":[crnt_data['SOC[%]'].iloc[0]], "end_soc":[crnt_data['SOC[%]'].iloc[-1]], 
+                                                "delta_soc":[delta_soc], "state":[chrgr_sta]})
+                        df_chrgr_soc = df_chrgr_soc.append(df_chrgr_soc_temp)
+                        df_chrgr_soc.reset_index(drop = True, inplace = True)
+                        # df_chrgr_soc.sort_values(by = ['splicestrt_time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+        if not df_chrgr_soc.empty:
+            return df_chrgr_soc
+        else:
+            return pd.DataFrame()

+ 24 - 0
USER/LZX/01算法开发/02析锂检测/04充电行为/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=r'D:\Platform\platform_python\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\04充电行为\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 105 - 0
USER/LZX/01算法开发/02析锂检测/04充电行为/main.py

@@ -0,0 +1,105 @@
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+import log
+from pandas.core.frame import DataFrame
+import chrgr_statics_pack
+import soc_total
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def chrgr_statics():
+    global SNnums
+    global df_chrgr_static
+    start=time.time()
+    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=3)
+    end_time=str(now_time)
+    start_time=str(start_time)
+    k = 1
+    for sn in SNnums[0:3]:
+        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三元电芯
+        elif 'TJMCL' in sn: 
+            celltype=100 #金茂电芯
+        else:
+            print('SN:{},未找到对应电池类型!!!'.format(sn))
+            continue
+            # sys.exit()
+        print('计算的第' + str(k) + '个:' + sn)
+        k = k + 1
+        #读取原始数据库数据........................................................................................................................................................
+        start_time = '2021-12-01 00:00:00'
+        end_time = '2021-12-31 00:00:00'
+        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']
+        df_Diag_chrgr_add = pd.DataFrame(columns = ['sn', 'crntstrt_time', 'splicestrt_time', 'crntend_time', 'spliceend_time', 'strt_soc', 'end_soc', 'delta_soc', 'state'])
+        #充电统计................................................................................................................................................................
+        if not df_bms.empty:
+            chrgr_statics_temp = chrgr_statics_pack.cell_statistic(sn,celltype,df_bms)#析锂检测
+            df_Diag_chrgr_add = chrgr_statics_temp.chrgr_sta()        
+        if not df_Diag_chrgr_add.empty:
+            df_chrgr_static = df_chrgr_static.append(df_Diag_chrgr_add)
+            df_chrgr_static = df_chrgr_static.drop_duplicates(subset = ['sn','splicestrt_time'], keep = 'first', inplace = False)
+            # df_chrgr_static.sort_values(by = ['sn'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+            df_chrgr_static.to_csv(r'D:\Platform\platform_python\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\04充电行为\金茂充电统计\充电行为.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    global SNnums
+    global df_chrgr_static
+    
+    excelpath=r'D:\Platform\platform_python\data_analyze_platform\USER\lzx\01算法开发\00项目sn号\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()
+    # SNums_file = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\SNnums_C7255析锂情况析锂排序.csv',encoding='GB18030')
+    # SNums_sn = SNums_file['sn']
+    # liplated_high = SNums_sn.iloc[7:10]
+    # liplated_low = SNums_sn.iloc[-11:-1]
+    # cal_sn = liplated_high.append(liplated_low)
+    #SNnums=SNnums_L7255 + SNnums_C7255 + SNnums_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['TJMCL120502305010','TJMCL120502305012','TJMCL120502305048','TJMCL120502305044','TJMCL120502305026','TJMCL120502305022','TJMCL120502305032','TJMCL120502305038']
+    # SNnums = list(cal_sn)#['MGMCLN750N215N049']#['MGMCLN750N215N049'] #SNnums_6040 #SNnums_C7255 #SNnums_6040['MGMCLN750N215N049'] 
+    # SNnums = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\liplated\疑似析锂电池sn.csv',encoding='GB18030')
+    SNnums=['TJMCL120502305010','TJMCL120502305012','TJMCL120502305048','TJMCL120502305044','TJMCL120502305026','TJMCL120502305022','TJMCL120502305032','TJMCL120502305038']
+    mylog=log.Mylog('log_diag.txt','error')#'TJMCL120502305010','TJMCL120502305012',
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    df_chrgr_static = pd.read_csv(r'D:\Platform\platform_python\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\04充电行为\金茂充电统计\充电行为.csv',encoding='GB18030')
+
+    print('----------------输入--------')
+    print('-------计算中-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(chrgr_statics, 'interval', seconds=10, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)
+

+ 133 - 0
USER/LZX/01算法开发/02析锂检测/04充电行为/soc_total.py

@@ -0,0 +1,133 @@
+from ctypes import Structure
+from re import M
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+from scipy.signal import savgol_filter
+from scipy import interpolate
+import os
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+class chrgr_statistic:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.LookTab_OCV = self.param.LookTab_OCV
+        self.LookTab_SOC = self.param.LookTab_SOC
+        self.packcrnt_flg = self.param.PackCrntDec#判断充放电电流方向,一般放电为正,充电为负
+        self.cellvolt_list=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+#.............................................充电行为统计............................................................................
+    def chrgr_soc_sta(self):
+        start_time = time.time()
+        df_chrgr_soc = pd.DataFrame(columns = ['sn', 'time', 'chrgr_soc', 'chrgr_volt', 'temp', 'full_chrgr_num'])
+        data = self.df_bms
+        data.fillna(0, inplace = True)
+        crnt_flg = self.packcrnt_flg
+        LookTab_OCV = self.LookTab_OCV
+        LookTab_SOC = self.LookTab_SOC
+        #----------------------------------------区分充放电数据----------------------------------------------------------------------
+        df_soc = data['SOC[%]']
+        df_soc_len = len(df_soc)
+        df_soc_add = df_soc.iloc[df_soc_len-3:df_soc_len-1]#由于对SOC二次微分,增加两行数据
+        df_soc_new = df_soc.append(df_soc_add)
+        df_soc_new_dif = np.diff(df_soc_new,axis=0)#SOC一次微分,判断升降
+        df_soc_new_dif = pd.DataFrame(df_soc_new_dif)
+        df_soc_new_dif[df_soc_new_dif > 0] = 1#SOC升高
+        df_soc_new_dif[df_soc_new_dif == 0] = 0#SOC升高或静置
+        df_soc_new_dif[df_soc_new_dif < 0] = -1#SOC下降
+        df_soc_dif_arr = np.array(df_soc_new_dif)
+        pos_change = nonzero(df_soc_dif_arr)#寻找非零元素位置
+        value_change = df_soc_dif_arr[pos_change[0]]#非零元素数值
+        #-------------------------------------------------------利用soc的升降判断充放电---------------------------------------------------------
+        pos_change_dif = np.diff(pos_change[0])#计算SOC变化时的位置信息
+        pos_change_del_temp = np.where(pos_change_dif < 10)
+        pos_change_del = pos_change_del_temp[0] + 1
+        value_change_new = np.delete(value_change[:,0], pos_change_del)#SOC发生变化数值
+        pos_change_new = np.delete(pos_change[0], pos_change_del)#SOC发生变化位置
+        value_change_new_dif = np.diff(value_change_new)#寻找充电或放电结束位置
+        if len(value_change_new_dif) > 0:
+            value_change_new_dif = np.insert(value_change_new_dif, 0, value_change_new_dif[0])
+            chrgr_dischrgr_pos_temp = np.where(abs(value_change_new_dif) == 2)#寻找充电或放电结束位置
+            splice_num = []
+            if len(chrgr_dischrgr_pos_temp[0]) >= 1:
+                chrgr_dischrgr_pos = pos_change_new[chrgr_dischrgr_pos_temp[0]]#原数据中充电或放电结束位置
+                chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, 0, 0)
+                # data_len = len(df_soc)#数据长度
+                pos_len = len(chrgr_dischrgr_pos)#切片长度
+                chrgr_dischrgr_pos = np.insert(chrgr_dischrgr_pos, pos_len, df_soc_len-1)#
+                for item in range(0,len(chrgr_dischrgr_pos)-1):
+                    splice_num.extend(item*np.ones(chrgr_dischrgr_pos[item +1]-chrgr_dischrgr_pos[item]))
+                splice_num = np.insert(splice_num, df_soc_len-2, item)
+            else:
+                splice_num = np.zeros(df_soc_len)
+                # pos_ful = np.array([0])
+            data['stat'] = splice_num
+            #--------------------------------------------------------筛选充电数据与放电数据-------------------------------------
+            chrgr_data = pd.DataFrame()
+            dischrgr_data = pd.DataFrame()
+            for num_chrgr in range(0,len(set(splice_num))-1):
+                df_data_temp = data.loc[(data['stat'] == num_chrgr)]
+                df_data_temp = df_data_temp.reset_index(drop = True)
+                df_soc_temp = df_data_temp['SOC[%]']
+                if len(df_soc_temp) > 10:
+                    if (df_soc_temp.iloc[-1] - df_soc_temp.iloc[0]) > 10:#筛选SOC增大的区间段,认为是一次充电
+                        # chrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] >= 0]
+                        chrgr_data = chrgr_data.append(df_data_temp)
+                        chrgr_data = chrgr_data.reset_index(drop = True)
+                    else:
+                        # dischrgr_data_temp = df_data_temp.loc[df_data_temp['总电流[A]'] <= 0]#筛选具有放电电流的放电数据
+                        dischrgr_data = dischrgr_data.append(df_data_temp)
+                        dischrgr_data = dischrgr_data.reset_index(drop = True)
+                else:
+                    dischrgr_data = dischrgr_data.append(df_data_temp)
+                    dischrgr_data = dischrgr_data.reset_index(drop = True)
+            if len(chrgr_data) > 1:
+                chrgr_num_difference = np.unique(chrgr_data['stat'])#充电过程有几段数据
+                #---------------------------------------------------统计充电截止电压、充电SOC区间---------------------------------------------------------
+                cell_name = self.cellvolt_list#电芯电压名称
+                temp_name = self.celltemp_name
+                full_chrgr_num = 0
+                if len(chrgr_num_difference) > 0:
+                    chrgr_soc = pd.DataFrame()
+                    soc_cal = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#插值函数
+                    max_volt = max(LookTab_OCV)
+                    min_volt = min(LookTab_OCV)
+                    for chrgr_num in chrgr_num_difference:
+                        data_temp = chrgr_data.loc[chrgr_data['stat'] == chrgr_num]#该片段数据
+                        chrgr_crnt_data = data_temp.loc[crnt_flg*data_temp['总电流[A]'] < 0]#充电数据中电流非零部分,充电时电流为负
+                        chrgr_crnt_data = chrgr_crnt_data.reset_index(drop = True)
+                        chrgr_crnt_zero = data_temp.loc[data_temp['总电流[A]'] == 0]#充电数据中电流为0数据
+                        chrgr_crnt_zero = chrgr_crnt_zero.reset_index(drop = True)
+                        chrgr_crnt_time = pd.to_datetime(chrgr_crnt_data['时间戳'])
+                        if len(chrgr_crnt_data) > 1:
+                            df_cell_volt = chrgr_crnt_data[cell_name].iloc[-1]/1000
+                            df_cell_volt[df_cell_volt >= max_volt] = max_volt - 0.005
+                            df_cell_volt[df_cell_volt <= min_volt] = min_volt + 0.005
+                            chrgr_soc = soc_cal(list(df_cell_volt))
+                            full_chrgr_check = (chrgr_soc > 98)
+                            if any(full_chrgr_check):
+                                full_chrgr_num = full_chrgr_num + 1
+                            df_chrgr_soc_temp = pd.DataFrame({"sn":[self.sn], "time":[chrgr_crnt_time.iloc[-1]], "chrgr_soc":[str(list(chrgr_soc))], "chrgr_volt":[str(list(df_cell_volt))], 
+                                                    "temp":[str(list(chrgr_crnt_data[temp_name].iloc[-1]))], "full_chrgr_num":[full_chrgr_num]})
+                            df_chrgr_soc = df_chrgr_soc.append(df_chrgr_soc_temp)
+                            df_chrgr_soc = df_chrgr_soc.reset_index(drop = True)
+                            df_chrgr_soc.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+        if not df_chrgr_soc.empty:
+            return df_chrgr_soc
+        else:
+            return pd.DataFrame()

+ 221 - 0
USER/LZX/01算法开发/02析锂检测/liplated/BatParam.py

@@ -0,0 +1,221 @@
+
+#定义电池参数
+class BatParam:
+    def __init__(self,celltype):
+
+        #公用参数................................................................................................................................................
+        self.CellTempUpLmt=119
+        self.CellTempLwLmt=-39
+        self.CellTempHighLv1=45
+        self.CellTempHighLv2=50
+        self.CellTempLowLv1=-20
+        self.CellTempLowLv2=-25
+        self.CellTempDiffLv1=10
+        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=1.5
+
+        self.SocJump=3
+        self.SocClamp=0.1
+        self.SocLow=3
+        self.SocDiff=20
+
+        self.SohLow=65
+        self.SohDiff=20
+
+        self.OcvWeight_Temp=[-30,-20,-10,0,10,20,30,40,50]
+        self.OcvWeight_StandingTime=[0,500,600,1200,1800,3600,7200,10800]
+        self.OcvWeight            =[[0,0,  0,  0,    0,   0.1,0.3, 1],
+                                    [0,0,  0,  0,    0,   0.1,0.3, 1],
+                                    [0,0,  0,  0,    0,   0.2,0.5, 1],
+                                    [0,0,  0,  0,    0.2, 0.4,0.8, 1],
+                                    [0,0,  0,  0.1,  0.3, 0.6,1,   1],
+                                    [0,0,  0.1,0.2,  0.5, 0.8,1,   1],
+                                    [0,0,  0.1,0.3,  0.6, 1,  1,   1],
+                                    [0,0,  0.1,0.3,  0.7, 1,  1,   1],
+                                    [0,0,  0.2,0.3,  0.8, 1,  1,   1]]
+
+
+        if celltype==1: #6040
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=17
+            self.CellTempNums=3
+            self.OtherTempNums=5
+            self.FullChrgSoc=98
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==2: #4840
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=14
+            self.CellTempNums=3
+            self.OtherTempNums=4
+            self.FullChrgSoc=98
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==3:   #力信50ah三元电芯
+            self.Capacity = 51
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=20
+            self.CellTempNums=3
+            self.OtherTempNums=4
+            self.FullChrgSoc=98
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.357, 	3.455, 	3.493, 	3.540, 	3.577, 	3.605, 	3.622, 	3.638, 	3.655, 	3.677, 	3.707, 	3.757, 	3.815, 	3.866, 	3.920, 	3.976, 	4.036, 	4.099, 	4.166, 	4.237, 	4.325, 4.415]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==4:   #CATL 50ah三元电芯
+            self.Capacity = 50
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=20
+            self.CellTempNums=2
+            self.OtherTempNums=0
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=-1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.152, 	3.397, 	3.438, 	3.481, 	3.523, 	3.560, 	3.586, 	3.604, 	3.620, 	3.638, 	3.661, 	3.693, 	3.748, 	3.803, 	3.853, 	3.903, 	3.953, 	4.006, 	4.063, 	4.121, 	4.183, 4.253]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==99:   #60ah磷酸铁锂电芯
+            self.Capacity = 54
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=3.5
+            self.CellFullChrgCrnt=-20
+            self.OcvInflexionBelow=3.281
+            self.OcvInflexion2=3.296
+            self.OcvInflexion3=3.328
+            self.OcvInflexionAbove=3.4
+            self.SocInflexion1=30
+            self.SocInflexion2=60
+            self.SocInflexion3=70
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.OtherTempNums=5
+            self.FullChrgSoc=98
+            self.PeakSoc=59
+            self.PeakVoltLowLmt=3.35
+            self.PeakVoltUpLmt=3.4
+            self.PeakCellVolt=[3.362,3.363,3.365,3.366,3.367]
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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]
+
+            self.CellOvLv1=3.68
+            self.CellOvLv2=3.7
+            self.CellUvLv1=2.1
+            self.CellUvLv2=2
+            self.CellVoltDiffLv1=0.6
+            self.CellVoltDiffLv2=1
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=20
+            self.LeakCurrentLv2=50
+            self.LeakCurrentLv3=100
+        else:
+            print('未找到对应电池编号!!!')
+            # sys.exit()
+

+ 557 - 0
USER/LZX/01算法开发/02析锂检测/liplated/CBMSBatDiag.py

@@ -0,0 +1,557 @@
+import pandas as pd
+import numpy as np
+import datetime
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class BatDiag:
+    def __init__(self,sn,celltype,df_bms,df_soh,df_uniform,df_diag_Ram):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_bms=df_bms
+        self.df_soh=df_soh
+        self.df_uniform=df_uniform
+        self.df_diag_ram=df_diag_Ram
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.bmsfault1=self.df_bms['故障代码']
+        # self.bmsfault2=self.df_bms['alarm2'].tolist()
+        # self.bmsfault3=self.df_bms['alarm3'].tolist()
+        # self.bmsfault4=self.df_bms['fault'].tolist()
+
+        self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+    
+    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 = np.array(self.df_bms.loc[num,self.cellvolt_name]/1000)
+        return cellvolt
+
+    #..........................................三元电池诊断功能..................................................................
+    def _ncm_diag(self):
+
+        bmssoc_st=float(self.bms_soc[0])    #SOC卡滞初始参数
+        ah_accum=0  #SOC卡滞初始参数
+        as_chg=0    #过流诊断初始参数
+        as_dis=0    #过流诊断初始参数
+        time1=self.bmstime[0]   #温升速率初始参数
+        temp1=np.array(self._celltemp_get(0))   #温升速率初始参数
+        temprate_cnt=0
+        
+        end_time='0000-00-00 00:00:00'
+            
+        for i in range(1,len(self.df_bms)):
+            
+            #温度诊断功能.............................................................................................................
+            celltemp0=self._celltemp_get(i-1)
+            celltemp1=self._celltemp_get(i)
+            celltempmin0=min(celltemp0)
+            celltempmin1=min(celltemp1)
+            celltempmax0=max(celltemp0)
+            celltempmax1=max(celltemp1)
+            #温度有效性判断..........................................................................
+            if celltempmax0>self.param.CellTempUpLmt or celltempmin0<self.param.CellTempLwLmt:
+                celltempvalid=0
+            else:  
+                celltempvalid=1
+           
+
+            if celltempvalid==1:
+                #过温判断.............................................................................................................
+                if not 4 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if celltempmax0>self.param.CellTempHighLv2 and celltempmax1>self.param.CellTempHighLv2:    #二级高温进入
+                        time=self.bmstime[i]
+                        code=4
+                        faultlv=3
+                        faultinfo='温度{}高温二级'.format(celltemp1.index(celltempmax1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if celltempmax0<self.param.CellTempHighLv1-5 and celltempmax1<self.param.CellTempHighLv1-5:    #二级高温恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==4].index, 'end_time'] = time
+                    else:
+                        pass
+            
+                #欠温判断.................................................................................................................
+                if not 6 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if celltempmin0<self.param.CellTempLowLv2 and celltempmin1<self.param.CellTempLowLv2:  #二级低温进入
+                        time=self.bmstime[i]
+                        code=6
+                        faultlv=3
+                        faultinfo='温度{}低温二级'.format(celltemp1.index(celltempmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if celltempmax0>self.param.CellTempLowLv1+2 and celltempmax1>self.param.CellTempLowLv1+2:    #二级高温恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==6].index, 'end_time'] = time
+                    else:
+                        pass
+              
+                #温差判断.............................................................................................................................
+                if not 8 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if (celltempmax0-celltempmin0)>self.param.CellTempDiffLv2 and (celltempmax1-celltempmin1)>self.param.CellTempDiffLv2:  #二级温差进入
+                        time=self.bmstime[i]
+                        code=8
+                        faultlv=3
+                        faultinfo='温度{}和{}温差大二级'.format(celltemp1.index(celltempmax1)+1,celltemp1.index(celltempmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if (celltempmax0-celltempmin0)<self.param.CellTempDiffLv1-2 and (celltempmax1-celltempmax0)>self.param.CellTempDiffLv1-2:  #二级温差恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==8].index, 'end_time'] = time
+                    else:
+                        pass
+
+                #温升判断
+                time2=self.bmstime[i]
+                delttime=(time2-time1).total_seconds()
+                if delttime>20:
+                    temp2=np.array(self._celltemp_get(i))
+                    celltemp_rate=(max(temp2-temp1)*60)/delttime    #计算最大温升速率
+                    temp1=temp2 #更新初始温度
+                    time1=time2 #更新初始时间
+                    if celltemp_rate>self.param.CellTempRate:
+                        temprate_cnt=temprate_cnt+1
+                        if not 9 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                            if temprate_cnt>2:  #温升故障进入
+                                time=self.bmstime[i]
+                                code=9
+                                faultlv=3
+                                faultinfo='温升速率过快:{}℃/min'.format(celltemp_rate)
+                                faultadvice='技术介入诊断'
+                                self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                            else:
+                                pass
+                        else:   #ram当前故障中有该故障,则判断是否退出该故障
+                            if celltemp_rate<self.param.CellTempRate-1: #温升故障恢复
+                                time=self.bmstime[i]
+                                self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==9].index, 'end_time'] = time
+                    else:
+                        pass
+                else:
+                    pass
+            
+            else:
+                pass
+            
+            #电压诊断功能.................................................................................................
+            cellvolt0=self._cellvolt_get(i-1)
+            cellvolt1=self._cellvolt_get(i)
+            cellvoltmin0=min(cellvolt0)
+            cellvoltmax0=max(cellvolt0)
+            cellvoltmin1=min(cellvolt1)
+            cellvoltmax1=max(cellvolt1)
+            #电压断线诊断...................................................................................................
+            if (cellvoltmin0<2 and cellvoltmax0>4.5) or cellvoltmin0<0.1 or cellvoltmax0>5:
+                cellvoltvalid=0
+            else:
+                cellvoltvalid=1
+            
+            if cellvoltvalid==1:
+                #过压诊断.............................................................................................................
+                if not 12 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellvoltmax0>self.param.CellOvLv2 and cellvoltmax1>self.param.CellOvLv2:  #二级过压进入
+                        time=self.bmstime[i]
+                        code=12
+                        faultlv=4
+                        faultinfo='电芯{}过压二级'.format(cellvolt1.index(cellvoltmax1)+1)
+                        faultadvice='联系用户询问用车场景,技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if cellvoltmax0<self.param.CellOvLv1-0.05 and cellvoltmax1<self.param.CellOvLv1-0.05:   #二级过压故障恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==12].index, 'end_time'] = time
+                    else:
+                        pass
+              
+
+                #欠压诊断.................................................................................................................
+                if not 14 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellvoltmin0<self.param.CellUvLv2 and cellvoltmin1<self.param.CellUvLv2:  #二级欠压
+                        time=self.bmstime[i]
+                        code=14
+                        faultlv=3
+                        faultinfo='电芯{}欠压二级'.format(cellvolt1.index(cellvoltmin1)+1)
+                        faultadvice='联系用户询问用车场景,技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if cellvoltmin0>self.param.CellUvLv1+0.1 and cellvoltmin1>self.param.CellUvLv1+0.1:
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==14].index, 'end_time'] = time
+                    else:
+                        pass
+             
+                #电芯压差大.....................................................................................................................................................
+                if not 16 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if (cellvoltmax0-cellvoltmin0)>self.param.CellVoltDiffLv2 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv2:  #二级电芯压差
+                        time=self.bmstime[i]
+                        code=16
+                        faultlv=3
+                        faultinfo='电芯{}和{}压差大二级'.format(cellvolt1.index(cellvoltmax1)+1,cellvolt1.index(cellvoltmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if (cellvoltmax0-cellvoltmin0)<self.param.CellVoltDiffLv1-0.05 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv1-0.05: #二级欠压恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==16].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+                
+            #电池包诊断.....................................................................................................................................
+            if not 18 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.packvolt[i-1]>self.param.PackVoltOvLv2 and self.packvolt[i]>self.param.PackVoltOvLv2:   #电池包过压二级进入
+                    time=self.bmstime[i]
+                    code=18
+                    faultlv=4
+                    faultinfo='电池包过压二级'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packvolt[i-1]<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums and self.packvolt[i]<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums: #电池包过压二级恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==18].index, 'end_time'] = time
+                else:
+                    pass
+          
+            #电池包诊断.....................................................................................................................................
+            if not 20 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.packvolt[i-1]<self.param.PackVoltUvLv2 and self.packvolt[i]<self.param.PackVoltUvLv2:   #电池包二级欠压进入
+                    time=self.bmstime[i]
+                    code=20
+                    faultlv=3
+                    faultinfo='电池包欠压二级'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packvolt[i-1]>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums and self.packvolt[i]>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums:   #电池包二级欠压恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==20].index, 'end_time'] = time
+                else:
+                    pass
+            
+            #电流过流诊断.......................................................................................................................
+            step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+            if step<120 and self.packcrnt[i]>self.param.PackDisOc:
+                as_dis=as_dis+(self.packcrnt[i]-self.param.self.PackDisOc)*step    #ah累计
+            elif step<120 and self.packcrnt[i]<self.param.PackChgOc:
+                as_chg=as_chg+(self.param.PackDisOc-self.packcrnt[i])*step    #ah累计
+            else:
+                as_dis=0
+                as_chg=0
+            
+            if not 22 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if as_dis>100:
+                    time=self.bmstime[i]
+                    code=22
+                    faultlv=3
+                    faultinfo='电池包放电过流'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packcrnt[i-1]<self.param.PackDisOc-10 and self.packcrnt[i]<self.param.PackDisOc-10:
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==22].index, 'end_time'] = time
+                else:
+                    pass
+            
+            if not 21 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if as_chg>100:
+                    time=self.bmstime[i]
+                    code=21
+                    faultlv=3
+                    faultinfo='电池包充电过流'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packcrnt[i-1]>self.param.PackChgOc+10 and self.packcrnt[i]>self.param.PackChgOc+10:
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==22].index, 'end_time'] = time
+                else:
+                    pass
+
+            #SOC卡滞、跳变诊断................................................................................................
+            step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+            if step<120:
+                ah_accum=ah_accum-self.packcrnt[i]*step/3600    #ah累计
+            else:
+                pass
+            #SOC卡滞............................................................................................................
+            if abs(ah_accum)>self.param.Capacity*0.05:   
+                bmssoc_now=float(self.bms_soc[i])
+                if not 27 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if abs(bmssoc_now-bmssoc_st)<self.param.SocClamp:   #SOC卡滞故障进入
+                        time=self.bmstime[i]
+                        code=27
+                        faultlv=1
+                        faultinfo='电池SOC卡滞'
+                        faultadvice='技术介入诊断,检修电池BMS软件'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if abs(bmssoc_now-bmssoc_st)>self.param.SocClamp:   #SOC卡滞故障退出
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==27].index, 'end_time'] = time
+                    else:
+                        pass
+                bmssoc_st=bmssoc_now
+                ah_accum=0
+            else:
+                pass
+
+            #SOC跳变....................................................................................................................
+            if step<30: 
+                bmssoc_last=float(self.bms_soc[i-1])
+                bmssoc_now=float(self.bms_soc[i])
+                if not 28 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if abs(bmssoc_now-bmssoc_last)>self.param.SocJump:  #SOC跳变进入
+                        time=self.bmstime[i]
+                        code=28
+                        faultlv=1
+                        faultinfo='电池SOC跳变'
+                        faultadvice='技术介入诊断,检修电池BMS软件'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   
+                    if abs(bmssoc_now-bmssoc_st)<self.param.SocJump:    #SOC跳变故障退出
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==28].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+
+            #SOC过低故障报警............................................................................................................
+            if not 26 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.bms_soc[i-1]<self.param.SocLow and self.bms_soc[i]<self.param.SocLow:   #SOC过低故障进入
+                    time=self.bmstime[0]
+                    code=26
+                    faultlv=1
+                    faultinfo='电池包电量过低'
+                    faultadvice='联系用户,请立刻充电'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:   
+                if self.bms_soc[i-1]>self.param.SocLow and self.bms_soc[i]>self.param.SocLow:   #SOC过低故障退出
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==26].index, 'end_time'] = time
+                else:
+                    pass
+
+            #BMS故障报警........................................................................................................
+            if not 1 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.bmsfault1[i-1] is None or self.bmsfault1[i] is None:
+                    self.bmsfault1[i-1]=0
+                    self.bmsfault1[i]=0
+                if self.bmsfault1[i-1]>0 or self.bmsfault1[i]>0:   #BMS故障进入
+                    time=self.bmstime[0]
+                    code=1
+                    faultlv=2
+                    faultinfo='BMS故障报警:{}'.format(self.bmsfault1[i-1])
+                    faultadvice='技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.bmsfault1[i-1]==0 and self.bmsfault1[i]==0:   #BMS故恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==1].index, 'end_time'] = time
+        
+        
+        #SOC一致性故障报警..........................................................................................................
+        if not self.df_uniform.empty:
+            cellsoc_diff=self.df_uniform.loc[0,'cellsoc_diff']
+            if not 25 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if cellsoc_diff>self.param.SocDiff: #SOC一致性差故障进入
+                    time=self.bmstime[0]
+                    code=25
+                    faultlv=1
+                    faultinfo='电芯{}和{}SOC差过大:{}'.format(self.df_uniform.loc[0,'cellmin_num'],self.df_uniform.loc[0,'cellmax_num']),cellsoc_diff
+                    faultadvice='技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if cellsoc_diff<self.param.SocDiff: #SOC一致性差故障恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==25].index, 'end_time'] = time
+        else:
+            cellsoc_diff=3
+
+        #容量过低和一致性故障报警................................................................................................
+        if not self.df_soh.empty:
+            soh=self.df_soh.loc[0,'soh']
+            cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
+            cellsoh=np.array(cellsoh)
+            cellsoh_lowindex=np.argwhere(cellsoh<self.param.SohLow)
+            cellsoh_lowindex=cellsoh_lowindex+1
+            if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4: 
+                cellsoh_diff=max(cellsoh)-min(cellsoh)
+                if not 23 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if soh<self.param.SohLow:   #soh过低故障进入
+                        time=self.bmstime[0]
+                        code=23
+                        faultlv=1
+                        faultinfo='电池包容量过低:电芯{}'.format(cellsoh_lowindex)
+                        faultadvice='检修电池,更换容量过低的电芯或模组'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if soh>self.param.SohLow+2:   #soh过低故障恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==23].index, 'end_time'] = time
+                    else:
+                        pass
+
+                if not 24 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellsoh_diff>self.param.SohDiff:
+                        time=self.bmstime[0]
+                        code=24
+                        faultlv=1
+                        faultinfo='电池包容量一致性差:电芯{}'.format(cellsoh_lowindex)
+                        faultadvice='检修电池,更换容量过低的电芯或模组'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if cellsoh_diff<self.param.SohDiff-2:
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==24].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+        else:
+            cellsoh_diff=5
+        
+        # #电池健康度评分.....................................................................................................
+        # health_state=soh*0.6+(100-cellsoh_diff)*0.2+(100-cellsoc_diff)*0.2
+        # if health_state>100:
+        #     health_state=100
+        # elif health_state<0:
+        #     health_state=0
+        # else:
+        #     pass
+        # health_state=eval(format(health_state,'.1f'))
+
+        #返回诊断结果...........................................................................................................
+        df_res=self.df_diag_ram
+        if not df_res.empty:
+            return df_res
+        else:
+            return pd.DataFrame()
+
+#............................................................内短路故障诊断.............................................................................
+class ShortDiag():
+    def __init__(self,sn,celltype,df_short):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_short=df_short
+
+    def shortdiag(self):
+        if len(self.df_short)>1:
+            df_res=self._short_diag()
+            return df_res
+        else:
+            return pd.DataFrame()
+
+    #内短路故障检测...................................................................................................................................
+    def _short_diag(self):
+        column_name=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice']
+        df_res=pd.DataFrame(columns=column_name)
+        time=datetime.datetime.now()
+        end_time=datetime.datetime.strftime('0000-00-00 00:00:00')
+        end_time=datetime.datetime.strptime(end_time,'%Y-%m-%d %H:%M:%S')
+
+        # if self.df_diag.empty:
+        #     health_state=100
+        # else:
+        #     health_state=self.df_diag.loc[0,'health_state']
+
+        for i in range(self.param.CellVoltNums):
+            #将字符串分割为多列
+            short_current=self.df_short['short_current']
+            short_current=short_current.str.replace("[", '')
+            short_current=short_current.str.replace("]", '')
+            self.df_short['cellshort'+str(i+1)]=short_current.map(lambda x:x.split(',')[i])
+            self.df_short['cellshort'+str(i+1)]=self.df_short['cellshort'+str(i+1)].map(lambda x:eval(x))
+
+            #漏电流故障判断
+            cellshort=np.array(self.df_short['cellshort'+str(i+1)])
+            shortlv3=np.sum(cellshort>self.param.LeakCurrentLv3)
+            shortlv2=np.sum(cellshort>self.param.LeakCurrentLv2)-shortlv3
+            shortlv1=np.sum(cellshort>self.param.LeakCurrentLv1)-shortlv2-shortlv3
+            shortlv=shortlv3*3 + shortlv2*2 + shortlv1
+
+            if not 31 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if shortlv>=5:
+                    time=self.bmstime[0]
+                    code=31
+                    faultlv=3
+                    faultinfo='电芯{}发生严重内短路'.format(i+1)
+                    faultadvice='禁止充放电,检修电池'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if shortlv<3:
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==31].index, 'end_time'] = time
+        
+        if not df_res.empty:
+            return df_res
+        else:
+            return pd.DataFrame()
+
+

+ 168 - 0
USER/LZX/01算法开发/02析锂检测/liplated/Li_plated.py

@@ -0,0 +1,168 @@
+import pandas as pd
+import numpy as np
+import datetime
+import matplotlib as plt
+from scipy.signal import savgol_filter
+from LIB.MIDDLE.SaftyCenter.Common import QX_BatteryParam as BatParam
+
+class Liplated_test:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatteryInfo(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+
+        self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+#.............................................析锂检测............................................................................
+    def liplated_detect(self):
+        #----------------------------------------筛选充电后静置数据------------------------------------------------------------
+        chrgr_rest_data_temp = self.df_bms.loc[((self.df_bms['充电状态'] == 0) & (self.df_bms['SOC[%]'] > 98) & (self.df_bms['总电流[A]'] == 0)) | 
+                                               ((self.df_bms['充电状态'] == 2) & (self.df_bms['SOC[%]'] > 98) & (self.df_bms['总电流[A]'] == 0))]#接近慢充后静置数据
+        df_lipltd_result = pd.DataFrame(columns=['sn','time','liplated','liplated_amount'])
+        if not chrgr_rest_data_temp.empty:
+            chrgr_rest_data = chrgr_rest_data_temp.reset_index(drop=True)
+            temp_rest_time = chrgr_rest_data['时间戳']
+            rest_time = pd.to_datetime(temp_rest_time)
+            delta_time = (np.diff(rest_time)/pd.Timedelta(1, 'min'))#计算时间差的分钟数
+            pos = np.where(delta_time > 30)#静置数据分段,大于30min时,认为是两个静置过程
+            splice_num = []
+            if len(pos[0]) >= 1:
+                pos_ful_tem = np.insert(pos, 0, 0)
+                pos_len = len(pos_ful_tem)
+                data_len = len(rest_time)
+                pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
+                for item in range(0,len(pos_ful)-1):
+                    splice_num.extend(item*np.ones(pos_ful[item +1]-pos_ful[item]))
+                splice_num = np.insert(splice_num, 0, 0)
+            else:
+                splice_num = np.zeros(len(temp_rest_time))
+                pos_ful = np.array([0])
+            chrgr_rest_data['chrgr_rest'] = splice_num
+            #---------------------------判断数据点数大于30的数据段,对电压微分并画图--------------------------------------------
+            cellvolt_list = self.cellvolt_name
+            chrgr_rest_check_data = chrgr_rest_data.drop(['GSM信号','故障等级','故障代码','绝缘电阻','总电流[A]','总电压[V]','充电状态','单体压差','SOC[%]'],axis=1,inplace=False)
+            chrgr_rest_check_data.fillna(value=0)
+            df_rest_volt_diffdt = pd.DataFrame()
+            df_rest_volt_smooth = pd.DataFrame()
+            k = 0
+            for j in range(0,len(pos_ful)-1):#len(pos_ful)-1#有几段充电后静置数据
+                df_test_rest_data = chrgr_rest_check_data.loc[chrgr_rest_check_data['chrgr_rest'] == j]
+                df_rest_volt_smooth = pd.DataFrame()
+                df_test_rest_time = pd.to_datetime(df_test_rest_data['时间戳'],format='%Y-%m-%d %H:%M:%S')
+                df_test_rest_time = df_test_rest_time.reset_index(drop=True)
+                df_data_length = len(df_test_rest_time)
+                if (df_data_length > 30) & ((df_test_rest_time[df_data_length - 1] - df_test_rest_time[0])/pd.Timedelta(1, 'min') > 40):#静置时间大于40min
+                    df_test_rest_time_dif_temp = np.diff(df_test_rest_time)/pd.Timedelta(1, 'min')
+                    num_list = []
+                    data_jump_pos = np.where(df_test_rest_time_dif_temp > 3)
+                    if len(data_jump_pos[0]) > 0:
+                        if data_jump_pos[0][0] > 100:
+                            for i in range(0,data_jump_pos[0][0],15):##采样密集时每隔10行取数据
+                                num_list.append(i)
+                            df_rest_data_temp = df_test_rest_data.iloc[num_list]
+                            df_test_rest_data_choose = pd.DataFrame(df_rest_data_temp)
+                            df_test_rest_data_choose_else = df_test_rest_data.iloc[data_jump_pos[0][0]+1:len(df_test_rest_data)-1]
+                            df_rest_data_recon_temp = df_test_rest_data_choose.append(df_test_rest_data_choose_else)
+                            df_rest_data_recon =df_rest_data_recon_temp.reset_index(drop=True)
+                        else:
+                            df_rest_data_recon = df_test_rest_data
+                    else:
+                        df_rest_data_recon = df_test_rest_data
+                    df_rest_time = pd.to_datetime(df_rest_data_recon['时间戳'],format='%Y-%m-%d %H:%M:%S')
+                    df_rest_time = df_rest_time.reset_index(drop=True)
+                    df_rest_time_dif_temp = np.diff(df_rest_time)/pd.Timedelta(1, 'min')
+                    df_rest_volt = df_rest_data_recon[cellvolt_list]
+                    for item in cellvolt_list:
+                        window_temp = int(len(df_rest_volt[item])/3)
+                        if window_temp%2:#滤波函数的窗口长度需为奇数
+                            window = window_temp
+                        else:
+                            window = window_temp - 1
+                        step = min(int(window/3),5)
+                        df_volt_smooth = savgol_filter(df_rest_volt[item],window,step)
+                        df_rest_volt_smooth[item] = df_volt_smooth
+                    df_test_rest_volt_diff_temp = np.diff(df_rest_volt_smooth,axis=0)
+                    df_test_rest_time_dif = pd.DataFrame(df_rest_time_dif_temp)
+                    df_test_rest_volt_diff = pd.DataFrame(df_test_rest_volt_diff_temp)
+                    df_test_rest_volt_diffdt_temp = np.divide(df_test_rest_volt_diff,df_test_rest_time_dif)
+                    df_test_rest_volt_diffdt = pd.DataFrame(df_test_rest_volt_diffdt_temp)
+                    df_test_rest_volt_diffdt = df_test_rest_volt_diffdt.append(df_test_rest_volt_diffdt.iloc[len(df_test_rest_volt_diffdt)-1])
+                    df_test_rest_volt_diffdt.columns = cellvolt_list
+                    if len(df_test_rest_volt_diffdt) > 25:
+                        for item in cellvolt_list:
+                            df_volt_diffdt_smooth = savgol_filter(df_test_rest_volt_diffdt[item],13,3)
+                            df_test_rest_volt_diffdt[item] = df_volt_diffdt_smooth
+                        df_test_rest_volt_diffdt['chrgr_rest'] = k
+                        df_test_rest_volt_diffdt['时间戳'] = list(df_rest_time)
+                        k = k+1
+                        df_rest_volt_diffdt = df_rest_volt_diffdt.append(df_test_rest_volt_diffdt)
+                        df_rest_volt_diffdt.reset_index()
+            #--------------------------------------------------------确认是否析锂----------------------------------------------------------------------------
+            for item in range(0,k):
+                lipltd_confirm = []
+                lipltd_amount = []
+                df_check_liplated_temp = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == item].reset_index(drop = True)
+                df_lipltd_volt_temp = df_check_liplated_temp[cellvolt_list]
+                df_lipltd_volt_len = len(df_lipltd_volt_temp)
+                df_data_temp_add = df_lipltd_volt_temp.iloc[df_lipltd_volt_len-3:df_lipltd_volt_len-1]
+                df_lipltd_volt_temp_add = df_lipltd_volt_temp.append(df_data_temp_add)
+                df_lipltd_volt_temp_difdif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压二次微分,判断升降
+                df_lipltd_volt_temp_difdif = pd.DataFrame(df_lipltd_volt_temp_difdif)
+                df_lipltd_volt_temp_difdif.columns = cellvolt_list
+                df_lipltd_volt_temp_difdif_temp = df_lipltd_volt_temp_difdif
+                df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp >= 0] = 1
+                df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp < 0] = -1
+                df_lipltd_volt_temp_difdifdif = np.diff(df_lipltd_volt_temp_difdif_temp,axis=0)#三次微分,利用-2,2判断波分和波谷
+                df_lipltd_volt_difdifdif = pd.DataFrame(df_lipltd_volt_temp_difdifdif)
+                df_lipltd_volt_difdifdif.columns = cellvolt_list
+                df_lipltd_volt_difdifdif['chrgr_rest'] = k
+                df_lipltd_volt_difdifdif['时间戳'] = list(df_check_liplated_temp['时间戳'])
+                df_lipltd_volt_difdifdif = df_lipltd_volt_difdifdif.reset_index(drop = True)
+                df_lipltd_data_temp = df_lipltd_volt_difdifdif.loc[df_lipltd_volt_difdifdif['时间戳'] < (df_check_liplated_temp['时间戳'][0] + datetime.timedelta(minutes=90))]
+                for cell_name in cellvolt_list:#对每个电芯判断
+                    df_check_plated_data = df_lipltd_data_temp[cell_name]
+                    peak_pos = np.where(df_check_plated_data == -2)
+                    bot_pos = np.where(df_check_plated_data == 2)
+                    if len(peak_pos[0]) & len(bot_pos[0]):
+                        ini_dvdt = df_check_liplated_temp[cell_name][0]
+                        peak_dvdt = df_check_liplated_temp[cell_name][peak_pos[0][0] + 1]
+                        bot_dvdt = df_check_liplated_temp[cell_name][bot_pos[0][0] + 1]
+                        peak_hight = peak_dvdt - ini_dvdt
+                        peak_bot_hight = peak_dvdt - bot_dvdt
+                        liplted_amount_temp = (df_check_liplated_temp['时间戳'][bot_pos[0][0] + 1] - df_check_liplated_temp['时间戳'][0])/pd.Timedelta(1, 'min')
+                        liplted_amount_temp = float(format(liplted_amount_temp, '.3f'))
+                        if ((bot_pos[0][0] - peak_pos[0][0]) > 3) & (df_check_liplated_temp[cell_name][peak_pos[0][0] + 1] < 0) & (peak_bot_hight > 0.05*peak_hight) & (liplted_amount_temp > 15):
+                            lipltd_confirm.append(1)#1为析锂,0为非析锂
+                            lipltd_amount.append(liplted_amount_temp)
+                        else:
+                            lipltd_confirm.append(0)
+                            lipltd_amount.append(0)
+                    else:
+                        lipltd_confirm.append(0)
+                        lipltd_amount.append(0)
+                lipltd_amount 
+                if any(lipltd_confirm):
+                    df_lipltd_confir_temp = pd.DataFrame({"sn":[self.sn], "time":[df_check_liplated_temp['时间戳'][0]], "liplated":[str(lipltd_confirm)], "liplated_amount":[str(lipltd_amount)]})
+                    df_lipltd_result = df_lipltd_result.append(df_lipltd_confir_temp)
+                    df_lipltd_result = df_lipltd_result.reset_index(drop = True)
+                    df_lipltd_result.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+        # df_lipltd_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\liplated\算法开发_检测\滤波后图片\析锂.csv',index=False,encoding='GB18030')
+        #返回诊断结果...........................................................................................................
+        if not df_lipltd_result.empty:
+            return df_lipltd_result
+        else:
+            return pd.DataFrame()
+
+

+ 84 - 0
USER/LZX/01算法开发/02析锂检测/liplated/SC_SamplingSafty.py

@@ -0,0 +1,84 @@
+import sys
+import numpy as np
+import pandas as pd
+import string
+import os
+from pandas import Series
+from matplotlib import pyplot as plt
+from pandas.core.frame import DataFrame
+from pandas.core.indexes.base import Index
+from pymysql import NULL
+from LIB.BACKEND import DBManager
+import datetime
+import time
+import string
+import re
+
+
+
+class SamplingSafty:
+    def __init__(self):
+        pass
+    def main(sn,param,bms_info,df_Diag_Ram_in):
+        df_Diag_Ram_Update_inside=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        df_Diag_Ram_Update_inside=df_Diag_Ram_Update_inside.append(df_Diag_Ram_in)
+        global QuitErrCount 
+        VolStarkCount=[0 for i in range(param.CellVoltNums)]
+        VolCount=0
+        QuitErrCount=[0 for i in range(param.FaultCount)]
+        df_Diag_Ram=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        st_tp=[]
+        #--------------该电池的所有当前故障-------------
+
+        VoltageNum=['单体电压'+str(i) for i in range(1,param.CellVoltNums+1)]#单体电压替换cellvolt_
+        CellVoltage=bms_info[VoltageNum]
+        CellMaxVoltage=CellVoltage.max(axis=1)
+        CellMinVoltage=CellVoltage.min(axis=1)
+        InVMaxBatNo=CellVoltage[CellVoltage>=param.CellOVlmt].dropna(axis=0,how='all',inplace=False)
+        InVMinBatNo=CellVoltage[CellVoltage<=param.CellUVlmt].dropna(axis=0,how='all',inplace=False)
+        #date替换为'时间戳'
+        if len(InVMaxBatNo):
+            indexValue=InVMaxBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'单体电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'单体电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'建议返厂维修']                         
+        if len(InVMinBatNo):
+            indexValue=InVMinBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'建议返厂维修']           
+        MedianVol=CellVoltage.median(axis=1).tolist()
+        MediaVolGap=abs(CellVoltage.sub(MedianVol,axis=0))
+        OutlineVol=MediaVolGap[MediaVolGap>=param.AvgVolGap][CellMaxVoltage<param.CellOVlmt][CellMinVoltage>param.CellUVlmt][abs(bms_info['总电流[A]'])<1].dropna(axis=0,how='all',inplace=False)
+        #OutlineVol=OutlineVol[CellMaxVoltage<param.CellOVlmt][CellMinVoltage>param.CellUVlmt].dropna(axis=0,how='all',inplace=False)
+        
+        
+        if len(OutlineVol):
+            indexValue=OutlineVol.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,sn,10,3,'电池电压发生偏移或发生断线','建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,10,3,'电池电压发生偏移或发生断线','建议返厂维修'] 
+        CellTemp=bms_info['单体温度1']
+        InVMaxTempBatNo=CellTemp[CellTemp>=param.PackOTlmt].dropna(axis=0,how='all',inplace=False)
+        InVMinTempBatNo=CellTemp[CellTemp<=param.PackUTlmt].dropna(axis=0,how='all',inplace=False)
+        if len(InVMaxTempBatNo):
+            indexValue=InVMaxTempBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度大于{:.0f}摄氏度,采样无效'.format(param.PackOTlmt),'请立即确认状态']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度大于{:.0f}摄氏度,采样无效'.format(param.PackOTlmt),'请立即确认状态'] 
+        if len(InVMinTempBatNo):
+            indexValue=InVMinTempBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度小于{:.0f}摄氏度,采样无效'.format(param.PackUTlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度小于{:.0f}摄氏度,采样无效'.format(param.PackUTlmt),'建议返厂维修'] 
+        return df_Diag_Ram

+ 185 - 0
USER/LZX/01算法开发/02析锂检测/liplated/liplated_range.py

@@ -0,0 +1,185 @@
+from ctypes import Structure
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+import math
+import os
+import log
+
+path = r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果'
+
+mylog=log.Mylog('log_diag.txt','error')
+mylog.logcfg()
+
+def get_file():                   #创建一个空列表
+    files =os.listdir(path)
+    files.sort() #排序
+    file_list= []
+    for file in files:
+        if not  os.path.isdir(path +file):  #判断该文件是否是一个文件夹       
+            f_name = str(file)        
+#             print(f_name)
+            tr = '\\'   #多增加一个斜杠
+            filename = path + tr + f_name        
+            file_list.append(filename)  
+    return file_list 
+
+file_list = get_file()
+for file in file_list:
+    df_lipltd_level = pd.DataFrame(columns=['sn','total_num','total_amount','liplt_num','liplated_amount','liplated_level','warnning_level'])
+    data = pd.read_csv(file,encoding='GB18030')
+    #----------------------------------------筛选充电后静置数据------------------------------------------------------------
+    # MGMCLN_name = list(filter(lambda x: 'MGMCLN' in x, data['sn']))
+    # df_MGMCLN7255 = data.loc[data['sn'].isin(MGMCLN_name)]
+    df_MGMCLN7255_del = data.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)#去除重复值
+    MGMCLN_list = np.unique(df_MGMCLN7255_del['sn'], return_index = False, return_inverse = False, return_counts = False)#
+    temperature = [15, 20, 22, 21, 17, 6, 4, -0.5]#5~11月平均气温
+    temperatuer = list(map(lambda x: x + 273.15, temperature))
+    for item in MGMCLN_list:
+        df_liamount = pd.DataFrame()
+        df_amount_temp = pd.DataFrame()
+        df_num = pd.DataFrame()
+        df_Num_temp = pd.DataFrame()
+        df_data_temp = df_MGMCLN7255_del.loc[df_MGMCLN7255_del['sn'] == item]
+        df_data_temp.reset_index(drop = True,inplace=True)
+        df_month_temp = pd.to_datetime(df_data_temp['time'])
+        df_month = df_month_temp.dt.month
+        df_month = list(map(lambda x: x - 5, df_month))#月份对应的温度位置
+        for i in range(0,len(df_data_temp)):#len(df_data_temp)
+            df_Num_temp = pd.DataFrame(eval(df_data_temp.iloc[i]['liplated']))#统计析锂次数
+            df_num = pd.concat([df_num,df_Num_temp], axis = 1)#统计总次数
+            df_lipltamount_temp = eval(df_data_temp.iloc[i]['liplated_amount'])#解析原数据列表
+            df_lipltamount_corrt = 4e-17*math.exp(0.1289*temperatuer[df_month[i]])#析锂量的温度系数
+            df_amount_temp = pd.DataFrame(list(map(lambda x: x*df_lipltamount_corrt, df_lipltamount_temp)))
+            df_liamount = pd.concat([df_liamount,df_amount_temp], axis = 1)#按列拼接各个该sn不同时刻的析锂量,每一行为一个电芯
+        df_sn_liamount = np.sum(df_liamount, axis = 1)#对该sn中每个电芯的析锂量求和
+        df_total_amount = np.sum(df_sn_liamount)#所有的析锂量
+        df_sn_num = np.sum(df_num, axis = 1)#对该sn中每个电芯析锂次数的求和
+        df_total_num = np.sum(df_sn_num)#所有的析锂次数
+        df_level_temp = df_sn_liamount.tolist()[:]
+        df_temp_level = np.array(df_level_temp)
+        df_temp_level[df_temp_level < 30] = 0
+        df_temp_level[(df_temp_level >= 30) & (df_temp_level < 60)] = 1
+        df_temp_level[(df_temp_level >= 60) & (df_temp_level < 90)] = 2
+        df_temp_level[(df_temp_level >= 90) & (df_temp_level < 120)] = 3
+        df_temp_level[(df_temp_level >= 120) & (df_temp_level < 180)] = 4
+        df_temp_level[(df_temp_level >= 180) & (df_temp_level <240)] = 5
+        df_temp_level[df_temp_level >= 240] = 6
+        df_level = np.sum(df_temp_level)#电池包析锂量评级
+        df_liplt_num = df_sn_num.tolist()
+        df_liamount_list = df_sn_liamount.tolist()
+        df_liplated_level = df_temp_level.tolist()
+        df_warnning_level = df_level.tolist()
+        df_lipltd_confir_level = pd.DataFrame({"sn":[item],"total_num":[df_total_num],"total_amount":[df_total_amount],"liplt_num":[str(df_liplt_num)], "liplated_amount":[str(df_liamount_list)], "liplated_level":[str(df_liplated_level)],"warnning_level":[str(df_warnning_level)]})
+        df_lipltd_level = df_lipltd_level.append(df_lipltd_confir_level)
+        df_lipltd_level = df_lipltd_level.reset_index(drop = True)
+        df_lipltd_level.sort_values(by = ['total_amount'], ascending=False,inplace=True)#对故障信息按照时间进行排序
+    temp = file.split('\\')
+    sn_name = temp[-1].split('.')[0]
+    title = sn_name
+    df_lipltd_level.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\02析锂分析\各项目析锂情况_211130\增加波峰高度与峰谷比计算结果\\'+ sn_name + '析锂排序.csv',index=False,encoding='GB18030')
+        
+        
+        # df_li_amount = df_data_temp['liplated_amount']
+
+
+
+    # #--------------------------------------------------------确认是否析锂----------------------------------------------------------------------------
+    # # df_lipltd_data = pd.DataFrame(columns=['sn','date','liplated'])
+    # for item in range(0,k):
+    #     lipltd_confirm = []
+    #     lipltd_amount = []
+    #     df_check_liplated_temp = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == item].reset_index(drop = True)
+    #     df_lipltd_volt_temp = df_check_liplated_temp[cellvolt_list]
+    #     df_lipltd_volt_len = len(df_lipltd_volt_temp)
+    #     df_data_temp_add = df_lipltd_volt_temp.iloc[df_lipltd_volt_len-4:df_lipltd_volt_len-1]
+    #     df_lipltd_volt_temp_add = df_lipltd_volt_temp.append(df_data_temp_add)
+    #     df_lipltd_volt_temp_dif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压一次微分,计算dv/dt
+    #     df_lipltd_volt_temp_dif = pd.DataFrame(df_lipltd_volt_temp_dif)
+    #     df_lipltd_volt_temp_dif.columns = cellvolt_list
+    #     df_lipltd_volt_temp_difdif = np.diff(df_lipltd_volt_temp_dif,axis=0)#电压二次微分,判断升降
+    #     df_lipltd_volt_temp_difdif = pd.DataFrame(df_lipltd_volt_temp_difdif)
+    #     df_lipltd_volt_temp_difdif.columns = cellvolt_list
+    #     df_lipltd_volt_temp_difdif_temp = df_lipltd_volt_temp_difdif
+    #     df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp >= 0] = 1
+    #     df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp < 0] = -1
+    #     df_lipltd_volt_temp_difdifdif = np.diff(df_lipltd_volt_temp_difdif_temp,axis=0)#三次微分,利用-2,2判断波分和波谷
+    #     df_lipltd_volt_difdifdif = pd.DataFrame(df_lipltd_volt_temp_difdifdif)
+    #     df_lipltd_volt_difdifdif.columns = cellvolt_list
+    #     df_lipltd_volt_difdifdif['chrgr_rest'] = k
+    #     df_lipltd_volt_difdifdif['时间戳'] = list(df_check_liplated_temp['时间戳'])
+    #     df_lipltd_volt_difdifdif = df_lipltd_volt_difdifdif.reset_index(drop = True)
+    #     df_lipltd_data_temp = df_lipltd_volt_difdifdif.loc[df_lipltd_volt_difdifdif['时间戳'] < (df_check_liplated_temp['时间戳'][0] + datetime.timedelta(minutes=90))]
+    #     for cell_name in cellvolt_list:#对每个电芯判断
+    #         df_check_plated_data = df_lipltd_data_temp[cell_name]
+    #         peak_pos = np.where(df_check_plated_data == -2)
+    #         bot_pos = np.where(df_check_plated_data == 2)
+    #         if len(peak_pos[0]) & len(bot_pos[0]):
+    #             if (peak_pos[0][0] > bot_pos[0][0]) & (df_lipltd_volt_temp_dif[cell_name][peak_pos[0][0] + 1] < 0):
+    #                 lipltd_confirm.append(1)#1为析锂,0为非析锂
+    #                 lipltd_amount.append((df_check_liplated_temp['时间戳'][bot_pos[0][0] + 2] - df_check_liplated_temp['时间戳'][0])/pd.Timedelta(1, 'min'))
+    #             else:
+    #                 lipltd_confirm.append(0)
+    #                 lipltd_amount.append(0)
+    #         else:
+    #             lipltd_confirm.append(0)
+    #             lipltd_amount.append(0)
+    #     if any(lipltd_confirm) & (max(lipltd_amount) > 5):
+    #         df_lipltd_confir_temp = pd.DataFrame({"sn":['sn'], "time":[df_check_liplated_temp['时间戳'][0]], "liplated":[str(lipltd_confirm)], "liplated_amount":[str(lipltd_amount)]})
+    #         df_lipltd_data = df_lipltd_data.append(df_lipltd_confir_temp)
+    #         df_lipltd_data = df_lipltd_data.reset_index(drop = True)
+    #         df_lipltd_data.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+    #         df_lipltd_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\MGMCLN750N215N049\析锂检测.csv',index=False,encoding='GB18030')
+    
+    # # for i in range(1,k):
+    # #     # fig = plt.figure(figsize=(20,10))
+    # #     df_fig = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == i]
+    # #     df_fig = df_fig.reset_index(drop=True)
+    # #     length = len(df_fig)
+    # #     for volt_num in cellvolt_name[5:6]:
+    # #         # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+    # #         plt.plot(df_fig['时间戳'], df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+    # #     plt.rcParams['font.family']=['SimHei']
+    # #     plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    # #     plt.legend()
+    # #     temp = file.split('\\')
+    # #     sn_name = temp[9].split('.')[0]
+    # #     title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+    # #     print(type(title))
+    # #     plt.xlabel('时间', fontsize=14)
+    # #     plt.ylabel('电压的时间微分(mv/min)', fontsize=14)
+    # #     plt.xlim(df_fig['时间戳'][0]-datetime.timedelta(minutes=5),df_fig['时间戳'][0] + datetime.timedelta(hours=3))
+    # #     # plt.ylim(-2.5,0.5)
+    # #     plt.title(title)
+    # #     plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\MGMCLN750N215N049\\'+title+'.png', dpi=300)
+    # #     # plt.show()
+    # fig = plt.figure(figsize=(20,10))
+    # for i in range(3,4):#0,k
+    #     # fig = plt.figure(figsize=(20,10))
+    #     df_fig = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == i]
+    #     df_fig = df_fig.reset_index(drop=True)
+    #     length = len(df_fig)
+    #     temp = file.split('\\')
+    #     sn_name = temp[9].split('.')[0]
+    #     title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+    #     plt_data_len = len(df_fig)
+    #     # for volt_num in cellvolt_name[5:6]:
+    #         # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+    #     # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+    #     # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[2]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+    #     plt.plot(df_fig['时间戳'], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = cellvolt_name[5])
+    #     mpl.rcParams['font.sans-serif']=['SimHei']
+    #     mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    #     plt.legend()
+    #     plt.xlabel('采样点', fontsize=14)
+    #     plt.ylabel('电压的时间微分(mv/min)', fontsize=14)
+    #     plt.xlim(df_fig['时间戳'][0]-datetime.timedelta(minutes=5),df_fig['时间戳'][0] + datetime.timedelta(hours=5))
+    #     # plt.xlim(0, 60)
+    #         # plt.ylim(-2.5,0.5)
+    #     plt.title('6#电芯不同时间电压微分曲线')
+    #     plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\MGMCLN750N215N049\\'+'6#电芯析锂'+'.png', dpi=300)
+    # # plt.show()
+    

+ 316 - 0
USER/LZX/01算法开发/02析锂检测/liplated/liplited_test.py

@@ -0,0 +1,316 @@
+from ctypes import Structure
+from re import M
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import matplotlib.pyplot as plt
+from pylab import*
+from scipy.signal import savgol_filter
+import os
+import log
+
+path = r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561原始数据'
+    
+def get_file():                   #创建一个空列表
+    files =os.listdir(path)
+    files.sort() #排序
+    file_list= []
+    for file in files:
+        if not  os.path.isdir(path +file):  #判断该文件是否是一个文件夹       
+            f_name = str(file)        
+#             print(f_name)
+            tr = '\\'   #多增加一个斜杠
+            filename = path + tr + f_name        
+            file_list.append(filename)  
+    return file_list 
+
+mylog=log.Mylog('log_diag.txt','error')
+mylog.logcfg()
+
+df_lipltd_data = pd.DataFrame(columns=['sn','time','liplated','liplated_amount'])
+file_list = get_file()
+for file in file_list:
+    data = pd.read_csv(file,encoding='GB18030')
+    #----------------------------------------定义滤波函数-----------------------------------------------------------------------
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+    #----------------------------------------筛选充电后静置数据------------------------------------------------------------
+    chrgr_rest_data_temp = data.loc[((data['充电状态'] == 0) & (data['SOC[%]'] > 98) & (data['总电流[A]'] == 0))| 
+                                               ((data['充电状态'] == 2) & (data['SOC[%]'] > 98) & (data['总电流[A]'] == 0))]#接近慢充后静置数据
+    chrgr_rest_data = chrgr_rest_data_temp.reset_index(drop=True)
+    temp_rest_time = chrgr_rest_data['时间戳'].reset_index(drop=True)
+    rest_time = pd.to_datetime(temp_rest_time)
+    # rest_chrg_time = datetime(rest_time)
+    # delta_time = np.diff(rest_chrg_time)
+    delta_time = (np.diff(rest_time)/pd.Timedelta(1, 'min'))#计算时间差的分钟数
+    pos = np.where(delta_time > 30)
+    pos_ful_tem = np.insert(pos, 0, 0)
+    pos_len = len(pos_ful_tem)
+    data_len = len(rest_time)
+    pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
+    splice_num = []
+    if len(pos[0]) >= 1:
+        pos_ful_tem = np.insert(pos, 0, 0)
+        pos_len = len(pos_ful_tem)
+        data_len = len(rest_time)
+        pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
+        for item in range(0,len(pos_ful)-1):
+            splice_num.extend(item*np.ones(pos_ful[item +1]-pos_ful[item]))
+        splice_num = np.insert(splice_num, 0, 0)
+    else:
+        splice_num = np.zeros(len(temp_rest_time))
+        pos_ful = np.array([0])
+    chrgr_rest_data['chrgr_rest'] = splice_num
+    #---------------------------判断数据点数大于30的数据段,对电压微分并画图--------------------------------------------
+    cellvolt_name=['单体电压'+str(x) for x in range(1,18)]
+    cellvolt_list = cellvolt_name
+    chrgr_rest_check_data = chrgr_rest_data.drop(['GSM信号','故障等级','故障代码','单体压差','绝缘电阻','总电流[A]','总电压[V]','充电状态','单体压差','SOC[%]'],axis=1,inplace=False)
+    chrgr_rest_check_data.fillna(value=0)
+    df_rest_volt_diffdt = pd.DataFrame()
+    df_rest_volt_smooth = pd.DataFrame()
+    df_ini_volt_total = pd.DataFrame()
+    k = 0
+    for j in range(0,len(pos_ful)-1):#len(pos_ful)-1#有几段充电后静置数据
+        df_test_rest_data = chrgr_rest_check_data.loc[chrgr_rest_check_data['chrgr_rest'] == j]
+        df_rest_volt_smooth = pd.DataFrame()
+        df_ini_volt = pd.DataFrame()
+        df_test_rest_time = pd.to_datetime(df_test_rest_data['时间戳'],format='%Y-%m-%d %H:%M:%S')
+        df_test_rest_time = df_test_rest_time.reset_index(drop=True)
+        df_data_length = len(df_test_rest_time)
+        if (df_data_length > 30) & ((df_test_rest_time[df_data_length - 1] - df_test_rest_time[0])/pd.Timedelta(1, 'min') > 40):#静置时间大于40min
+            df_test_rest_time_dif_temp = np.diff(df_test_rest_time)/pd.Timedelta(1, 'min')
+            num_list = []
+            data_jump_pos = np.where(df_test_rest_time_dif_temp > 3)
+            if len(data_jump_pos[0]) > 0:
+                if data_jump_pos[0][0] > 100:
+                    for i in range(0,data_jump_pos[0][0],15):##采样密集时每隔10行取数据
+                        num_list.append(i)
+                    df_rest_data_temp = df_test_rest_data.iloc[num_list]
+                    df_test_rest_data_choose = pd.DataFrame(df_rest_data_temp)
+                    df_test_rest_data_choose_else = df_test_rest_data.iloc[data_jump_pos[0][0]+1:len(df_test_rest_data)-1]
+                    df_rest_data_recon_temp = df_test_rest_data_choose.append(df_test_rest_data_choose_else)
+                    df_rest_data_recon =df_rest_data_recon_temp.reset_index(drop=True)
+                else:
+                    df_rest_data_recon = df_test_rest_data
+            else:
+                df_rest_data_recon = df_test_rest_data
+            df_rest_time = pd.to_datetime(df_rest_data_recon['时间戳'],format='%Y-%m-%d %H:%M:%S')
+            df_rest_time = df_rest_time.reset_index(drop=True)
+            df_rest_time_dif_temp = np.diff(df_rest_time)/pd.Timedelta(1, 'min')
+            df_rest_volt = df_rest_data_recon[cellvolt_list]
+            for item in cellvolt_list:
+                window_temp = int(len(df_rest_volt[item])/3)
+                if window_temp%2:#滤波函数的窗口长度需为奇数
+                    window = window_temp
+                else:
+                    window = window_temp - 1
+                step = min(int(window/3),5)
+                df_volt_smooth = savgol_filter(df_rest_volt[item],window,step)
+                df_rest_volt_smooth[item] = df_volt_smooth
+            df_ini_volt = df_ini_volt.append(df_rest_volt_smooth)
+            df_ini_volt.columns = cellvolt_list
+            df_test_rest_volt_diff_temp = np.diff(df_rest_volt_smooth,axis=0)
+            df_test_rest_time_dif = pd.DataFrame(df_rest_time_dif_temp)
+            df_test_rest_volt_diff = pd.DataFrame(df_test_rest_volt_diff_temp)
+            df_test_rest_volt_diffdt_temp = np.divide(df_test_rest_volt_diff,df_test_rest_time_dif)#电压对时间的微分
+            df_test_rest_volt_diffdt = pd.DataFrame(df_test_rest_volt_diffdt_temp)
+            df_test_rest_volt_diffdt = df_test_rest_volt_diffdt.append(df_test_rest_volt_diffdt.iloc[len(df_test_rest_volt_diffdt)-1])
+            df_test_rest_volt_diffdt.columns = cellvolt_list
+            if len(df_test_rest_volt_diffdt) > 25:
+                for item in cellvolt_list:
+                    df_volt_diffdt_smooth = savgol_filter(df_test_rest_volt_diffdt[item],13,3)
+                    df_test_rest_volt_diffdt[item] = df_volt_diffdt_smooth
+                df_test_rest_volt_diffdt['chrgr_rest'] = k
+                df_test_rest_volt_diffdt['时间戳'] = list(df_rest_time)
+                df_ini_volt['chrgr_rest'] = k
+                df_ini_volt['时间戳'] = list(df_rest_time)
+                k = k+1
+                df_rest_volt_diffdt = df_rest_volt_diffdt.append(df_test_rest_volt_diffdt)#电压对时间的一次微分
+                df_rest_volt_diffdt.reset_index()
+                df_ini_volt_total = df_ini_volt_total.append(df_ini_volt)
+                df_ini_volt_total.reset_index()
+    #--------------------------------------------------------确认是否析锂----------------------------------------------------------------------------
+    # df_lipltd_data = pd.DataFrame(columns=['sn','date','liplated'])
+    m_num = 0
+    df_fig_dvdtdata = pd.DataFrame()
+    df_fig_voltdata = pd.DataFrame()
+    for item in range(0,k):
+        lipltd_confirm = []
+        lipltd_amount = []
+        df_check_liplated_temp = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == item].reset_index(drop = True)
+        df_check_volt_temp = df_ini_volt_total.loc[df_ini_volt_total['chrgr_rest'] == item].reset_index(drop = True)
+        df_lipltd_volt_temp = df_check_liplated_temp[cellvolt_list]
+        df_lipltd_volt_len = len(df_lipltd_volt_temp)
+        df_data_temp_add = df_lipltd_volt_temp.iloc[df_lipltd_volt_len-3:df_lipltd_volt_len-1]#电压对时间的一次微分
+        df_lipltd_volt_temp_add = df_lipltd_volt_temp.append(df_data_temp_add)
+        # df_lipltd_volt_temp_dif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压一次微分,计算dv/dt
+        # df_lipltd_volt_temp_dif = pd.DataFrame(df_lipltd_volt_temp_dif)
+        # df_lipltd_volt_temp_dif.columns = cellvolt_list
+        df_lipltd_volt_temp_difdif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压二次微分,判断升降
+        df_lipltd_volt_temp_difdif = pd.DataFrame(df_lipltd_volt_temp_difdif)
+        df_lipltd_volt_temp_difdif.columns = cellvolt_list
+        df_lipltd_volt_temp_difdif_temp = df_lipltd_volt_temp_difdif
+        df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp >= 0] = 1
+        df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp < 0] = -1
+        df_lipltd_volt_temp_difdifdif = np.diff(df_lipltd_volt_temp_difdif_temp,axis=0)#三次微分,利用-2,2判断波分和波谷
+        df_lipltd_volt_difdifdif = pd.DataFrame(df_lipltd_volt_temp_difdifdif)
+        df_lipltd_volt_difdifdif.columns = cellvolt_list
+        df_lipltd_volt_difdifdif['chrgr_rest'] = k
+        df_lipltd_volt_difdifdif['时间戳'] = list(df_check_liplated_temp['时间戳'])
+        df_lipltd_volt_difdifdif = df_lipltd_volt_difdifdif.reset_index(drop = True)
+        df_lipltd_data_temp = df_lipltd_volt_difdifdif.loc[df_lipltd_volt_difdifdif['时间戳'] < (df_check_liplated_temp['时间戳'][0] + datetime.timedelta(minutes=90))]
+        for cell_name in cellvolt_list:#对每个电芯判断
+            df_check_plated_data = df_lipltd_data_temp[cell_name]
+            peak_pos = np.where(df_check_plated_data == -2)
+            bot_pos = np.where(df_check_plated_data == 2)
+            if len(bot_pos[0]) & len(peak_pos[0]):
+                ini_dvdt = df_check_liplated_temp[cell_name][0]
+                peak_dvdt = df_check_liplated_temp[cell_name][peak_pos[0][0] + 1]
+                bot_dvdt = df_check_liplated_temp[cell_name][bot_pos[0][0] + 1]
+                peak_hight = peak_dvdt - ini_dvdt
+                peak_bot_hight = peak_dvdt - bot_dvdt
+                liplted_amount_temp = (df_check_liplated_temp['时间戳'][bot_pos[0][0] + 1] - df_check_liplated_temp['时间戳'][0])/pd.Timedelta(1, 'min')
+                if ((bot_pos[0][0] - peak_pos[0][0]) > 3) & (df_check_liplated_temp[cell_name][peak_pos[0][0] + 1] < 0) & (peak_bot_hight > 0.05*peak_hight) & (liplted_amount_temp > 15):
+                    lipltd_confirm.append(1)#1为析锂,0为非析锂
+                    lipltd_amount.append(liplted_amount_temp)
+                else:
+                    lipltd_confirm.append(0)
+                    lipltd_amount.append(0)
+            else:
+                lipltd_confirm.append(0)
+                lipltd_amount.append(0)
+        if any(lipltd_confirm):
+            temp = file.split('\\')
+            sn_name = temp[-1].split('.')[0]
+            df_lipltd_confir_temp = pd.DataFrame({"sn":[sn_name], "time":[df_check_liplated_temp['时间戳'][0]], "liplated":[str(lipltd_confirm)], "liplated_amount":[str(lipltd_amount)]})
+            df_lipltd_data = df_lipltd_data.append(df_lipltd_confir_temp)
+            df_lipltd_data = df_lipltd_data.reset_index(drop = True)
+            df_lipltd_data.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+            df_fig_dvdtdata_temp = df_check_liplated_temp
+            df_fig_dvdtdata_temp['chrgr_rest'] = m_num
+            df_fig_dvdtdata = df_fig_dvdtdata.append(df_fig_dvdtdata_temp)#电压对时间微分数据
+            df_fig_dvdtdata = df_fig_dvdtdata.reset_index(drop = True)
+            df_fig_voltdata_temp = df_check_volt_temp
+            df_fig_voltdata_temp['chrgr_rest'] = m_num
+            df_fig_voltdata = df_fig_voltdata.append(df_fig_voltdata_temp)#原始电压数据
+            df_fig_voltdata = df_fig_voltdata.reset_index(drop = True)
+            m_num = m_num + 1
+            df_lipltd_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561析锂检测结果\PK50001A100000561.csv',index=False,encoding='GB18030')
+            df_fig_dvdtdata.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561析锂检测结果\微分电压曲线.csv',index=False,encoding='GB18030')
+            df_fig_voltdata.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561析锂检测结果\电压曲线.csv',index=False,encoding='GB18030')
+    
+    for i in range(0,m_num):
+        fig = plt.figure(figsize=(20,10))
+        df_fig_temp = df_fig_dvdtdata.loc[df_fig_dvdtdata['chrgr_rest'] == i]
+        df_fig_temp = df_fig_temp.reset_index(drop=True)
+        df_fig = df_fig_temp.loc[df_fig_temp['时间戳'] < (df_fig_temp['时间戳'][0] + datetime.timedelta(hours=1))]
+        length = len(df_fig)
+        df_hms_temp = pd.to_datetime(df_fig['时间戳'])#转换时间格式
+        df_hms = df_hms_temp.dt.time#仅保留时分秒
+        df_hms_fig = df_hms.apply(lambda x:x.strftime('%H:%M:%S'))
+        for volt_num in cellvolt_name[0:10]:
+            # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+            plt.plot(df_hms_fig, df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+        mpl.rcParams['font.sans-serif']=['KaiTi']
+        mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        temp = file.split('\\')
+        sn_name = temp[-1].split('.')[0]
+        title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+        plt.xlabel('时间', fontsize=16)
+        plt.ylabel('电压的时间微分(mv/min)', fontsize=16)
+        plt.xticks(range(1,len(df_hms_fig),5),rotation=45, fontsize=16)
+        plt.yticks(fontsize=16)
+        # plt.xlim((df_hms_temp[0]-datetime.timedelta(minutes=5)).dt.time,(df_hms_temp[0] + datetime.timedelta(hours=1.5)).dt.time)
+        # plt.ylim(-2.5,0.5)
+        plt.title(title, fontsize=20)
+        # plt.show()
+        plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561析锂分布画图\微分电压曲线\\'+title+'前.png', dpi=300)
+    for i in range(0,m_num):
+        fig = plt.figure(figsize=(20,10))
+        df_fig_temp = df_fig_dvdtdata.loc[df_fig_dvdtdata['chrgr_rest'] == i]
+        df_fig_temp = df_fig_temp.reset_index(drop=True)
+        df_fig = df_fig_temp.loc[df_fig_temp['时间戳'] < (df_fig_temp['时间戳'][0] + datetime.timedelta(hours=1))]
+        length = len(df_fig)
+        df_hms_temp = pd.to_datetime(df_fig['时间戳'])#转换时间格式
+        df_hms = df_hms_temp.dt.time#仅保留时分秒
+        df_hms_fig = df_hms.apply(lambda x:x.strftime('%H:%M:%S'))
+        for volt_num in cellvolt_name[10:21]:
+            # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+            plt.plot(df_hms_fig, df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+        mpl.rcParams['font.sans-serif']=['KaiTi']
+        mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+        plt.legend()
+        temp = file.split('\\')
+        sn_name = temp[-1].split('.')[0]
+        title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+        plt.xlabel('时间', fontsize=16)
+        plt.ylabel('电压的时间微分(mv/min)', fontsize=16)
+        plt.xticks(range(1,len(df_hms_fig),5),rotation=45, fontsize=16)
+        plt.yticks(fontsize=16)
+        # plt.xlim((df_hms_temp[0]-datetime.timedelta(minutes=5)).dt.time,(df_hms_temp[0] + datetime.timedelta(hours=1.5)).dt.time)
+        # plt.ylim(-2.5,0.5)
+        plt.title(title, fontsize=20)
+        # plt.show()
+        plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561析锂分布画图\微分电压曲线\\'+title+'后.png', dpi=300)
+    #-------------------------------------原始电压变化曲线-------------------------------------------------
+    fig = plt.figure(figsize=(20,15))
+    for i in range(0,m_num):#0,k
+        # fig = plt.figure(figsize=(20,10))
+        df_fig = df_fig_voltdata.loc[df_fig_voltdata['chrgr_rest'] == i]
+        df_fig = df_fig.reset_index(drop=True)
+        length = len(df_fig)
+        temp = file.split('\\')
+        sn_name = temp[-1].split('.')[0]
+        title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+        plt_data_len = len(df_fig)
+        # for volt_num in cellvolt_name[5:6]:
+            # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+        # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+        plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+        # plt.plot(df_fig['时间戳'], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)#cellvolt_name[5]
+    mpl.rcParams['font.sans-serif']=['KaiTi']
+    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    plt.legend(fontsize=24)
+    plt.xlabel('采样点', fontsize=24)
+    plt.ylabel('电压(mV)', fontsize=24)
+    plt.xticks(fontsize=20)
+    plt.yticks(fontsize=20)
+    
+    # plt.xlim(df_fig['时间戳'][0]-datetime.timedelta(minutes=5),df_fig['时间戳'][0] + datetime.timedelta(hours=1.5))
+    # plt.xlim(0, 30)
+    # plt.ylim(4120, 4200)
+        # plt.ylim(-2.5,0.5)
+    plt.title('6#电芯不同时刻电压曲线', fontsize=30)
+    plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\PK6040\0561析锂分布画图\静置电压曲线\\'+'6#电芯不同时刻电压曲线'+'.png', dpi=300)
+#     # plt.show()
+    # fig = plt.figure(figsize=(20,10))
+    # for i in range(3,4):#0,k
+    #     # fig = plt.figure(figsize=(20,10))
+    #     df_fig = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == i]
+    #     df_fig = df_fig.reset_index(drop=True)
+    #     length = len(df_fig)
+    #     temp = file.split('\\')
+    #     sn_name = temp[9].split('.')[0]
+    #     title = sn_name + '-' + df_fig['时间戳'][0].strftime('%y-%m-%d')#df_fig['device_id'][0] + '-' + 
+    #     plt_data_len = len(df_fig)
+    #     # for volt_num in cellvolt_name[5:6]:
+    #         # plt.scatter([x for x in range(0, length)], df_fig[volt_num][0:length], label=volt_num)
+    #     # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+    #     # plt.plot([x for x in range(0, plt_data_len)], df_fig[cellvolt_name[2]],linewidth = 2, linestyle = '-', marker = 's',label = title)
+    #     plt.plot(df_fig['时间戳'], df_fig[cellvolt_name[5]],linewidth = 2, linestyle = '-', marker = 's',label = cellvolt_name[5])
+    #     mpl.rcParams['font.sans-serif']=['SimHei']
+    #     mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+    #     plt.legend()
+    #     plt.xlabel('采样点', fontsize=14)
+    #     plt.ylabel('电压的时间微分(mv/min)', fontsize=14)
+    #     plt.xlim(df_fig['时间戳'][0]-datetime.timedelta(minutes=5),df_fig['时间戳'][0] + datetime.timedelta(hours=5))
+    #     # plt.xlim(0, 60)
+    #         # plt.ylim(-2.5,0.5)
+    #     plt.title('6#电芯不同时间电压微分曲线')
+    #     plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\01下载数据\MGMCLN750N215N049\\'+'6#电芯析锂'+'.png', dpi=300)
+    # plt.show()
+    

+ 24 - 0
USER/LZX/01算法开发/02析锂检测/liplated/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=r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\01算法开发\02析锂检测\liplated\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 100 - 0
USER/LZX/01算法开发/02析锂检测/liplated/main.py

@@ -0,0 +1,100 @@
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+import log
+from pandas.core.frame import DataFrame
+import Li_plated
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def cell_platd_test():
+    global SNnums
+    global df_Diag_lipltd
+    start=time.time()
+    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=3)
+    end_time=str(now_time)
+    start_time=str(start_time)
+    k = 1
+    for sn in SNnums:
+        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三元电芯
+        elif 'TJMCL' in sn: 
+            celltype=100 #金茂电芯
+        else:
+            print('SN:{},未找到对应电池类型!!!'.format(sn))
+            continue
+            # sys.exit()
+        print('计算的第' + str(k) + '个:' + sn)
+        k = k + 1
+        #读取原始数据库数据........................................................................................................................................................
+        start_time = '2021-8-20 12:00:00'
+        end_time = '2021-8-31 12:00:00'
+        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']
+        df_Diag_lipltd_add = pd.DataFrame(columns = ['sn','time','liplated', 'liplated_amount'])
+
+        #析锂诊断................................................................................................................................................................
+        if not df_bms.empty:
+            Diag_lipltd_temp = Li_plated.Liplated_test(sn,celltype,df_bms)#析锂检测
+            df_Diag_lipltd_add = Diag_lipltd_temp.liplated_detect()
+        print(df_Diag_lipltd_add)        
+        if not df_Diag_lipltd_add.empty:
+            df_Diag_lipltd_temp = df_Diag_lipltd.append(df_Diag_lipltd_add)
+            df_Diag_lipltd = df_Diag_lipltd_temp.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)
+            df_Diag_lipltd.sort_values(by = ['sn'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+            df_Diag_lipltd.to_csv(r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\01算法开发\02析锂检测\liplated\析锂.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    global SNnums
+    global df_Diag_lipltd
+    
+    excelpath=r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\01算法开发\00项目sn号\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['TJMCL120502305010','TJMCL120502305012','TJMCL120502305048','TJMCL120502305044','TJMCL120502305026','TJMCL120502305022','TJMCL120502305032','TJMCL120502305038']
+    SNnums = ['MGMCLN750N215N049']#['MGMCLN750N215N049'] #SNnums_6040 #SNnums_C7255 #SNnums_6040['MGMCLN750N215N049'] 
+    # SNnums = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\liplated\疑似析锂电池sn.csv',encoding='GB18030')
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    df_Diag_lipltd=pd.read_csv(r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\01算法开发\02析锂检测\liplated\析锂.csv',encoding='GB18030')
+
+    print('----------------输入--------')
+    print('-------计算中-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(cell_platd_test, 'interval', seconds=10, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

Файловите разлики са ограничени, защото са твърде много
+ 71 - 0
USER/LZX/01算法开发/02析锂检测/析锂检测/liplated_test.ipynb


Файловите разлики са ограничени, защото са твърде много
+ 65 - 0
USER/LZX/01算法开发/02析锂检测/析锂检测/liplated_test2.ipynb


Файловите разлики са ограничени, защото са твърде много
+ 52 - 0
USER/LZX/01算法开发/03电压信息熵/01算法开发/entropy.ipynb


+ 208 - 0
USER/LZX/01算法开发/04故障诊断/BatParam.py

@@ -0,0 +1,208 @@
+
+#定义电池参数
+
+class BatParam:
+    def __init__(self,celltype):
+
+        #公用参数................................................................................................................................................
+        self.CellTempUpLmt=119
+        self.CellTempLwLmt=-39
+        self.CellTempHighLv1=45
+        self.CellTempHighLv2=50
+        self.CellTempLowLv1=-20
+        self.CellTempLowLv2=-25
+        self.CellTempDiffLv1=10
+        self.CellTempDiffLv2=15
+        self.CellTempRate=5
+
+        self.SocJump=3
+        self.SocClamp=0.1
+        self.SocLow=3
+        self.SocDiff=20
+
+        self.SohLow=65
+        self.SohDiff=20
+
+        self.OcvWeight_Temp=[-30,-20,-10,0,10,20,30,40,50]
+        self.OcvWeight_StandingTime=[0,500,600,1200,1800,3600,7200,10800]
+        self.OcvWeight            =[[0,0,  0,  0,    0,   0.1,0.3, 1],
+                                    [0,0,  0,  0,    0,   0.1,0.3, 1],
+                                    [0,0,  0,  0,    0,   0.2,0.5, 1],
+                                    [0,0,  0,  0,    0.2, 0.4,0.8, 1],
+                                    [0,0,  0,  0.1,  0.3, 0.6,1,   1],
+                                    [0,0,  0.1,0.2,  0.5, 0.8,1,   1],
+                                    [0,0,  0.1,0.3,  0.6, 1,  1,   1],
+                                    [0,0,  0.1,0.3,  0.7, 1,  1,   1],
+                                    [0,0,  0.2,0.3,  0.8, 1,  1,   1]]
+
+
+        if celltype==1: #6040
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=17
+            self.CellTempNums=3
+            self.FullChrgSoc=98
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+
+            self.CellOvLv1=4.3#原为4.3
+            self.CellOvLv2=4.35#原为4.35
+            self.CellUvLv1=2.8#原为2.8
+            self.CellUvLv2=2.5#原为2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==2: #4840
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=14
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==3:   #力信50ah三元电芯
+            self.Capacity = 51
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.357, 	3.455, 	3.493, 	3.540, 	3.577, 	3.605, 	3.622, 	3.638, 	3.655, 	3.677, 	3.707, 	3.757, 	3.815, 	3.866, 	3.920, 	3.976, 	4.036, 	4.099, 	4.166, 	4.237, 	4.325, 4.415]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==4:   #CATL 50ah三元电芯
+            self.Capacity = 50
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellFullChrgCrnt=-15
+            self.CellVoltNums=20
+            self.CellTempNums=2
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=-1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.152, 	3.397, 	3.438, 	3.481, 	3.523, 	3.560, 	3.586, 	3.604, 	3.620, 	3.638, 	3.661, 	3.693, 	3.748, 	3.803, 	3.853, 	3.903, 	3.953, 	4.006, 	4.063, 	4.121, 	4.183, 4.253]
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=10
+            self.LeakCurrentLv2=20
+            self.LeakCurrentLv3=50
+
+        elif celltype==99:   #60ah磷酸铁锂电芯
+            self.Capacity = 54
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=3.5
+            self.CellFullChrgCrnt=-20
+            self.OcvInflexionBelow=3.281
+            self.OcvInflexion2=3.296
+            self.OcvInflexion3=3.328
+            self.OcvInflexionAbove=3.4
+            self.SocInflexion1=30
+            self.SocInflexion2=60
+            self.SocInflexion3=70
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PeakSoc=59
+            self.PeakVoltLowLmt=3.35
+            self.PeakVoltUpLmt=3.4
+            self.PeakCellVolt=[3.362,3.363,3.365,3.366,3.367]
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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]
+
+            self.CellOvLv1=3.68
+            self.CellOvLv2=3.7
+            self.CellUvLv1=2.1
+            self.CellUvLv2=2
+            self.CellVoltDiffLv1=0.6
+            self.CellVoltDiffLv2=1
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=-40
+            self.PackDisOc=200
+
+            self.LeakCurrentLv1=20
+            self.LeakCurrentLv2=50
+            self.LeakCurrentLv3=100
+        else:
+            print('未找到对应电池编号!!!')
+            # sys.exit()
+

+ 557 - 0
USER/LZX/01算法开发/04故障诊断/CBMSBatDiag.py

@@ -0,0 +1,557 @@
+import pandas as pd
+import numpy as np
+import datetime
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class BatDiag:
+    def __init__(self,sn,celltype,df_bms,df_soh,df_uniform,df_diag_Ram):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_bms=df_bms
+        self.df_soh=df_soh
+        self.df_uniform=df_uniform
+        self.df_diag_ram=df_diag_Ram
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.bmsfault1=self.df_bms['故障代码']
+        # self.bmsfault2=self.df_bms['alarm2'].tolist()
+        # self.bmsfault3=self.df_bms['alarm3'].tolist()
+        # self.bmsfault4=self.df_bms['fault'].tolist()
+
+        self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+    
+    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 = np.array(self.df_bms.loc[num,self.cellvolt_name]/1000)
+        return cellvolt
+
+    #..........................................三元电池诊断功能..................................................................
+    def _ncm_diag(self):
+
+        bmssoc_st=float(self.bms_soc[0])    #SOC卡滞初始参数
+        ah_accum=0  #SOC卡滞初始参数
+        as_chg=0    #过流诊断初始参数
+        as_dis=0    #过流诊断初始参数
+        time1=self.bmstime[0]   #温升速率初始参数
+        temp1=np.array(self._celltemp_get(0))   #温升速率初始参数
+        temprate_cnt=0
+        
+        end_time='0000-00-00 00:00:00'
+            
+        for i in range(1,len(self.df_bms)):
+            
+            #温度诊断功能.............................................................................................................
+            celltemp0=self._celltemp_get(i-1)
+            celltemp1=self._celltemp_get(i)
+            celltempmin0=min(celltemp0)
+            celltempmin1=min(celltemp1)
+            celltempmax0=max(celltemp0)
+            celltempmax1=max(celltemp1)
+            #温度有效性判断..........................................................................
+            if celltempmax0>self.param.CellTempUpLmt or celltempmin0<self.param.CellTempLwLmt:
+                celltempvalid=0
+            else:  
+                celltempvalid=1
+           
+
+            if celltempvalid==1:
+                #过温判断.............................................................................................................
+                if not 4 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if celltempmax0>self.param.CellTempHighLv2 and celltempmax1>self.param.CellTempHighLv2:    #二级高温进入
+                        time=self.bmstime[i]
+                        code=4
+                        faultlv=3
+                        faultinfo='温度{}高温二级'.format(celltemp1.index(celltempmax1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if celltempmax0<self.param.CellTempHighLv1-5 and celltempmax1<self.param.CellTempHighLv1-5:    #二级高温恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==4].index, 'end_time'] = time
+                    else:
+                        pass
+            
+                #欠温判断.................................................................................................................
+                if not 6 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if celltempmin0<self.param.CellTempLowLv2 and celltempmin1<self.param.CellTempLowLv2:  #二级低温进入
+                        time=self.bmstime[i]
+                        code=6
+                        faultlv=3
+                        faultinfo='温度{}低温二级'.format(celltemp1.index(celltempmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if celltempmax0>self.param.CellTempLowLv1+2 and celltempmax1>self.param.CellTempLowLv1+2:    #二级高温恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==6].index, 'end_time'] = time
+                    else:
+                        pass
+              
+                #温差判断.............................................................................................................................
+                if not 8 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if (celltempmax0-celltempmin0)>self.param.CellTempDiffLv2 and (celltempmax1-celltempmin1)>self.param.CellTempDiffLv2:  #二级温差进入
+                        time=self.bmstime[i]
+                        code=8
+                        faultlv=3
+                        faultinfo='温度{}和{}温差大二级'.format(celltemp1.index(celltempmax1)+1,celltemp1.index(celltempmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if (celltempmax0-celltempmin0)<self.param.CellTempDiffLv1-2 and (celltempmax1-celltempmax0)>self.param.CellTempDiffLv1-2:  #二级温差恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==8].index, 'end_time'] = time
+                    else:
+                        pass
+
+                #温升判断
+                time2=self.bmstime[i]
+                delttime=(time2-time1).total_seconds()
+                if delttime>20:
+                    temp2=np.array(self._celltemp_get(i))
+                    celltemp_rate=(max(temp2-temp1)*60)/delttime    #计算最大温升速率
+                    temp1=temp2 #更新初始温度
+                    time1=time2 #更新初始时间
+                    if celltemp_rate>self.param.CellTempRate:
+                        temprate_cnt=temprate_cnt+1
+                        if not 9 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                            if temprate_cnt>2:  #温升故障进入
+                                time=self.bmstime[i]
+                                code=9
+                                faultlv=3
+                                faultinfo='温升速率过快:{}℃/min'.format(celltemp_rate)
+                                faultadvice='技术介入诊断'
+                                self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                            else:
+                                pass
+                        else:   #ram当前故障中有该故障,则判断是否退出该故障
+                            if celltemp_rate<self.param.CellTempRate-1: #温升故障恢复
+                                time=self.bmstime[i]
+                                self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==9].index, 'end_time'] = time
+                    else:
+                        pass
+                else:
+                    pass
+            
+            else:
+                pass
+            
+            #电压诊断功能.................................................................................................
+            cellvolt0=self._cellvolt_get(i-1)
+            cellvolt1=self._cellvolt_get(i)
+            cellvoltmin0=min(cellvolt0)
+            cellvoltmax0=max(cellvolt0)
+            cellvoltmin1=min(cellvolt1)
+            cellvoltmax1=max(cellvolt1)
+            #电压断线诊断...................................................................................................
+            if (cellvoltmin0<2 and cellvoltmax0>4.5) or cellvoltmin0<0.1 or cellvoltmax0>5:
+                cellvoltvalid=0
+            else:
+                cellvoltvalid=1
+            
+            if cellvoltvalid==1:
+                #过压诊断.............................................................................................................
+                if not 12 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellvoltmax0>self.param.CellOvLv2 and cellvoltmax1>self.param.CellOvLv2:  #二级过压进入
+                        time=self.bmstime[i]
+                        code=12
+                        faultlv=3
+                        faultinfo='电芯{}过压二级'.format(cellvolt1.index(cellvoltmax1)+1)
+                        faultadvice='联系用户询问用车场景,技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if cellvoltmax0<self.param.CellOvLv1-0.05 and cellvoltmax1<self.param.CellOvLv1-0.05:   #二级过压故障恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==12].index, 'end_time'] = time
+                    else:
+                        pass
+              
+
+                #欠压诊断.................................................................................................................
+                if not 14 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellvoltmin0<self.param.CellUvLv2 and cellvoltmin1<self.param.CellUvLv2:  #二级欠压
+                        time=self.bmstime[i]
+                        code=14
+                        faultlv=3
+                        faultinfo='电芯{}欠压二级'.format(cellvolt1.index(cellvoltmin1)+1)
+                        faultadvice='联系用户询问用车场景,技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if cellvoltmin0>self.param.CellUvLv1+0.1 and cellvoltmin1>self.param.CellUvLv1+0.1:
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==14].index, 'end_time'] = time
+                    else:
+                        pass
+             
+                #电芯压差大.....................................................................................................................................................
+                if not 16 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if (cellvoltmax0-cellvoltmin0)>self.param.CellVoltDiffLv2 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv2:  #二级电芯压差
+                        time=self.bmstime[i]
+                        code=16
+                        faultlv=3
+                        faultinfo='电芯{}和{}压差大二级'.format(cellvolt1.index(cellvoltmax1)+1,cellvolt1.index(cellvoltmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if (cellvoltmax0-cellvoltmin0)<self.param.CellVoltDiffLv1-0.05 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv1-0.05: #二级欠压恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==16].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+                
+            #电池包诊断.....................................................................................................................................
+            if not 18 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.packvolt[i-1]>self.param.PackVoltOvLv2 and self.packvolt[i]>self.param.PackVoltOvLv2:   #电池包过压二级进入
+                    time=self.bmstime[i]
+                    code=18
+                    faultlv=3
+                    faultinfo='电池包过压二级'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packvolt[i-1]<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums and self.packvolt[i]<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums: #电池包过压二级恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==18].index, 'end_time'] = time
+                else:
+                    pass
+          
+            #电池包诊断.....................................................................................................................................
+            if not 20 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.packvolt[i-1]<self.param.PackVoltUvLv2 and self.packvolt[i]<self.param.PackVoltUvLv2:   #电池包二级欠压进入
+                    time=self.bmstime[i]
+                    code=20
+                    faultlv=3
+                    faultinfo='电池包欠压二级'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packvolt[i-1]>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums and self.packvolt[i]>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums:   #电池包二级欠压恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==20].index, 'end_time'] = time
+                else:
+                    pass
+            
+            #电流过流诊断.......................................................................................................................
+            step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+            if step<120 and self.packcrnt[i]>self.param.PackDisOc:
+                as_dis=as_dis+(self.packcrnt[i]-self.param.self.PackDisOc)*step    #ah累计
+            elif step<120 and self.packcrnt[i]<self.param.PackChgOc:
+                as_chg=as_chg+(self.param.PackDisOc-self.packcrnt[i])*step    #ah累计
+            else:
+                as_dis=0
+                as_chg=0
+            
+            if not 22 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if as_dis>100:
+                    time=self.bmstime[i]
+                    code=22
+                    faultlv=3
+                    faultinfo='电池包放电过流'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packcrnt[i-1]<self.param.PackDisOc-10 and self.packcrnt[i]<self.param.PackDisOc-10:
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==22].index, 'end_time'] = time
+                else:
+                    pass
+            
+            if not 21 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if as_chg>100:
+                    time=self.bmstime[i]
+                    code=21
+                    faultlv=3
+                    faultinfo='电池包充电过流'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packcrnt[i-1]>self.param.PackChgOc+10 and self.packcrnt[i]>self.param.PackChgOc+10:
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==22].index, 'end_time'] = time
+                else:
+                    pass
+
+            #SOC卡滞、跳变诊断................................................................................................
+            step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+            if step<120:
+                ah_accum=ah_accum-self.packcrnt[i]*step/3600    #ah累计
+            else:
+                pass
+            #SOC卡滞............................................................................................................
+            if abs(ah_accum)>self.param.Capacity*0.05:   
+                bmssoc_now=float(self.bms_soc[i])
+                if not 27 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if abs(bmssoc_now-bmssoc_st)<self.param.SocClamp:   #SOC卡滞故障进入
+                        time=self.bmstime[i]
+                        code=27
+                        faultlv=1
+                        faultinfo='电池SOC卡滞'
+                        faultadvice='技术介入诊断,检修电池BMS软件'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if abs(bmssoc_now-bmssoc_st)>self.param.SocClamp:   #SOC卡滞故障退出
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==27].index, 'end_time'] = time
+                    else:
+                        pass
+                bmssoc_st=bmssoc_now
+                ah_accum=0
+            else:
+                pass
+
+            #SOC跳变....................................................................................................................
+            if step<30: 
+                bmssoc_last=float(self.bms_soc[i-1])
+                bmssoc_now=float(self.bms_soc[i])
+                if not 28 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if abs(bmssoc_now-bmssoc_last)>self.param.SocJump:  #SOC跳变进入
+                        time=self.bmstime[i]
+                        code=28
+                        faultlv=1
+                        faultinfo='电池SOC跳变'
+                        faultadvice='技术介入诊断,检修电池BMS软件'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   
+                    if abs(bmssoc_now-bmssoc_st)<self.param.SocJump:    #SOC跳变故障退出
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==28].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+
+            #SOC过低故障报警............................................................................................................
+            if not 26 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.bms_soc[i-1]<self.param.SocLow and self.bms_soc[i]<self.param.SocLow:   #SOC过低故障进入
+                    time=self.bmstime[0]
+                    code=26
+                    faultlv=1
+                    faultinfo='电池包电量过低'
+                    faultadvice='联系用户,请立刻充电'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:   
+                if self.bms_soc[i-1]>self.param.SocLow and self.bms_soc[i]>self.param.SocLow:   #SOC过低故障退出
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==26].index, 'end_time'] = time
+                else:
+                    pass
+
+            #BMS故障报警........................................................................................................
+            if not 1 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.bmsfault1[i-1] is None or self.bmsfault1[i] is None:
+                    self.bmsfault1[i-1]=0
+                    self.bmsfault1[i]=0
+                if self.bmsfault1[i-1]>0 or self.bmsfault1[i]>0:   #BMS故障进入
+                    time=self.bmstime[0]
+                    code=1
+                    faultlv=2
+                    faultinfo='BMS故障报警:{}'.format(self.bmsfault1[i-1])
+                    faultadvice='技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.bmsfault1[i-1]==0 and self.bmsfault1[i]==0:   #BMS故恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==1].index, 'end_time'] = time
+        
+        
+        #SOC一致性故障报警..........................................................................................................
+        if not self.df_uniform.empty:
+            cellsoc_diff=self.df_uniform.loc[0,'cellsoc_diff']
+            if not 25 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if cellsoc_diff>self.param.SocDiff: #SOC一致性差故障进入
+                    time=self.bmstime[0]
+                    code=25
+                    faultlv=1
+                    faultinfo='电芯{}和{}SOC差过大:{}'.format(self.df_uniform.loc[0,'cellmin_num'],self.df_uniform.loc[0,'cellmax_num']),cellsoc_diff
+                    faultadvice='技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if cellsoc_diff<self.param.SocDiff: #SOC一致性差故障恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==25].index, 'end_time'] = time
+        else:
+            cellsoc_diff=3
+
+        #容量过低和一致性故障报警................................................................................................
+        if not self.df_soh.empty:
+            soh=self.df_soh.loc[0,'soh']
+            cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
+            cellsoh=np.array(cellsoh)
+            cellsoh_lowindex=np.argwhere(cellsoh<self.param.SohLow)
+            cellsoh_lowindex=cellsoh_lowindex+1
+            if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4: 
+                cellsoh_diff=max(cellsoh)-min(cellsoh)
+                if not 23 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if soh<self.param.SohLow:   #soh过低故障进入
+                        time=self.bmstime[0]
+                        code=23
+                        faultlv=1
+                        faultinfo='电池包容量过低:电芯{}'.format(cellsoh_lowindex)
+                        faultadvice='检修电池,更换容量过低的电芯或模组'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if soh>self.param.SohLow+2:   #soh过低故障恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==23].index, 'end_time'] = time
+                    else:
+                        pass
+
+                if not 24 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellsoh_diff>self.param.SohDiff:
+                        time=self.bmstime[0]
+                        code=24
+                        faultlv=1
+                        faultinfo='电池包容量一致性差:电芯{}'.format(cellsoh_lowindex)
+                        faultadvice='检修电池,更换容量过低的电芯或模组'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if cellsoh_diff<self.param.SohDiff-2:
+                        time=self.bmstime[i]
+                        self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==24].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+        else:
+            cellsoh_diff=5
+        
+        # #电池健康度评分.....................................................................................................
+        # health_state=soh*0.6+(100-cellsoh_diff)*0.2+(100-cellsoc_diff)*0.2
+        # if health_state>100:
+        #     health_state=100
+        # elif health_state<0:
+        #     health_state=0
+        # else:
+        #     pass
+        # health_state=eval(format(health_state,'.1f'))
+
+        #返回诊断结果...........................................................................................................
+        df_res=self.df_diag_ram
+        if not df_res.empty:
+            return df_res
+        else:
+            return pd.DataFrame()
+
+#............................................................内短路故障诊断.............................................................................
+class ShortDiag():
+    def __init__(self,sn,celltype,df_short):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_short=df_short
+
+    def shortdiag(self):
+        if len(self.df_short)>1:
+            df_res=self._short_diag()
+            return df_res
+        else:
+            return pd.DataFrame()
+
+    #内短路故障检测...................................................................................................................................
+    def _short_diag(self):
+        column_name=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice']
+        df_res=pd.DataFrame(columns=column_name)
+        time=datetime.datetime.now()
+        end_time=datetime.datetime.strftime('0000-00-00 00:00:00')
+        end_time=datetime.datetime.strptime(end_time,'%Y-%m-%d %H:%M:%S')
+
+        # if self.df_diag.empty:
+        #     health_state=100
+        # else:
+        #     health_state=self.df_diag.loc[0,'health_state']
+
+        for i in range(self.param.CellVoltNums):
+            #将字符串分割为多列
+            short_current=self.df_short['short_current']
+            short_current=short_current.str.replace("[", '')
+            short_current=short_current.str.replace("]", '')
+            self.df_short['cellshort'+str(i+1)]=short_current.map(lambda x:x.split(',')[i])
+            self.df_short['cellshort'+str(i+1)]=self.df_short['cellshort'+str(i+1)].map(lambda x:eval(x))
+
+            #漏电流故障判断
+            cellshort=np.array(self.df_short['cellshort'+str(i+1)])
+            shortlv3=np.sum(cellshort>self.param.LeakCurrentLv3)
+            shortlv2=np.sum(cellshort>self.param.LeakCurrentLv2)-shortlv3
+            shortlv1=np.sum(cellshort>self.param.LeakCurrentLv1)-shortlv2-shortlv3
+            shortlv=shortlv3*3 + shortlv2*2 + shortlv1
+
+            if not 31 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if shortlv>=5:
+                    time=self.bmstime[0]
+                    code=31
+                    faultlv=3
+                    faultinfo='电芯{}发生严重内短路'.format(i+1)
+                    faultadvice='禁止充放电,检修电池'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if shortlv<3:
+                    time=self.bmstime[i]
+                    self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['code']==31].index, 'end_time'] = time
+        
+        if not df_res.empty:
+            return df_res
+        else:
+            return pd.DataFrame()
+
+

+ 63 - 0
USER/LZX/01算法开发/04故障诊断/FeiShuData.py

@@ -0,0 +1,63 @@
+from numpy import empty
+import pandas as pd
+from pandas.core.frame import DataFrame
+
+import requests
+import json
+import datetime,time
+import numpy as np
+
+
+
+def getFeiShuDATA():
+    print('飞书数据获取中......')
+    Columns=["状态", "发生时间","代理商","电池编码","用户信息","业务分类A","业务分类B","操作","信息来源", "内容描述", "客服处理时间","客服处理结果","记录人","当前处理人","处理部门","跟进记录","问题类型A","问题类型B","事件处理完结时间","运维紧急程度","维修信息","返厂时间"]
+    # 获取token
+
+    app_id = 'cli_a1e503bb3d78100c'
+    app_secret = 'oZBbGSRYsf9sXy8t8e8kbhVLciekyvMt'
+    url = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal'
+
+    headers = {'Content-Type':"application/json; charset=utf-8"}
+    datas = json.dumps({'app_id':app_id, 'app_secret':app_secret})
+    response = requests.post(url, data=datas, headers=headers)
+    auth_token = json.loads(response.text)['tenant_access_token']
+
+    # 获取数据
+    app_token = 'bascnpaW50pJsCNd1AyIRFIc24b'
+    table_id = 'tblo3wnR2HFWI6rA'
+    sheet_id = 'vewZh94xDC'
+    url = 'https://open.feishu.cn/open-apis/bitable/v1/apps/{}/tables/{}/records'.format(app_token, table_id)
+    headers = {"Authorization":"Bearer {}".format(auth_token)}
+
+
+    df_file = pd.DataFrame(columns=Columns)
+    timesort=['发生时间','客服处理时间','事件处理完结时间','返厂时间']
+    count=0
+    GotPageToken=str()
+
+    while True:
+        # 筛选条件加载这里
+        datas = {'view_id':sheet_id, 'page_size':100, 'text_field_as_array':"true", 'page_token':GotPageToken,'field_names':'["状态", "发生时间","代理商","电池编码","用户信息","业务分类A","业务分类B","操作","信息来源", "内容描述", "客服处理时间","客服处理结果","记录人","当前处理人","处理部门","跟进记录","问题类型A","问题类型B","事件处理完结时间","运维紧急程度","维修信息","返厂时间"]'}
+        try:
+            response = requests.get(url, params=datas, headers=headers)
+            #print(response.text)
+            results = json.loads(response.text)['data']['items']
+            GotPageToken=json.loads(response.text)['data']['page_token']
+
+            for r in results:
+                df_file = df_file.append([r['fields']], ignore_index=True)
+        except:
+            break
+
+    for i in range(0,len(df_file)):
+        for t in range(0,len(timesort)):
+            if not df_file.loc[i,timesort[t]] is np.nan and not df_file.loc[i,timesort[t]] is None:
+                timeTemp= float(df_file.loc[i,timesort[t]])
+                timeTTmp=time.localtime(timeTemp/1000) 
+                df_file.loc[i,timesort[t]] = time.strftime('%Y-%m-%d %H:%M:%S',timeTTmp)
+    for col in Columns:
+        df_file[col]=df_file[col].map(lambda x:str(x).lstrip('[{\'text\': ').rstrip('\', \'type\': \'text\'}]').replace('\\n\', \'type\': \'text\'}, {\'text\': \'',' '))
+    df_file.to_excel('df_file.xlsx')
+    print('飞书数据获取完成')
+    return df_file

+ 66 - 0
USER/LZX/01算法开发/04故障诊断/GetFeiShuData.py

@@ -0,0 +1,66 @@
+from numpy import empty
+import pandas as pd
+from pandas.core.frame import DataFrame
+
+import requests
+import json
+import datetime,time
+import numpy as np
+
+
+
+def getFeiShuDATA():
+    Columns=["状态", "发生时间","代理商","电池编码","用户信息","业务分类A","业务分类B","操作","信息来源", "内容描述", "客服处理时间","客服处理结果","记录人","当前处理人","处理部门","跟进记录","问题类型A","问题类型B","事件处理完结时间","维修信息","返厂时间"]
+    # 获取token
+
+    app_id = 'cli_a1e503bb3d78100c'
+    app_secret = 'oZBbGSRYsf9sXy8t8e8kbhVLciekyvMt'
+    url = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal'
+
+    headers = {'Content-Type':"application/json; charset=utf-8"}
+    datas = json.dumps({'app_id':app_id, 'app_secret':app_secret})
+    response = requests.post(url, data=datas, headers=headers)
+    auth_token = json.loads(response.text)['tenant_access_token']
+
+    # 获取数据
+    app_token = 'bascnpaW50pJsCNd1AyIRFIc24b'
+    table_id = 'tblo3wnR2HFWI6rA'
+    sheet_id = 'vewZh94xDC'
+    url = 'https://open.feishu.cn/open-apis/bitable/v1/apps/{}/tables/{}/records'.format(app_token, table_id)
+    headers = {"Authorization":"Bearer {}".format(auth_token)}
+
+
+    df_file = pd.DataFrame(columns=Columns)
+    timesort=['发生时间','客服处理时间','事件处理完结时间','返厂时间']
+    count=0
+    GotPageToken=str()
+
+    while True:
+        # 筛选条件加载这里
+        datas = {'view_id':sheet_id, 'page_size':100, 'text_field_as_array':"true", 'page_token':GotPageToken,'field_names':'["状态", "发生时间","代理商","电池编码","用户信息","业务分类A","业务分类B","操作","信息来源", "内容描述", "客服处理时间","客服处理结果","记录人","当前处理人","处理部门","跟进记录","问题类型A","问题类型B","事件处理完结时间","维修信息","返厂时间"]'}
+        try:
+            response = requests.get(url, params=datas, headers=headers)
+            results = json.loads(response.text)['data']['items']
+            GotPageToken=json.loads(response.text)['data']['page_token']
+
+            for r in results:
+                df_file = df_file.append([r['fields']], ignore_index=True)
+        except:
+            break
+
+    for i in range(0,len(df_file)):
+        for t in range(0,len(timesort)):
+            if not df_file.loc[i,timesort[t]] is np.nan:
+                # temp_para = df_file.loc[i,timesort[t]
+                # timeTemp= float(temp_para/1000)
+                # temp_para = df_file.loc[i,timesort[t]
+                # print(i)
+                # print(t)
+                # print(df_file.loc[i,timesort[t]])
+                timeTemp= float(df_file.loc[i,timesort[t]]/1000)
+                timeTTmp=time.localtime(timeTemp) 
+                df_file.loc[i,timesort[t]] = time.strftime('%Y-%m-%d %H:%M:%S',timeTTmp)
+    for col in Columns:
+        df_file[col]=df_file[col].map(lambda x:str(x).lstrip('[{\'text\': ').rstrip('\', \'type\': \'text\'}]').replace('\\n\', \'type\': \'text\'}, {\'text\': \'',' '))
+    df_file.to_excel('df_file.xlsx')
+    return df_file

+ 157 - 0
USER/LZX/01算法开发/04故障诊断/QX_BatteryParam.py

@@ -0,0 +1,157 @@
+class BatteryInfo():
+    def __init__(self,celltype):
+        self.CellMaxUSBTemp=55
+        self.AllowChgMinTemp=0
+        self.AllowDsChgTemp=-5
+        self.AvgVolGap=1
+        self.AvgCellTempGap=10
+        self.AvgOtherTempGap=40
+        self.PackOTlmt=65
+        self.PackUTlmt=-20
+        self.OtherOTlmt=91
+        self.OtherUTlmt=-20        
+        self.FaultCount=100
+
+
+
+        if celltype==1: #6040
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=17
+            self.CellTempNums=3
+            self.OtherTempNums=5
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+            self.BLVol = 3
+            self.CellOVlmt=5#原为5
+            self.CellUVlmt=2#原为2
+            self.CantChrgVol=3
+          
+        elif celltype==2: #4840
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=14
+            self.CellTempNums=4
+            self.OtherTempNums=5            
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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,   105]
+            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, 4.263]
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3        
+
+        elif  celltype==3:   #力信50ah三元电芯
+            self.Capacity = 51
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.OtherTempNums=1
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.357, 	3.455, 	3.493, 	3.540, 	3.577, 	3.605, 	3.622, 	3.638, 	3.655, 	3.677, 	3.707, 	3.757, 	3.815, 	3.866, 	3.920, 	3.976, 	4.036, 	4.099, 	4.166, 	4.237, 	4.325, 4.415]
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3
+
+        elif celltype==4:   #CATL 50ah三元电芯
+            self.Capacity = 50
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=2
+            self.OtherTempNums=0
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=-1
+            self.BalCurrent=0.015
+            self.LookTab_SOC = [0,	    5,	    10,	    15,	    20,	    25,	    30,	    35,	    40,	    45,	    50,	    55,	    60,	    65,	    70,	    75,	    80,	    85,	    90,	    95,	    100,   105]
+            self.LookTab_OCV = [3.152, 	3.397, 	3.438, 	3.481, 	3.523, 	3.560, 	3.586, 	3.604, 	3.620, 	3.638, 	3.661, 	3.693, 	3.748, 	3.803, 	3.853, 	3.903, 	3.953, 	4.006, 	4.063, 	4.121, 	4.183, 4.253]
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3
+          
+
+        elif 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.OtherTempNums=5 
+            self.FullChrgSoc=98
+            self.PeakSoc=59
+            self.PeakVoltLowLmt=3.35
+            self.PeakVoltUpLmt=3.4
+            self.PeakCellVolt=[3.362,3.363,3.365,3.366,3.367]
+            self.PackCrntDec=1
+            self.BalCurrent=0.015
+            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]
+            self.BLVol = 3
+            self.CellOVlmt=4
+            self.CellUVlmt=2
+            self.CantChrgVol=2.6
+ 
+        elif celltype==100:
+            self.Capacity = 14
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=10
+            self.CellTempNums=1
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.PackCrntDec=1
+            self.LookTab_SOC = [0,	1,	2,	3,	4,	5,	6,	7,	8,	9,	10,	11,	12,	13,	14,	15,	16,	17,	18,	19,	20,	21,	22,	23,	24,	25,	26,	27,	28,	29,	30,	31,	32,	33,	34,	35,	36,	37,	38,	39,	40,	41,	42,	43,	44,	45,	46,	47,	48,	49,	50,	51,	52,	53,	54,	55,	56,	57,	58,	59,	60,	61,	62,	63,	64,	65,	66,	67,	68,	69,	70,	71,	72,	73,	74,	75,	76,	77,	78,	79,	80,	81,	82,	83,	84,	85,	86,	87,	88,	89,	90,	91,	92,	93,	94,	95,	96,	97,	98,	100]
+            self.LookTab_OCV = [2.841,	3.064,	3.181,	3.261,	3.322,	3.372,	3.413,	3.445,	3.464,	3.475,	3.482,	3.489,	3.495,	3.502,	3.51,	3.519,	3.529,	3.537,	3.545,	3.553,	3.562,	3.57,	3.578,	3.586,	3.594,	3.602,	3.611,	3.621,	3.631,	3.642,	3.655,	3.668,	3.681,	3.694,	3.708,	3.722,	3.735,	3.748,	3.761,	3.771,	3.782,	3.791,	3.799,	3.807,	3.81,	3.814,	3.82,	3.826,	3.832,	3.836,	3.841,	3.847,	3.852,	3.856,	3.861,	3.866,	3.871,	3.875,	3.88,	3.885,	3.891,	3.896,	3.903,	3.91,	3.917,	3.926,	3.936,	3.944,	3.953,	3.961,	3.969,	3.976,	3.983,	3.991,	3.997,	4.004,	4.01,	4.016,	4.022,	4.026,	4.03,	4.034,	4.037,	4.041,	4.044,	4.048,	4.052,	4.056,	4.06,	4.064,	4.069,	4.075,	4.081,	4.088,	4.097,	4.106,	4.116,	4.129,	4.145,	4.164]
+
+            self.CellTempHighLv1=45
+            self.CellTempHighLv2=50
+            self.CellTempLowLv1=-20
+            self.CellTempLowLv2=-25
+            self.CellTempDiffLv1=10
+            self.CellTempDiffLv2=15
+            self.CellTempRate=0.99
+
+            self.CellOvLv1=4.3
+            self.CellOvLv2=4.35
+            self.CellUvLv1=2.8
+            self.CellUvLv2=2.5
+            self.CellVoltDiffLv1=0.3
+            self.CellVoltDiffLv2=0.5
+            self.PackVoltOvLv1=self.CellOvLv1*self.CellVoltNums
+            self.PackVoltOvLv2=self.CellOvLv2*self.CellVoltNums
+            self.PackVoltUvLv1=self.CellUvLv1*self.CellVoltNums
+            self.PackVoltUvLv2=self.CellUvLv2*self.CellVoltNums
+
+            self.PackChgOc=1.5*self.Capacity
+            self.PackDisChgOc=3*self.Capacity
+
+            self.SocJump=3
+            self.SocClamp=3
+            self.BLVol = 3
+            self.CellOVlmt=5
+            self.CellUVlmt=2
+            self.CantChrgVol=3
+        else:
+            print('未找到对应电池编号!!!')
+            # sys.exit()

+ 84 - 0
USER/LZX/01算法开发/04故障诊断/SC_SamplingSafty.py

@@ -0,0 +1,84 @@
+import sys
+import numpy as np
+import pandas as pd
+import string
+import os
+from pandas import Series
+from matplotlib import pyplot as plt
+from pandas.core.frame import DataFrame
+from pandas.core.indexes.base import Index
+from pymysql import NULL
+from LIB.BACKEND import DBManager
+import datetime
+import time
+import string
+import re
+
+
+
+class SamplingSafty:
+    def __init__(self):
+        pass
+    def main(sn,param,bms_info,df_Diag_Ram_in):
+        df_Diag_Ram_Update_inside=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        df_Diag_Ram_Update_inside=df_Diag_Ram_Update_inside.append(df_Diag_Ram_in)
+        global QuitErrCount 
+        VolStarkCount=[0 for i in range(param.CellVoltNums)]
+        VolCount=0
+        QuitErrCount=[0 for i in range(param.FaultCount)]
+        df_Diag_Ram=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        st_tp=[]
+        #--------------该电池的所有当前故障-------------
+
+        VoltageNum=['单体电压'+str(i) for i in range(1,param.CellVoltNums+1)]#单体电压替换cellvolt_
+        CellVoltage=bms_info[VoltageNum]
+        CellMaxVoltage=CellVoltage.max(axis=1)
+        CellMinVoltage=CellVoltage.min(axis=1)
+        InVMaxBatNo=CellVoltage[CellVoltage>=param.CellOVlmt].dropna(axis=0,how='all',inplace=False)
+        InVMinBatNo=CellVoltage[CellVoltage<=param.CellUVlmt].dropna(axis=0,how='all',inplace=False)
+        #date替换为'时间戳'
+        if len(InVMaxBatNo):
+            indexValue=InVMaxBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'单体电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'单体电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'建议返厂维修']                         
+        if len(InVMinBatNo):
+            indexValue=InVMinBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'建议返厂维修']           
+        MedianVol=CellVoltage.median(axis=1).tolist()
+        MediaVolGap=abs(CellVoltage.sub(MedianVol,axis=0))
+        OutlineVol=MediaVolGap[MediaVolGap>=param.AvgVolGap][CellMaxVoltage<param.CellOVlmt][CellMinVoltage>param.CellUVlmt][abs(bms_info['总电流[A]'])<1].dropna(axis=0,how='all',inplace=False)
+        #OutlineVol=OutlineVol[CellMaxVoltage<param.CellOVlmt][CellMinVoltage>param.CellUVlmt].dropna(axis=0,how='all',inplace=False)
+        
+        
+        if len(OutlineVol):
+            indexValue=OutlineVol.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,sn,10,3,'电池电压发生偏移或发生断线','建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,10,3,'电池电压发生偏移或发生断线','建议返厂维修'] 
+        CellTemp=bms_info['单体温度1']
+        InVMaxTempBatNo=CellTemp[CellTemp>=param.PackOTlmt].dropna(axis=0,how='all',inplace=False)
+        InVMinTempBatNo=CellTemp[CellTemp<=param.PackUTlmt].dropna(axis=0,how='all',inplace=False)
+        if len(InVMaxTempBatNo):
+            indexValue=InVMaxTempBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度大于{:.0f}摄氏度,采样无效'.format(param.PackOTlmt),'请立即确认状态']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度大于{:.0f}摄氏度,采样无效'.format(param.PackOTlmt),'请立即确认状态'] 
+        if len(InVMinTempBatNo):
+            indexValue=InVMinTempBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度小于{:.0f}摄氏度,采样无效'.format(param.PackUTlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度小于{:.0f}摄氏度,采样无效'.format(param.PackUTlmt),'建议返厂维修'] 
+        return df_Diag_Ram

+ 491 - 0
USER/LZX/01算法开发/04故障诊断/diagfault/CBMSBatDiag.py

@@ -0,0 +1,491 @@
+import pandas as pd
+import numpy as np
+import datetime
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class BatDiag:
+    def __init__(self,sn,celltype,df_bms,df_soh,df_uniform,df_diag_Ram):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)
+        self.df_bms=df_bms
+        self.df_soh=df_soh
+        self.df_uniform=df_uniform
+        self.df_diag_ram=df_diag_Ram
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.bmsfault1=self.df_bms['故障代码']
+        # self.bmsfault2=self.df_bms['alarm2'].tolist()
+        # self.bmsfault3=self.df_bms['alarm3'].tolist()
+        # self.bmsfault4=self.df_bms['fault'].tolist()
+
+        self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+    
+    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):
+
+        bmssoc_st=float(self.bms_soc[0])    #SOC卡滞初始参数
+        ah_accum=0  #SOC卡滞初始参数
+        as_chg=0    #过流诊断初始参数
+        as_dis=0    #过流诊断初始参数
+        time1=self.bmstime[0]   #温升速率初始参数
+        temp1=np.array(self._celltemp_get(0))   #温升速率初始参数
+        temprate_cnt=0
+        
+        end_time='0000-00-00 00:00:00'
+            
+        for i in range(1,len(self.df_bms)):
+            
+            #温度诊断功能.............................................................................................................
+            celltemp0=self._celltemp_get(i-1)
+            celltemp1=self._celltemp_get(i)
+            celltempmin0=min(celltemp0)
+            celltempmin1=min(celltemp1)
+            celltempmax0=max(celltemp0)
+            celltempmax1=max(celltemp1)
+            #温度有效性判断..........................................................................
+            if celltempmax0>self.param.CellTempUpLmt or celltempmin0<self.param.CellTempLwLmt:
+                celltempvalid=0
+            else:  
+                celltempvalid=1
+           
+
+            if celltempvalid==1:
+                #过温判断.............................................................................................................
+                if not 4 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if celltempmax0>self.param.CellTempHighLv2 and celltempmax1>self.param.CellTempHighLv2:    #二级高温进入
+                        time=self.bmstime[i]
+                        code=4
+                        faultlv=3
+                        faultinfo='温度{}高温二级'.format(celltemp1.index(celltempmax1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if celltempmax0<self.param.CellTempHighLv1-5 and celltempmax1<self.param.CellTempHighLv1-5:    #二级高温恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==4].index, 'end_time'] = time
+                    else:
+                        pass
+            
+                #欠温判断.................................................................................................................
+                if not 6 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if celltempmin0<self.param.CellTempLowLv2 and celltempmin1<self.param.CellTempLowLv2:  #二级低温进入
+                        time=self.bmstime[i]
+                        code=6
+                        faultlv=3
+                        faultinfo='温度{}低温二级'.format(celltemp1.index(celltempmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if celltempmax0>self.param.CellTempLowLv1+2 and celltempmax1>self.param.CellTempLowLv1+2:    #二级高温恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==6].index, 'end_time'] = time
+                    else:
+                        pass
+              
+                #温差判断.............................................................................................................................
+                if not 8 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if (celltempmax0-celltempmin0)>self.param.CellTempDiffLv2 and (celltempmax1-celltempmin1)>self.param.CellTempDiffLv2:  #二级温差进入
+                        time=self.bmstime[i]
+                        code=8
+                        faultlv=3
+                        faultinfo='温度{}和{}温差大二级'.format(celltemp1.index(celltempmax1)+1,celltemp1.index(celltempmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if (celltempmax0-celltempmin0)<self.param.CellTempDiffLv1-2 and (celltempmax1-celltempmax0)>self.param.CellTempDiffLv1-2:  #二级温差恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==8].index, 'end_time'] = time
+                    else:
+                        pass
+
+                #温升判断
+                time2=self.bmstime[i]
+                delttime=(time2-time1).total_seconds()
+                if delttime>20:
+                    temp2=np.array(self._celltemp_get(i))
+                    celltemp_rate=(max(temp2-temp1)*60)/delttime    #计算最大温升速率
+                    temp1=temp2 #更新初始温度
+                    time1=time2 #更新初始时间
+                    if celltemp_rate>self.param.CellTempRate:
+                        temprate_cnt=temprate_cnt+1
+                        if not 9 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                            if temprate_cnt>2:  #温升故障进入
+                                time=self.bmstime[i]
+                                code=9
+                                faultlv=3
+                                faultinfo='温升速率过快:{}℃/min'.format(celltemp_rate)
+                                faultadvice='技术介入诊断'
+                                self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                            else:
+                                pass
+                        else:   #ram当前故障中有该故障,则判断是否退出该故障
+                            if celltemp_rate<self.param.CellTempRate-1: #温升故障恢复
+                                time=self.bmstime[i]
+                                self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==9].index, 'end_time'] = time
+                    else:
+                        pass
+                else:
+                    pass
+            
+            else:
+                pass
+            
+            #电压诊断功能.................................................................................................
+            cellvolt0=self._cellvolt_get(i-1)
+            cellvolt1=self._cellvolt_get(i)
+            cellvoltmin0=min(cellvolt0)
+            cellvoltmax0=max(cellvolt0)
+            cellvoltmin1=min(cellvolt1)
+            cellvoltmax1=max(cellvolt1)
+            #电压断线诊断...................................................................................................
+            if (cellvoltmin0<2 and cellvoltmax0>4.5) or cellvoltmin0<0.1 or cellvoltmax0>5:
+                cellvoltvalid=0
+            else:
+                cellvoltvalid=1
+            
+            if cellvoltvalid==1:
+                #过压诊断.............................................................................................................
+                if not 12 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellvoltmax0>self.param.CellOvLv2 and cellvoltmax1>self.param.CellOvLv2:  #二级过压进入
+                        time=self.bmstime[i]
+                        code=12
+                        faultlv=4
+                        faultinfo='电芯{}过压二级'.format(cellvolt1.index(cellvoltmax1)+1)
+                        faultadvice='联系用户询问用车场景,技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   #ram当前故障中有该故障,则判断是否退出该故障
+                    if cellvoltmax0<self.param.CellOvLv1-0.05 and cellvoltmax1<self.param.CellOvLv1-0.05:   #二级过压故障恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==12].index, 'end_time'] = time
+                    else:
+                        pass
+              
+
+                #欠压诊断.................................................................................................................
+                if not 14 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellvoltmin0<self.param.CellUvLv2 and cellvoltmin1<self.param.CellUvLv2:  #二级欠压
+                        time=self.bmstime[i]
+                        code=14
+                        faultlv=3
+                        faultinfo='电芯{}欠压二级'.format(cellvolt1.index(cellvoltmin1)+1)
+                        faultadvice='联系用户询问用车场景,技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if cellvoltmin0>self.param.CellUvLv1+0.1 and cellvoltmin1>self.param.CellUvLv1+0.1:
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==14].index, 'end_time'] = time
+                    else:
+                        pass
+             
+                #电芯压差大.....................................................................................................................................................
+                if not 16 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if (cellvoltmax0-cellvoltmin0)>self.param.CellVoltDiffLv2 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv2:  #二级电芯压差
+                        time=self.bmstime[i]
+                        code=16
+                        faultlv=3
+                        faultinfo='电芯{}和{}压差大二级'.format(cellvolt1.index(cellvoltmax1)+1,cellvolt1.index(cellvoltmin1)+1)
+                        faultadvice='技术介入诊断'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if (cellvoltmax0-cellvoltmin0)<self.param.CellVoltDiffLv1-0.05 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv1-0.05: #二级欠压恢复
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==16].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+                
+            #电池包诊断.....................................................................................................................................
+            if not 18 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.packvolt[i-1]>self.param.PackVoltOvLv2 and self.packvolt[i]>self.param.PackVoltOvLv2:   #电池包过压二级进入
+                    time=self.bmstime[i]
+                    code=18
+                    faultlv=4
+                    faultinfo='电池包过压二级'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packvolt[i-1]<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums and self.packvolt[i]<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums: #电池包过压二级恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==18].index, 'end_time'] = time
+                else:
+                    pass
+          
+            #电池包诊断.....................................................................................................................................
+            if not 20 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.packvolt[i-1]<self.param.PackVoltUvLv2 and self.packvolt[i]<self.param.PackVoltUvLv2:   #电池包二级欠压进入
+                    time=self.bmstime[i]
+                    code=20
+                    faultlv=3
+                    faultinfo='电池包欠压二级'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packvolt[i-1]>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums and self.packvolt[i]>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums:   #电池包二级欠压恢复
+                    time=self.bmstime[i]
+                    self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==20].index, 'end_time'] = time
+                else:
+                    pass
+            
+            #电流过流诊断.......................................................................................................................
+            step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+            if step<120 and self.packcrnt[i]>self.param.PackDisOc:
+                as_dis=as_dis+(self.packcrnt[i]-self.param.self.PackDisOc)*step    #ah累计
+            elif step<120 and self.packcrnt[i]<self.param.PackChgOc:
+                as_chg=as_chg+(self.param.PackDisOc-self.packcrnt[i])*step    #ah累计
+            else:
+                as_dis=0
+                as_chg=0
+            
+            if not 22 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if as_dis>100:
+                    time=self.bmstime[i]
+                    code=22
+                    faultlv=3
+                    faultinfo='电池包放电过流'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packcrnt[i-1]<self.param.PackDisOc-10 and self.packcrnt[i]<self.param.PackDisOc-10:
+                    time=self.bmstime[i]
+                    self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==22].index, 'end_time'] = time
+                else:
+                    pass
+            
+            if not 21 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if as_chg>100:
+                    time=self.bmstime[i]
+                    code=21
+                    faultlv=3
+                    faultinfo='电池包充电过流'
+                    faultadvice='联系用户询问用车场景,技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if self.packcrnt[i-1]>self.param.PackChgOc+10 and self.packcrnt[i]>self.param.PackChgOc+10:
+                    time=self.bmstime[i]
+                    self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==22].index, 'end_time'] = time
+                else:
+                    pass
+
+            #SOC卡滞、跳变诊断................................................................................................
+            step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+            if step<120:
+                ah_accum=ah_accum-self.packcrnt[i]*step/3600    #ah累计
+            else:
+                pass
+            #SOC卡滞............................................................................................................
+            if abs(ah_accum)>self.param.Capacity*0.05:   
+                bmssoc_now=float(self.bms_soc[i])
+                if not 27 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if abs(bmssoc_now-bmssoc_st)<self.param.SocClamp:   #SOC卡滞故障进入
+                        time=self.bmstime[i]
+                        code=27
+                        faultlv=1
+                        faultinfo='电池SOC卡滞'
+                        faultadvice='技术介入诊断,检修电池BMS软件'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if abs(bmssoc_now-bmssoc_st)>self.param.SocClamp:   #SOC卡滞故障退出
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==27].index, 'end_time'] = time
+                    else:
+                        pass
+                bmssoc_st=bmssoc_now
+                ah_accum=0
+            else:
+                pass
+
+            #SOC跳变....................................................................................................................
+            if step<30: 
+                bmssoc_last=float(self.bms_soc[i-1])
+                bmssoc_now=float(self.bms_soc[i])
+                if not 28 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if abs(bmssoc_now-bmssoc_last)>self.param.SocJump:  #SOC跳变进入
+                        time=self.bmstime[i]
+                        code=28
+                        faultlv=1
+                        faultinfo='电池SOC跳变'
+                        faultadvice='技术介入诊断,检修电池BMS软件'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:   
+                    if abs(bmssoc_now-bmssoc_st)<self.param.SocJump:    #SOC跳变故障退出
+                        time=self.bmstime[i]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==28].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+
+            #SOC过低故障报警............................................................................................................
+            if not 26 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if self.bms_soc[i-1]<self.param.SocLow and self.bms_soc[i]<self.param.SocLow:   #SOC过低故障进入
+                    time=self.bmstime[i]
+                    code=26
+                    faultlv=1
+                    faultinfo='电池包电量过低'
+                    faultadvice='联系用户,请立刻充电'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:   
+                if self.bms_soc[i-1]>self.param.SocLow and self.bms_soc[i]>self.param.SocLow:   #SOC过低故障退出
+                    time=self.bmstime[i]
+                    self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==26].index, 'end_time'] = time
+                else:
+                    pass
+
+            # #BMS故障报警........................................................................................................
+            # if not 1 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+            #     if self.bmsfault1[i-1] is None or self.bmsfault1[i] is None:
+            #         self.bmsfault1[i-1]=0
+            #         self.bmsfault1[i]=0
+            #     if self.bmsfault1[i-1]>0 or self.bmsfault1[i]>0:   #BMS故障进入
+            #         time=self.bmstime[0]
+            #         code=1
+            #         faultlv=2
+            #         faultinfo='BMS故障报警:{}'.format(self.bmsfault1[i-1])
+            #         faultadvice='技术介入诊断'
+            #         self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+            #     else:
+            #         pass
+            # else:
+            #     if self.bmsfault1[i-1]==0 and self.bmsfault1[i]==0:   #BMS故恢复
+            #         time=self.bmstime[i]
+            #         self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==1].index, 'end_time'] = time
+        
+        
+        #SOC一致性故障报警..........................................................................................................
+        if not self.df_uniform.empty:
+            cellsoc_diff=self.df_uniform.loc[0,'cellsoc_diff']
+            if not 25 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                if cellsoc_diff>self.param.SocDiff: #SOC一致性差故障进入
+                    time=self.bmstime[0]
+                    code=25
+                    faultlv=1
+                    faultinfo='电芯{}和{}SOC差过大:{}'.format(self.df_uniform.loc[0,'cellmin_num'],self.df_uniform.loc[0,'cellmax_num'],cellsoc_diff)
+                    faultadvice='技术介入诊断'
+                    self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                else:
+                    pass
+            else:
+                if cellsoc_diff<self.param.SocDiff: #SOC一致性差故障恢复
+                    time=self.bmstime[0]
+                    self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==25].index, 'end_time'] = time
+        else:
+            cellsoc_diff=3
+
+        #容量过低和一致性故障报警................................................................................................
+        if not self.df_soh.empty:
+            soh=self.df_soh.loc[0,'soh']
+            cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
+            cellsoh=np.array(cellsoh)
+            cellsoh_lowindex=np.argwhere(cellsoh<self.param.SohLow)
+            cellsoh_lowindex=cellsoh_lowindex+1
+            if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4: 
+                cellsoh_diff=max(cellsoh)-min(cellsoh)
+                if not 23 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if soh<self.param.SohLow:   #soh过低故障进入
+                        time=self.bmstime[0]
+                        code=23
+                        faultlv=1
+                        faultinfo='电池包容量过低:电芯{}'.format(cellsoh_lowindex)
+                        faultadvice='检修电池,更换容量过低的电芯或模组'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if soh>self.param.SohLow+2:   #soh过低故障恢复
+                        time=self.bmstime[0]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==23].index, 'end_time'] = time
+                    else:
+                        pass
+
+                if not 24 in list(self.df_diag_ram['code']):  #当前故障中没有该故障,则判断是否发生该故障
+                    if cellsoh_diff>self.param.SohDiff:
+                        time=self.bmstime[0]
+                        code=24
+                        faultlv=1
+                        faultinfo='电池包容量一致性差:电芯{}'.format(cellsoh_lowindex)
+                        faultadvice='检修电池,更换容量过低的电芯或模组'
+                        self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
+                    else:
+                        pass
+                else:
+                    if cellsoh_diff<self.param.SohDiff-2:
+                        time=self.bmstime[0]
+                        self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']==24].index, 'end_time'] = time
+                    else:
+                        pass
+            else:
+                pass
+        else:
+            cellsoh_diff=5
+        
+        # #电池健康度评分.....................................................................................................
+        # health_state=soh*0.6+(100-cellsoh_diff)*0.2+(100-cellsoc_diff)*0.2
+        # if health_state>100:
+        #     health_state=100
+        # elif health_state<0:
+        #     health_state=0
+        # else:
+        #     pass
+        # health_state=eval(format(health_state,'.1f'))
+
+        #返回诊断结果...........................................................................................................
+        df_res=self.df_diag_ram
+        if not df_res.empty:
+            return df_res
+        else:
+            return pd.DataFrame()

+ 84 - 0
USER/LZX/01算法开发/04故障诊断/diagfault/SC_SamplingSafty.py

@@ -0,0 +1,84 @@
+import sys
+import numpy as np
+import pandas as pd
+import string
+import os
+from pandas import Series
+from matplotlib import pyplot as plt
+from pandas.core.frame import DataFrame
+from pandas.core.indexes.base import Index
+from pymysql import NULL
+from LIB.BACKEND import DBManager
+import datetime
+import time
+import string
+import re
+
+
+
+class SamplingSafty:
+    def __init__(self):
+        pass
+    def main(sn,param,bms_info,df_Diag_Ram_in):
+        df_Diag_Ram_Update_inside=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        df_Diag_Ram_Update_inside=df_Diag_Ram_Update_inside.append(df_Diag_Ram_in)
+        global QuitErrCount 
+        VolStarkCount=[0 for i in range(param.CellVoltNums)]
+        VolCount=0
+        QuitErrCount=[0 for i in range(param.FaultCount)]
+        df_Diag_Ram=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        st_tp=[]
+        #--------------该电池的所有当前故障-------------
+
+        VoltageNum=['单体电压'+str(i) for i in range(1,param.CellVoltNums+1)]#单体电压替换cellvolt_
+        CellVoltage=bms_info[VoltageNum]
+        CellMaxVoltage=CellVoltage.max(axis=1)
+        CellMinVoltage=CellVoltage.min(axis=1)
+        InVMaxBatNo=CellVoltage[CellVoltage>=param.CellOVlmt].dropna(axis=0,how='all',inplace=False)
+        InVMinBatNo=CellVoltage[CellVoltage<=param.CellUVlmt].dropna(axis=0,how='all',inplace=False)
+        #date替换为'时间戳'
+        if len(InVMaxBatNo):
+            indexValue=InVMaxBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'单体电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'单体电压大于{:.2f}V,采样无效'.format(param.CellOVlmt),'建议返厂维修']                         
+        if len(InVMinBatNo):
+            indexValue=InVMinBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电压小于{:.2f}V,采样无效'.format(param.CellUVlmt),'建议返厂维修']           
+        MedianVol=CellVoltage.median(axis=1).tolist()
+        MediaVolGap=abs(CellVoltage.sub(MedianVol,axis=0))
+        OutlineVol=MediaVolGap[MediaVolGap>=param.AvgVolGap][CellMaxVoltage<param.CellOVlmt][CellMinVoltage>param.CellUVlmt][abs(bms_info['总电流[A]'])<1].dropna(axis=0,how='all',inplace=False)
+        #OutlineVol=OutlineVol[CellMaxVoltage<param.CellOVlmt][CellMinVoltage>param.CellUVlmt].dropna(axis=0,how='all',inplace=False)
+        
+        
+        if len(OutlineVol):
+            indexValue=OutlineVol.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,sn,10,3,'电池电压发生偏移或发生断线','建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,10,3,'电池电压发生偏移或发生断线','建议返厂维修'] 
+        CellTemp=bms_info['单体温度1']
+        InVMaxTempBatNo=CellTemp[CellTemp>=param.PackOTlmt].dropna(axis=0,how='all',inplace=False)
+        InVMinTempBatNo=CellTemp[CellTemp<=param.PackUTlmt].dropna(axis=0,how='all',inplace=False)
+        if len(InVMaxTempBatNo):
+            indexValue=InVMaxTempBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度大于{:.0f}摄氏度,采样无效'.format(param.PackOTlmt),'请立即确认状态']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度大于{:.0f}摄氏度,采样无效'.format(param.PackOTlmt),'请立即确认状态'] 
+        if len(InVMinTempBatNo):
+            indexValue=InVMinTempBatNo.index.values
+            df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[0],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度小于{:.0f}摄氏度,采样无效'.format(param.PackUTlmt),'建议返厂维修']
+            for i in range(1,len(indexValue)):
+                if indexValue[i]- indexValue[i-1]>10:
+                    df_Diag_Ram.loc[len(df_Diag_Ram)-1,'end_time']=bms_info.loc[indexValue[i-1],'时间戳']
+                    df_Diag_Ram.loc[len(df_Diag_Ram)]=[bms_info.loc[indexValue[i],'时间戳'],'0000-00-00 00:00:00',sn,50,3,'电池温度小于{:.0f}摄氏度,采样无效'.format(param.PackUTlmt),'建议返厂维修'] 
+        return df_Diag_Ram

+ 164 - 0
USER/LZX/01算法开发/04故障诊断/diagfault/main.py

@@ -0,0 +1,164 @@
+import CBMSBatDiag
+from SC_SamplingSafty import SamplingSafty
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from sqlalchemy import create_engine
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from pandas.core.frame import DataFrame
+import datacompy
+from LIB.MIDDLE.SaftyCenter.Common import FeiShuData
+from LIB.MIDDLE.SaftyCenter.Common import QX_BatteryParam
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global df_Diag_Ram
+  
+    start=time.time()
+    end_time=datetime.datetime.now()
+    start_time=end_time-datetime.timedelta(seconds=300)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+    df_read_Yunw = FeiShuData.getFeiShuDATA()#运维表格数据
+    df_read_Yunw.rename(columns={'电池编码':'product_id'},inplace=True)
+    df_read_Yunw.rename(columns={'内容描述':'info'},inplace=True)
+    df_read_Yunw.rename(columns={'发生时间':'start_time'},inplace=True)
+    df_read_Yunw.rename(columns={'维修信息':'advice'},inplace=True)
+    for sn in SNnums:
+        print(sn)
+        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()
+        param=QX_BatteryParam.BatteryInfo(celltype) 
+        print(sn)    
+        #读取原始数据库数据........................................................................................................................................................
+        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']
+
+        #读取结果数据库数据........................................................................................................................................................
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+        mode=1
+        tablename1='cellstateestimation_soh'
+        tablename2='cellstateestimation_uniform_socvoltdiff'       
+        #电池诊断................................................................................................................................................................
+        DBRead=DBDownload.DBDownload(host, port, db, user, password,mode)
+        with DBRead as DBRead:
+            df_soh=DBRead.getdata('time_st,sn,soh,cellsoh', tablename=tablename1, sn=sn, timename='time_sp', st=start_time, sp=end_time)
+            df_uniform=DBRead.getdata('time,sn,cellsoc_diff,cellmin_num,cellmax_num', tablename=tablename2, sn=sn, timename='time', st=start_time, sp=end_time)
+
+        #电池诊断................................................................................................................................................................
+        CellFltInfo=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        df_Diag_Ram_sn = df_Diag_Ram.loc[df_Diag_Ram['product_id']==sn]#历史故障
+        df_Diag_Ram_sn_else = pd.concat([df_Diag_Ram,df_Diag_Ram_sn,df_Diag_Ram_sn]).drop_duplicates(subset=['product_id','code','start_time','Batpos','info'],keep=False)#sn之外的故障
+        CellFltInfo = df_Diag_Ram_sn.drop('Batpos',axis=1)
+        df_Diag_Ram_add = pd.DataFrame()
+        df_Diag_Ram_Update_change = pd.DataFrame()
+        if not df_bms.empty:
+            df_Diag_Batdiag_update_xq=SamplingSafty.main(sn,param,df_bms,CellFltInfo)#学琦计算故障   
+            BatDiag=CBMSBatDiag.BatDiag(sn,celltype,df_bms, df_soh, df_uniform, CellFltInfo)#鹏飞计算
+            df_Diag_Batdiag_update=BatDiag.diag() 
+            df_Diag_Cal_Update_add = pd.concat([CellFltInfo,df_Diag_Batdiag_update_xq,df_Diag_Batdiag_update])#重新计算的该SN下的故障
+            df_Diag_Cal_Update_temp = df_Diag_Cal_Update_add.drop_duplicates(subset=['product_id','start_time','end_time','code','info'], keep='first', inplace=False, ignore_index=False)#去除相同故障
+            df_Diag_cal_early_unfix = pd.DataFrame()
+            df_Diag_Cal_finish = pd.DataFrame()
+            df_Diag_cal_early_fix = pd.DataFrame()
+            if not df_Diag_Cal_Update_temp.empty:
+                #------------------------------合并两者故障,并将同一sn号下的车辆故障放一起----------------------------------------------
+                df_Diag_Cal_Update = df_Diag_Cal_Update_temp#替换上一行
+                df_Diag_Cal_finish = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['end_time'] != '0000-00-00 00:00:00']
+                df_Diag_Cal_new = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['end_time'] == '0000-00-00 00:00:00']
+                df_Diag_Cal_finish['Batpos'] = 1
+                df_Diag_Cal_new['Batpos'] = 0
+                df_feishu_sta = df_read_Yunw.loc[(df_read_Yunw['product_id'] == sn)]#飞书中该sn车辆状态
+                if df_feishu_sta.empty:#飞书中没有该sn记录故障的新增
+                    df_Diag_cal_early_unfix = df_Diag_Cal_new#如果为新出故障,则直接记录在df_diag_frame中
+                else:
+                    df_Diag_cal_later = df_Diag_Cal_new.loc[df_Diag_Cal_new['start_time'] > max(df_feishu_sta['start_time'])]#故障表中故障时间晚于飞书记录时间的新增
+                    df_Diag_cal_early = pd.concat([df_Diag_Cal_new,df_Diag_cal_later,df_Diag_cal_later]).drop_duplicates(subset=['product_id','code','start_time'],keep=False)#故障表中故障时间早于飞书记录时间
+                    df_feishu_sta_latest = df_feishu_sta.loc[df_feishu_sta['start_time'] == max(df_feishu_sta['start_time'])]#飞书中该SN下的最新故障
+                    df_feishu_diag_unfix = (df_feishu_sta_latest['advice'] == '需正常返仓') | (df_feishu_sta_latest['advice'] == '需紧急返仓')
+                    if any(df_feishu_diag_unfix):
+                        df_Diag_cal_early_unfix = df_Diag_Cal_new
+                    else:
+                        df_Diag_cal_early_fix = df_Diag_cal_early
+                        df_Diag_cal_early_unfix = df_Diag_cal_later
+                if not df_Diag_cal_early_fix.empty:
+                    df_Diag_cal_early_fix['Batpos'] = 1
+            df_Diag_Ram_Update = pd.concat([df_Diag_cal_early_unfix,df_Diag_cal_early_fix,df_Diag_Cal_finish])
+            df_Diag_Ram_Update.sort_values(by = ['start_time'], axis = 0, ascending=True,inplace=True)#该sn下当次诊断的故障状态
+            df_Diag_Ram_add = pd.concat([df_Diag_Ram_Update,df_Diag_Ram_sn,df_Diag_Ram_sn]).drop_duplicates(subset=['start_time','code'],keep=False)#此次判断中新增故障
+            df_Diag_Ram_Update_old = pd.concat([df_Diag_Ram_Update,df_Diag_Ram_add,df_Diag_Ram_add]).drop_duplicates(subset=['start_time','code'],keep=False)#此次判断中旧有故障
+            df_Diag_Ram_Update_change = pd.concat([df_Diag_Ram_Update_old,df_Diag_Ram_sn,df_Diag_Ram_sn]).drop_duplicates(subset=['start_time','code','Batpos'],keep=False)#此次判断中更改故障
+            df_Diag_Ram = pd.concat([df_Diag_Ram_sn_else,df_Diag_Cal_new])
+
+        if (len(df_Diag_Ram_add) > 0) | (len(df_Diag_Ram_Update_change) > 0):#历史及现有故障
+            df_Diag_Ram.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\SaftyCenter_CODE_V1_1_DIDI\01Screen_Problem\result.csv',index=False,encoding='GB18030')
+        if len(df_Diag_Ram_add) > 0:#故障车辆已返仓
+            df_Diag_Ram_add.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\SaftyCenter_CODE_V1_1_DIDI\01Screen_Problem\result_add.csv',index=False,encoding='GB18030')
+        if len(df_Diag_Ram_Update_change) > 0:#故障车辆未返仓
+            df_Diag_Ram_Update_change.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\SaftyCenter_CODE_V1_1_DIDI\01Screen_Problem\result_change.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    global SNnums
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\SaftyCenter_CODE_V1_1_DIDI\01Screen_Problem\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['MGMCLN750N215I005','PK504B10100004341','PK504B00100004172','MGMLXN750N2189014']
+    SNnums = ['MGMLXN750N21B5004'] #SNnums_6040
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\SaftyCenter_CODE_V1_1_DIDI\01Screen_Problem\result.csv',encoding='gbk')
+    
+    # df_Diag_Ram=result[result['end_time']=='0000-00-00 00:00:00']
+    result['Batpos'] = 0 
+    df_Diag_Ram=result#[result['Batpos'] == 0]#将故障依然存在的赋值
+    # print('----------------输入--------')
+    # print(df_Diag_Ram)
+    # print('-------计算中-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', seconds=300, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 224 - 0
USER/LZX/01算法开发/04故障诊断/main.py

@@ -0,0 +1,224 @@
+#from test.spf.BatDiag import CBMSBatDiag, Log
+import CBMSBatDiag
+import QX_BatteryParam
+from SC_SamplingSafty import SamplingSafty
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from sqlalchemy import create_engine
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from pandas.core.frame import DataFrame
+import datacompy
+import GetFeiShuData
+
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global df_Diag_Ram
+  
+    start=time.time()
+    end_time=datetime.datetime.now()
+    start_time=end_time-datetime.timedelta(seconds=120)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    for sn in SNnums:
+        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()
+        param=QX_BatteryParam.BatteryInfo(celltype)     
+        # sn='PK50201A000002039'
+        # celltype=2
+        # start_time='2021-05-02 09:12:26'
+        # end_time='2021-06-03 19:12:26'
+        # # df_bms= pd.read_csv(r'D:\Platform\platform_python\data_analyze_platform\USER\01qixiang\98Download\\'+'BMS_'+sn+'.csv',encoding='GB18030')
+
+        #读取原始数据库数据........................................................................................................................................................
+        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']
+        df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\\''BMS_'+sn+'.csv',encoding='GB18030')
+
+        #读取结果数据库数据........................................................................................................................................................
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+        mode=1
+        tablename1='cellstateestimation_soh'
+        tablename2='cellstateestimation_uniform_socvoltdiff'
+        tablename3='cellstateestimation_soc'
+        DBRead=DBDownload.DBDownload(host, port, db, user, password,mode)
+        with DBRead as DBRead:
+            df_soh=DBRead.getdata('time_st,sn,soh,cellsoh', tablename=tablename1, sn=sn, timename='time_sp', st=start_time, sp=end_time)
+            df_uniform=DBRead.getdata('time,sn,cellsoc_diff,cellmin_num,cellmax_num', tablename=tablename2, sn=sn, timename='time', st=start_time, sp=end_time)
+            # df_soc=DBRead.getdata('time','sn','packsoc', tablename=tablename3, sn=sn)
+
+        #电池诊断................................................................................................................................................................
+        #BatDiag=CBMSBatDiag.BatDiag(sn,celltype,df_bms, df_soh, df_uniform)
+        #df_res=BatDiag.diag()
+        #df_Diag_Ram_old=df_Diag_Ram
+        df_Diag_Ram_Update=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        CellFltInfo=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        if not df_bms.empty:
+            CellFltInfo=df_Diag_Ram[df_Diag_Ram['product_id']==sn]
+            df_Diag_Ram_Update=SamplingSafty.main(sn,param,df_bms,CellFltInfo)#学琦计算故障   
+            BatDiag=CBMSBatDiag.BatDiag(sn,celltype,df_bms, df_soh, df_uniform, CellFltInfo)#鹏飞计算
+            df_res=BatDiag.diag() 
+            df_Diag_Ram_Update=df_Diag_Ram_Update.append(df_res)
+            #------------------------------合并两者故障,并将同一sn号下的车辆故障放一起----------------------------------------------
+            df_read_Yunw = GetFeiShuData.getFeiShuDATA()#运维表格数据
+            set_diff_df = pd.concat([df_Diag_Ram_Update,df_read_Yunw,df_read_Yunw]).drop_duplicates(subset=['product_id'],keep=False)#新增故障的sn,报出故障减去原文档中的sn
+            same_sn = df_read_Yunw[(df_read_Yunw['维修信息']== '需正常返仓') | (df_read_Yunw['维修信息']== '需紧急返仓')]#筛选待修改和需返回车辆
+            set_same_df = df_Diag_Ram_Update.loc[df_Diag_Ram_Update['product_id'].isin(same_sn['product_id'])]#筛选待修改和需返回车辆
+            df_temp = set_diff_df.append(set_same_df)#新增及待改进车辆
+            set_same_df_else = pd.concat([df_Diag_Ram_Update,df_temp,df_temp]).drop_duplicates(subset=['product_id'],keep=False)#寻找旧sn中新增故障的sn
+            #先取sn相同的车辆,然后对比时间,保留故障码时间晚于运营记录的信息
+            set_same_df_oth = pd.DataFrame()
+            for i in set_same_df_else['product_id']:
+                if max(df_Diag_Ram_Update.loc[df_Diag_Ram_Update['product_id'] == i]['start_time']) > max(df_read_Yunw.loc[df_read_Yunw['product_id'] == i]['发生时间']):
+                    temp_df = df_Diag_Ram_Update.loc[[df_Diag_Ram_Update['product_id'] == i]['start_time'] > max(df_read_Yunw.loc[df_read_Yunw['product_id'] == i]['发生时间'])]#故障时间晚于运维记录时间的sn故障
+                    set_same_df_oth = set_same_df_oth.append(temp_df)
+                else:
+                    pass
+            df_diag_frame = pd.concat([set_diff_df,same_sn,set_same_df_oth])#筛选新增sn故障、维修信息依旧故障sn、旧sn中新增故障
+            df_tempnum = df_diag_frame.groupby(["product_id"]).size()#获取每个sn的故障总数
+            col1 = df_tempnum[df_tempnum>1].reset_index()[["product_id"]]#多故障sn号
+            col2 = df_tempnum[df_tempnum==1].reset_index()[["product_id"]]#单故障sn号
+            df_temp1 = pd.merge(col1,df_diag_frame,on=["product_id"])#多故障码数据筛选
+            df_temp1.sort_values(by = "start_time", axis = 0, ascending=True,inplace=True)#对故障信息按照sn号进行排序
+            df_temp2 = pd.merge(col2,df_diag_frame,on=["product_id"])#单故障码数据筛选
+            df_temp3 = pd.concat([df_temp1,df_temp2], ignore_index=True)#多故障及单故障合并
+            df_Diag_Ram_Update = df_temp3#计算故障信息
+            #-------------------------------故障--------------------------------------------
+        if not df_Diag_Ram_Update.empty:
+            sn_index=df_Diag_Ram[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_Ram_Update)
+            df_Diag_Ram.reset_index(inplace=True,drop=True)
+
+        Diag_Ram_Dif=datacompy.Compare(df_Diag_Ram_Update,CellFltInfo,join_columns=['product_id','end_time','code'])
+        Diag_Ram_Dif=Diag_Ram_Dif.df1_unq_rows    
+        if len(Diag_Ram_Dif)>0:
+            Diag_Ram_Dif_New=Diag_Ram_Dif[Diag_Ram_Dif['end_time']=='0000-00-00 00:00:00']
+            Diag_Ram_Dif_Finish=df_Diag_Ram[df_Diag_Ram['end_time']!='0000-00-00 00:00:00']
+            if len(Diag_Ram_Dif_New)>0:
+                result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\result.csv',encoding='gbk')
+                result=result.append(Diag_Ram_Dif_New)
+                result.to_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\result.csv',index=False,encoding='GB18030')
+            if len(Diag_Ram_Dif_Finish)>0:
+                result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\result.csv',encoding='gbk')
+                Diag_Ram_Dif_Finish=Diag_Ram_Dif_Finish.reset_index(drop=True)
+                for i in range(0,len(Diag_Ram_Dif_Finish)):
+                    result.loc[result[result[result['product_id']==Diag_Ram_Dif_Finish.loc[i,'product_id']]['code']==Diag_Ram_Dif_Finish.loc[i,'code']].index,'end_time']=Diag_Ram_Dif_Finish.loc[i,'end_time']
+                result.to_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\result.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+        # print(df_soh)
+        
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def shortdiag_cal():
+    global SNnums
+    global df_Diag_Ram
+    start=time.time()
+    end_time=datetime.datetime.now()
+    start_time=end_time-datetime.timedelta(days=30)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    for sn in SNnums:
+        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()
+
+        #读取结果数据库数据........................................................................................................................................................
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+        mode=2
+        tablename4='cellstateestimation_intershort'
+        DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)  #mode==1取数据库最后一行数据
+        with DBRead as DBRead:
+            df_short=DBRead.getdata('time_sp,sn,short_current', tablename=tablename4, sn=sn, timename='time_sp', st=start_time, sp=end_time)  
+        
+        #电池诊断................................................................................................................................................................
+        ShortDiag=CBMSBatDiag.ShortDiag(sn,celltype, df_short)
+        df_res=ShortDiag.shortdiag()
+        df_res.to_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\\'+'CBMS_diag_'+sn+'.csv',encoding='GB18030')
+        
+        print(df_res)
+
+        end=time.time()
+        print(end-start)
+        # print(df_soh)
+        
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    SNnums=['MGMCLN750N215I005','PK504B10100004341','PK504B00100004172','MGMLXN750N2189014']
+    #SNnums = SNnums_6060
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\result.csv',encoding='gbk')
+    
+    df_Diag_Ram=result[result['end_time']=='0000-00-00 00:00:00']
+    print('----------------输入--------')
+    print(df_Diag_Ram)
+    print('-------done-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', seconds=120, id='diag_job')
+    scheduler.add_job(shortdiag_cal, 'interval', days=7, id='shortdiag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 235 - 0
USER/LZX/01算法开发/04故障诊断/maincopy.py

@@ -0,0 +1,235 @@
+#from test.spf.BatDiag import CBMSBatDiag, Log
+import CBMSBatDiag
+import QX_BatteryParam
+from SC_SamplingSafty import SamplingSafty
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from sqlalchemy import create_engine
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from pandas.core.frame import DataFrame
+import datacompy
+import GetFeiShuData
+
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global df_Diag_Ram
+  
+    start=time.time()
+    end_time=datetime.datetime.now()
+    start_time=end_time-datetime.timedelta(seconds=60)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    for sn in SNnums:
+        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()
+        param=QX_BatteryParam.BatteryInfo(celltype)     
+        # sn='PK50201A000002039'
+        # celltype=2
+        # start_time='2021-05-02 09:12:26'
+        # end_time='2021-06-03 19:12:26'
+        # # df_bms= pd.read_csv(r'D:\Platform\platform_python\data_analyze_platform\USER\01qixiang\98Download\\'+'BMS_'+sn+'.csv',encoding='GB18030')
+
+        #读取原始数据库数据........................................................................................................................................................
+        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']
+        #df_bms.to_csv(r'D:\Work\Code_write\data_analyze_platform\01智联运维故障显示\\''BMS_'+sn+'.csv',encoding='GB18030')
+
+        #读取结果数据库数据........................................................................................................................................................
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+        mode=1
+        tablename1='cellstateestimation_soh'
+        tablename2='cellstateestimation_uniform_socvoltdiff'
+        tablename3='cellstateestimation_soc'
+        DBRead=DBDownload.DBDownload(host, port, db, user, password,mode)
+        with DBRead as DBRead:
+            df_soh=DBRead.getdata('time_st,sn,soh,cellsoh', tablename=tablename1, sn=sn, timename='time_sp', st=start_time, sp=end_time)
+            df_uniform=DBRead.getdata('time,sn,cellsoc_diff,cellmin_num,cellmax_num', tablename=tablename2, sn=sn, timename='time', st=start_time, sp=end_time)
+            # df_soc=DBRead.getdata('time','sn','packsoc', tablename=tablename3, sn=sn)
+
+        #电池诊断................................................................................................................................................................
+        #BatDiag=CBMSBatDiag.BatDiag(sn,celltype,df_bms, df_soh, df_uniform)
+        #df_res=BatDiag.diag()
+        df_Diag_Ram_old=df_Diag_Ram.drop('Batpos',axis=1)
+        df_Diag_Ram_Update=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        CellFltInfo=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        if not df_bms.empty:
+            CellFltInfo=df_Diag_Ram_old[df_Diag_Ram_old['product_id']==sn]#历史故障
+            df_Diag_Batdiag_update_xq=SamplingSafty.main(sn,param,df_bms,CellFltInfo)#学琦计算故障   
+            BatDiag=CBMSBatDiag.BatDiag(sn,celltype,df_bms, df_soh, df_uniform, CellFltInfo)#鹏飞计算
+            df_Diag_Batdiag_update=BatDiag.diag() 
+            df_Diag_Cal_Update_temp=df_Diag_Batdiag_update_xq.append(df_Diag_Batdiag_update)
+            if not df_Diag_Cal_Update_temp.empty:
+                #------------------------------合并两者故障,并将同一sn号下的车辆故障放一起----------------------------------------------
+                df_Diag_Cal_Update = df_Diag_Cal_Update_temp.append(df_Diag_Ram_old)
+                df_read_Yunw = GetFeiShuData.getFeiShuDATA()#运维表格数据
+                df_read_Yunw.rename(columns={'电池编码':'product_id'},inplace=True)
+                set_diff_df = pd.concat([df_Diag_Cal_Update,df_read_Yunw,df_read_Yunw]).drop_duplicates(subset=['product_id','code','start_time'],keep=False)#新增故障的sn,报出故障减去原文档中的sn
+                new_sn = set_diff_df['product_id']
+                same_sn = df_read_Yunw.loc[(df_read_Yunw['维修信息']== '需正常返仓') | (df_read_Yunw['维修信息']== '需紧急返仓')]['product_id']#筛选待修改和需返回车辆
+                #set_same_df = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['product_id'].isin(same_sn['product_id'])]#筛选待修改和需返回车辆
+                need_fix_sn = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['end_time'] == '0000-00-00 00:00:00']['product_id']
+                df_temp_sn = pd.concat([new_sn,same_sn,need_fix_sn])#新增及待改进车辆
+                df_diag_frame = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['product_id'].isin(df_temp_sn)]#筛选待修改和需返回车辆
+                df_tempnum = df_diag_frame.groupby(["product_id"]).size()#获取每个sn的故障总数
+                col1 = df_tempnum[df_tempnum>1].reset_index()[["product_id"]]#多故障sn号
+                col2 = df_tempnum[df_tempnum==1].reset_index()[["product_id"]]#单故障sn号
+                df_temp1 = pd.DataFrame()
+                if not col1.empty:
+                    for item in col1['product_id']:
+                        temp_data = df_diag_frame.loc[df_diag_frame['product_id'] == item]
+                        temp_data.sort_values(by = "start_time", axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+                        df_temp1.append(temp_data)
+                df_temp2 = pd.merge(col2,df_diag_frame,on=["product_id"])#单故障码数据筛选
+                df_temp3 = pd.concat([df_temp1,df_temp2])#多故障及单故障合并
+                df_temp4 = df_temp3.reset_index(drop=True)
+                #-------------------------------差集加入状态1--------------------------------
+                set_diff_df_add = pd.concat([df_Diag_Cal_Update,df_temp4,df_temp4]).drop_duplicates(subset=['product_id','code','start_time'],keep=False)
+                set_diff_df_add['Batpos'] = 1
+                #--------------------------------交集加入状态0------------------------------
+                df_temp4['Batpos'] = 0
+                df_Diag_Ram_Update = df_temp4.append(set_diff_df)#计算故障信息
+                diag_temp = df_Diag_Ram_Update.reset_index(drop=True)
+                df_Diag_Ram_Update = diag_temp[['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice','Batpos']]
+                #-------------------------------故障--------------------------------------------
+                df_Diag_Ram = df_Diag_Ram_Update
+                # sn_index=df_Diag_Ram[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_Ram_Update)
+                # df_Diag_Ram.reset_index(inplace=True,drop=True)
+
+            # Diag_Ram_Dif=datacompy.Compare(df_Diag_Ram_Update,CellFltInfo,join_columns=['product_id','end_time','code'])
+            # Diag_Ram_Dif=Diag_Ram_Dif.df1_unq_rows    
+        if len(df_Diag_Ram)>0:#Diag_Ram_Dif
+            Diag_Ram_Dif_New=df_Diag_Ram[df_Diag_Ram['end_time']=='0000-00-00 00:00:00']
+            Diag_Ram_Dif_Finish=df_Diag_Ram[df_Diag_Ram['end_time']!='0000-00-00 00:00:00']
+            if len(Diag_Ram_Dif_New)>0:
+                result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\result.csv',encoding='gbk')
+                result=result.append(Diag_Ram_Dif_New)
+                result.to_csv(r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\result.csv',index=False,encoding='GB18030')
+            if len(Diag_Ram_Dif_Finish)>0:
+                result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\result.csv',encoding='gbk')
+                Diag_Ram_Dif_Finish=Diag_Ram_Dif_Finish.reset_index(drop=True)
+                for i in range(0,len(Diag_Ram_Dif_Finish)):
+                    aa_id = result['product_id']==Diag_Ram_Dif_Finish.loc[i,'product_id']
+                    bb_code = result['code']==Diag_Ram_Dif_Finish.loc[i,'code']
+                    result.loc[result.loc[aa_id & bb_code].index,'end_time'] = Diag_Ram_Dif_Finish.loc[i,'end_time']
+                    # result.loc[result[result.loc[result['product_id']==Diag_Ram_Dif_Finish.loc[i,'product_id']]['code']==Diag_Ram_Dif_Finish.loc[i,'code']].index,'end_time']=Diag_Ram_Dif_Finish.loc[i,'end_time']
+                result.to_csv(r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\result.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+        # print(df_soh)
+        
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def shortdiag_cal():
+    global SNnums
+    global df_Diag_Ram
+    start=time.time()
+    end_time=datetime.datetime.now()
+    start_time=end_time-datetime.timedelta(days=30)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    for sn in SNnums:
+        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()
+
+        #读取结果数据库数据........................................................................................................................................................
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+        mode=2
+        tablename4='cellstateestimation_intershort'
+        DBRead=DBDownload.DBDownload(host, port, db, user, password, mode)  #mode==1取数据库最后一行数据
+        with DBRead as DBRead:
+            df_short=DBRead.getdata('time_sp,sn,short_current', tablename=tablename4, sn=sn, timename='time_sp', st=start_time, sp=end_time)  
+        
+        #电池诊断................................................................................................................................................................
+        ShortDiag=CBMSBatDiag.ShortDiag(sn,celltype, df_short)
+        df_res=ShortDiag.shortdiag()
+        df_res.to_csv(r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\\'+'CBMS_diag_'+sn+'.csv',encoding='GB18030')
+        
+        print(df_res)
+
+        end=time.time()
+        print(end-start)
+        # print(df_soh)
+        
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['MGMCLN750N215I005','PK504B10100004341','PK504B00100004172','MGMLXN750N2189014']
+    SNnums = SNnums_6040
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\01Screen_Problem\result.csv',encoding='gbk')
+    
+    df_Diag_Ram=result[result['end_time']=='0000-00-00 00:00:00']
+    print('----------------输入--------')
+    print(df_Diag_Ram)
+    print('-------done-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', seconds=60, id='diag_job')
+    scheduler.add_job(shortdiag_cal, 'interval', days=7, id='shortdiag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 178 - 0
USER/LZX/01算法开发/04故障诊断/maincopy_v1.py

@@ -0,0 +1,178 @@
+import CBMSBatDiag
+import QX_BatteryParam
+from SC_SamplingSafty import SamplingSafty
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from sqlalchemy import create_engine
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from pandas.core.frame import DataFrame
+import datacompy
+import FeiShuData
+
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global df_Diag_Ram
+  
+    start=time.time()
+    end_time=datetime.datetime.now()
+    start_time=end_time-datetime.timedelta(seconds=130)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+    df_read_Yunw = FeiShuData.getFeiShuDATA()#运维表格数据
+    df_read_Yunw.rename(columns={'电池编码':'product_id'},inplace=True)
+    df_read_Yunw.rename(columns={'内容描述':'info'},inplace=True)
+    df_read_Yunw.rename(columns={'发生时间':'start_time'},inplace=True)
+    df_read_Yunw.rename(columns={'维修信息':'advice'},inplace=True)
+    for sn in SNnums:
+        print(sn)
+        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()
+        param=QX_BatteryParam.BatteryInfo(celltype) 
+        print(sn)    
+        #读取原始数据库数据........................................................................................................................................................
+        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']
+
+        #读取结果数据库数据........................................................................................................................................................
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+        mode=1
+        tablename1='cellstateestimation_soh'
+        tablename2='cellstateestimation_uniform_socvoltdiff'       
+        #电池诊断................................................................................................................................................................
+        DBRead=DBDownload.DBDownload(host, port, db, user, password,mode)
+        with DBRead as DBRead:
+            df_soh=DBRead.getdata('time_st,sn,soh,cellsoh', tablename=tablename1, sn=sn, timename='time_sp', st=start_time, sp=end_time)
+            df_uniform=DBRead.getdata('time,sn,cellsoc_diff,cellmin_num,cellmax_num', tablename=tablename2, sn=sn, timename='time', st=start_time, sp=end_time)
+
+        #电池诊断................................................................................................................................................................
+        CellFltInfo=DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
+        df_Diag_Ram_sn = df_Diag_Ram.loc[df_Diag_Ram['product_id']==sn]#历史故障
+        df_Diag_Ram_sn_else = pd.concat([df_Diag_Ram,df_Diag_Ram_sn,df_Diag_Ram_sn]).drop_duplicates(subset=['product_id','code','start_time','Batpos','info'],keep=False)#sn之外的故障
+        CellFltInfo = df_Diag_Ram_sn.drop('Batpos',axis=1)
+        df_Diag_Ram_fix = df_Diag_Ram.loc[df_Diag_Ram['Batpos'] == 1]
+        df_Diag_Ram_unfix = df_Diag_Ram.loc[df_Diag_Ram['Batpos'] == 0]
+        if not df_bms.empty:
+            df_Diag_Batdiag_update_xq=SamplingSafty.main(sn,param,df_bms,CellFltInfo)#学琦计算故障   
+            BatDiag=CBMSBatDiag.BatDiag(sn,celltype,df_bms, df_soh, df_uniform, CellFltInfo)#鹏飞计算
+            df_Diag_Batdiag_update=BatDiag.diag() 
+            df_Diag_Cal_Update_add = pd.concat([CellFltInfo,df_Diag_Batdiag_update_xq,df_Diag_Batdiag_update])#重新计算的该SN下的故障
+            df_Diag_Cal_Update_temp = df_Diag_Cal_Update_add.drop_duplicates(subset=['product_id','start_time','end_time','code','info'], keep='first', inplace=False, ignore_index=False)#去除相同故障
+            df_Diag_cal_early_unfix = pd.DataFrame()
+            df_sn_car_fix = pd.DataFrame()
+            df_Diag_Cal_finish = pd.DataFrame()
+            df_Diag_cal_early_fix = pd.DataFrame()
+            if not df_Diag_Cal_Update_temp.empty:
+                #------------------------------合并两者故障,并将同一sn号下的车辆故障放一起----------------------------------------------
+                df_Diag_Cal_Update = df_Diag_Cal_Update_temp#替换上一行
+                df_Diag_Cal_finish = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['end_time'] != '0000-00-00 00:00:00']
+                df_Diag_Cal_new = df_Diag_Cal_Update.loc[df_Diag_Cal_Update['end_time'] == '0000-00-00 00:00:00']
+                df_Diag_Cal_finish['Batpos'] = 1
+                df_Diag_Cal_new['Batpos'] = 0
+                df_feishu_sta = df_read_Yunw.loc[(df_read_Yunw['product_id'] == sn)]#飞书中该sn车辆状态
+                if df_feishu_sta.empty:
+                    df_Diag_cal_early_unfix = df_Diag_Cal_new#如果为新出故障,则直接记录在df_diag_frame中
+                else:
+                    df_Diag_cal_later = df_Diag_Cal_new.loc[df_Diag_Cal_new['start_time'] > max(df_feishu_sta['start_time'])]#故障表中故障时间晚于飞书记录时间
+                    df_Diag_cal_early = pd.concat([df_Diag_Cal_new,df_Diag_cal_later,df_Diag_cal_later]).drop_duplicates(subset=['product_id','code','start_time'],keep=False)#故障表中故障时间早于飞书记录时间
+                    df_feishu_sta_latest = df_feishu_sta.loc[df_feishu_sta['start_time'] == max(df_feishu_sta['start_time'])]#飞书中该SN下的最新故障
+                    df_feishu_diag_unfix = (df_feishu_sta_latest['advice'] == '需正常返仓') | (df_feishu_sta_latest['advice'] == '需紧急返仓')
+                    df_sn_car_unfix = pd.DataFrame()
+                    if any(df_feishu_diag_unfix):
+                        df_Diag_cal_early_unfix = df_Diag_Cal_new
+                    else:
+                        df_Diag_cal_early_fix = df_Diag_cal_early
+                        df_Diag_cal_early_unfix = df_Diag_cal_later
+                if not df_Diag_cal_early_fix.empty:
+                    df_Diag_cal_early_fix['Batpos'] = 1
+            df_Diag_Ram_Update = pd.concat([df_Diag_cal_early_unfix,df_Diag_cal_early_fix,df_Diag_Cal_finish])
+            df_Diag_Ram_Update.sort_values(by = ['start_time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+            df_temp5 = pd.concat([df_Diag_Ram_Update,df_Diag_Ram_sn_else])
+            df_Diag_Ram_sum = df_temp5.drop_duplicates(subset=['product_id','start_time','end_time','code','info'], keep='first', inplace=False, ignore_index=False)#去除相同故障
+            df_tempnum = df_Diag_Ram_sum.groupby(['product_id']).size()#获取每个sn的故障总数
+            col1 = df_tempnum[df_tempnum>1].reset_index()[['product_id']]#多故障sn号
+            col2 = df_tempnum[df_tempnum==1].reset_index()[['product_id']]#单故障sn号
+            df_temp1 = pd.DataFrame()
+            if not col1.empty:
+                for item in col1['product_id']:
+                    temp_data = df_Diag_Ram_sum.loc[df_Diag_Ram_sum['product_id'] == item]
+                    temp_data.sort_values(by = ['start_time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+                    df_temp1 = df_temp1.append(temp_data)
+            df_temp2 = pd.merge(col2,df_Diag_Ram_sum,on=["product_id"])#单故障码数据筛选
+            df_temp3 = pd.concat([df_temp1,df_temp2])#多故障及单故障合并
+            df_temp4 = df_temp3.reset_index(drop=True)
+            df_Diag_Ram = df_temp4
+            df_Diag_Ram_fix = df_Diag_Ram.loc[df_Diag_Ram['Batpos'] == 1]
+            df_Diag_Ram_unfix = df_Diag_Ram.loc[df_Diag_Ram['Batpos'] == 0]
+        if len(df_Diag_Ram) > 0:
+            df_Diag_Ram.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\01Screen_Problem\result.csv',index=False,encoding='GB18030')
+        if len(df_Diag_Ram_fix) > 0:
+            df_Diag_Ram_fix.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\01Screen_Problem\result_fix.csv',index=False,encoding='GB18030')
+        if len(df_Diag_Ram_unfix) > 0:
+            df_Diag_Ram_unfix.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\01Screen_Problemm\result_unfix.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+
+#...............................................主函数.......................................................................................................................
+if __name__ == "__main__":
+    global SNnums
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\USER\01Screen_Problem\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['MGMCLN750N215I005','PK504B10100004341','PK504B00100004172','MGMLXN750N2189014']
+    SNnums = ['MGMLXN750N21B5004'] #SNnums_6040
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    result=pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\01Screen_Problem\result.csv',encoding='gbk')
+    
+    # df_Diag_Ram=result[result['end_time']=='0000-00-00 00:00:00']
+    df_Diag_Ram=result#[result['Batpos'] == 0]#将故障依然存在的赋值
+    print('----------------输入--------')
+    print(df_Diag_Ram)
+    print('-------计算中-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', seconds=120, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

+ 55 - 0
USER/LZX/01算法开发/04故障诊断/test.py

@@ -0,0 +1,55 @@
+import CBMSBatDiag
+import QX_BatteryParam
+from SC_SamplingSafty import SamplingSafty
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+from sqlalchemy import create_engine
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from pandas.core.frame import DataFrame
+import datacompy
+import pymysql
+import GetFeiShuData
+#...................................电池包电芯安全诊断函数......................................................................................................................
+
+SNnums = ['MGMCLN750N215N049']
+
+end_time=datetime.datetime.now()
+start_time=end_time-datetime.timedelta(seconds=120)
+start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+end_time=end_time.strftime('%Y-%m-%d %H:%M:%S')
+for sn in SNnums:
+    start=time.time()
+    print(sn)
+    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()
+    param=QX_BatteryParam.BatteryInfo(celltype) 
+    print(sn)    
+    # sn='PK50201A000002039'
+    # celltype=2
+    # start_time='2021-05-02 09:12:26'
+    # end_time='2021-06-03 19:12:26'
+    # # df_bms= pd.read_csv(r'D:\Platform\platform_python\data_analyze_platform\USER\01qixiang\98Download\\'+'BMS_'+sn+'.csv',encoding='GB18030')
+
+    #读取原始数据库数据........................................................................................................................................................
+    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)
+    end = time.time()
+    print(end - start)

+ 24 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/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=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\01算法开发\内阻估计\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 108 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/main.py

@@ -0,0 +1,108 @@
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from pandas.core.frame import DataFrame
+import matplotlib as plt
+from pylab import*
+import sor_est_v0301
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+import log
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def cell_sor_test():
+    global SNnums
+    global df_diag_sor
+    start=time.time()
+    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=3)
+    end_time=str(now_time)
+    start_time=str(start_time)
+    k = 1
+    for sn in SNnums[46:]:
+        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' in sn: 
+            celltype=4 #CATL 50ah三元电芯
+        elif 'UD' in sn:
+            celltype=4 #CATL 50ah三元电芯
+        elif 'TJMCL' in sn: 
+            celltype=100 #金茂电芯
+        else:
+            print('SN:{},未找到对应电池类型!!!'.format(sn))
+            continue
+            # sys.exit()
+        print('计算的第' + str(k) + '个:' + sn)
+        k = k + 1
+        #读取原始数据库数据........................................................................................................................................................
+        start_time = '2022-01-01 00:00:00'
+        end_time = '2022-03-01 00:00:00'
+        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']
+        # df_sor_add = pd.DataFrame()
+        param = BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        #........................................................电压内阻估计.....................................................................
+        if not df_bms.empty:
+            Diag_sorvol_temp = sor_est_v0301.sor_est(sn,celltype,df_bms)#电压内阻估计
+            df_sor_add = Diag_sorvol_temp.sor_cal()        
+            if not df_sor_add.empty:
+                df_diag_sor = df_diag_sor.append(df_sor_add)
+                df_diag_sor = df_diag_sor.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)
+                df_diag_sor.to_csv(r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\LZX\01算法开发\05内阻及电压估计\01算法开发\内阻估计\测试结果\估计结果\内阻估计.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+        
+
+#...............................................主函数...............................................................................................
+if __name__ == "__main__":
+    global SNnums
+    global df_diag_sor
+    
+    excelpath=r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\LZX\01算法开发\00项目sn号\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()
+    # SNums_finish = list(df_diag_sor['sn'])
+    #SNnums=SNnums_L7255 + SNnums_C7255 + SNnums_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    #SNnums=['TJMCL120502305010','TJMCL120502305012','TJMCL120502305048','TJMCL120502305044','TJMCL120502305026','TJMCL120502305022','TJMCL120502305032','TJMCL120502305038']
+    # SNnums = SNnums_U7255#['MGMCLN750N215N049'] #SNnums_6040 #SNnums_C7255 #SNnums_6040['MGMCLN750N215N049'] PK504B00100004003
+    SNnums_temp = pd.read_csv(r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\LZX\01算法开发\05内阻及电压估计\01算法开发\内阻估计\测试结果\内阻一致性-列表名\df_same_sn.csv',encoding='GB18030')
+    SNnums = SNnums_temp['same_sn']
+    # SNnums = list(set(SNnums_U7255).difference(set(SNums_finish)))
+    # SNnums = ['MGMCLN750N215N097']
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    df_diag_sor = pd.read_csv(r'D:\Develop\User\Liuzhongxiao\data_analyze_platform\USER\LZX\01算法开发\05内阻及电压估计\01算法开发\内阻估计\测试结果\估计结果\内阻估计.csv',encoding='GB18030')
+    
+    print('----------------输入--------')
+    print('-------计算中-----------')
+    cell_sor_test()
+    #定时任务.......................................................................................................................................................................
+    # scheduler = BlockingScheduler()
+    # scheduler.add_job(cell_sor_test, 'interval', seconds=10, id='diag_job')
+    # try:  
+    #     scheduler.start()
+    # except Exception as e:
+    #     scheduler.shutdown()
+    #     print(repr(e))
+    #     mylog.logopt(e)

+ 124 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/sor_est.py

@@ -0,0 +1,124 @@
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import scipy
+import math
+import itertools
+import log
+from scipy.signal import savgol_filter
+from scipy import interpolate
+from sklearn.linear_model import LinearRegression
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class sor_est:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.LookTab_OCV = self.param.LookTab_OCV
+        self.LookTab_SOC = self.param.LookTab_SOC
+        
+        self.cellvolt_list=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+#.............................................内阻及电压估计............................................................................
+    def sor_cal(self):
+        start_time = time.time()
+        data = self.df_bms
+        LookTab_OCV = self.LookTab_OCV
+        LookTab_SOC = self.LookTab_SOC
+        max_volt = max(LookTab_OCV)
+        min_volt = min(LookTab_OCV)
+        crnt = data['总电流[A]']
+        zero_group = itertools.groupby(crnt, lambda x : x == 0)#判断电流是否为0,并根据0和非0分组
+        zero_flg = []
+        zero_value = []
+        for k, v in zero_group:
+            zero_flg.append(k)#0和非0状态
+            zero_value.append(len(list(v)))#各个连续0和非0值的个数
+        zero_flg_new = zero_flg.copy()
+        for item in range(0, len(zero_value)):
+            if (zero_flg[item] == True) & (zero_value[item] < 6):#筛选出充电或放电过程中跳零的点,0点数据少于等于3个采样的时刻
+                zero_flg_new[item] = False
+        def get_index1(lst=None, item=''):
+            return [index for (index,value) in enumerate(lst) if value == item]#获取某个元素的位置
+        true_num = (get_index1(zero_flg_new, True))#获取电流为0的位置
+        zero_value_fit = []
+        true_num_flg = []
+        for item in range(len(true_num) - 1):
+            if ((true_num[item + 1] - true_num[item]) == 2):#重新赋值零点和非零点并计算各数据段个数
+                true_num_flg.append(True)
+                true_num_flg.append(False)
+                zero_value_fit.append(zero_value[true_num[item]])#[2*item]
+                zero_value_fit.append(zero_value[true_num[item] + 1])#[2*item + 1]
+            else:
+                true_num_flg.append(True)
+                true_num_flg.append(False)
+                zero_value_fit.append(zero_value[true_num[item]])
+                zero_value_fit.append(sum(zero_value[(true_num[item] + 1):(true_num[item + 1])]))
+        true_num_flg_fit = []
+        for item in range(1,len(zero_value_fit) + 1):
+            true_num_flg_fit.append(sum(zero_value_fit[0:item]) - 1)
+        true_num_flg_fit.insert(0,0)
+        soc_interplt = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#插值函数
+        cellvolt_name = self.cellvolt_list#电芯数量
+        celltemp_name = self.celltemp_name#电芯温度数量
+        df_sor_result = pd.DataFrame(columns = ["sn", "time", "sor", "soc", "temp", "delta_time"])
+        k = 1
+        for range_num in range(0, len(true_num_flg) - 1):#
+            sor_temp = []
+            df_time = pd.to_datetime(data['时间戳'])
+            delta_time = (df_time.iloc[true_num_flg_fit[range_num + 1]] - df_time.iloc[true_num_flg_fit[range_num] + 1])/pd.Timedelta(1, 'min')#电流为0阶段的时间长度
+            if (true_num_flg[range_num] == True) & (delta_time > 30):#电流为0时间大于30 min时,利用下一段数据计算阻值
+                df_sor_soc_data = data.iloc[(true_num_flg_fit[range_num] + 1):(true_num_flg_fit[range_num + 1] + 1)]#获取电流为零数据段,计算SOC
+                df_sor_cal_temp = data.iloc[(true_num_flg_fit[range_num + 1] + 1):(true_num_flg_fit[range_num + 2] + 1)]#获取电流非零数据,计算内阻
+                df_sor_cal_temp.reset_index(drop = True, inplace = True)
+                df_sor_cal_len = len(df_sor_cal_temp)
+                cal_range_num = true_num_flg_fit[range_num + 1] + 1
+                if df_sor_cal_len > 20:#放电数据
+                    df_sor_cal = df_sor_cal_temp.iloc[:30]#筛选前30行放电数据
+                    df_sor_time = pd.to_datetime(df_sor_cal['时间戳'])
+                    delta_time_sor = (df_sor_time.iloc[-1] - df_sor_time.iloc[0])/pd.Timedelta(1, 'min')#计算内阻使用数据段的时长
+                    df_soc_volt = df_sor_soc_data[cellvolt_name].iloc[-1]/1000
+                    # print(df_sor_cal)
+                    df_soc_volt[df_soc_volt > max_volt] = max_volt - 0.005
+                    df_soc_volt[df_soc_volt < min_volt] = min_volt + 0.005
+                    df_soc = soc_interplt(list(df_soc_volt))#插值计算电芯SOC
+                    df_sor_volt = df_sor_cal[cellvolt_name]/1000
+                    df_sor_crnt = df_sor_cal['总电流[A]']
+                    df_sorvolt_dif = np.diff(df_sor_volt, axis = 0)
+                    df_sorcrnt_dif = np.diff(df_sor_crnt, axis = 0)
+                    df_sorvolt_dif_csv = pd.DataFrame(df_sorvolt_dif)
+                    df_sorvolt_dif_csv.columns = cellvolt_name
+                    if np.sum(df_sorcrnt_dif != 0) > 0.5*len(df_sorcrnt_dif):
+                        for item in cellvolt_name:
+                            lineModel = LinearRegression()
+                            lineModel.fit(np.array(df_sorcrnt_dif).reshape(-1, 1), df_sorvolt_dif_csv[item])
+                            # delt_volt = lineModel.predict(np.array(df_sorcrnt_dif).reshape(-1, 1))
+                            sor_temp.append(lineModel.coef_[0])
+                        print(k)
+                        end_time_cal = time.time()
+                        print(end_time_cal - start_time)
+                        k = k + 1
+                        df_sor_result_temp = pd.DataFrame({"sn":[self.sn], "time":[df_sor_cal_temp['时间戳'][0]], "sor":[str(sor_temp)], "soc":[str(list(df_soc))], 
+                                            "temp":[str(list(df_sor_cal_temp[celltemp_name].iloc[0]))], "delta_time":[delta_time_sor]})
+                        df_sor_result = df_sor_result.append(df_sor_result_temp)
+                        df_sor_result.reset_index(drop = True, inplace = True)
+        end_time = time.time()
+        print(end_time - start_time)
+        if not df_sor_result.empty:
+            return df_sor_result
+        else:
+            return pd.DataFrame()

+ 204 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/sor_est_v0301.py

@@ -0,0 +1,204 @@
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import scipy
+import math
+import itertools
+import log
+from scipy.signal import savgol_filter
+from scipy import interpolate
+from sklearn.linear_model import LinearRegression
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class sor_est:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+        self.LookTab_OCV = self.param.LookTab_OCV
+        self.LookTab_SOC = self.param.LookTab_SOC
+        
+        self.cellvolt_list=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+    
+#.............................................内阻及电压估计............................................................................
+    def sor_cal(self):
+        #定义Rint模型计算内阻函数----------------------------------------------
+        def sor_cal_prog(input_data):
+            # cellvolt_name = self.cellvolt_list#电芯数量
+            # celltemp_name = self.celltemp_name#电芯温度数量
+            # LookTab_OCV = self.LookTab_OCV
+            # LookTab_SOC = self.LookTab_SOC
+            # max_volt = max(LookTab_OCV)
+            # min_volt = min(LookTab_OCV)
+            # soc_interplt = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#OCV-SOC插值函数
+            df_sor_result_cal = pd.DataFrame(columns = ["sn", "time", "sor", "sor_sigma", "soc", "temp", "delta_time"])
+            np_crnt_num = np.sum(input_data['总电流[A]'] != 0)#计算所选数据中非零值个数
+            if np_crnt_num > 10:#放电中无电流过多数据时不计算阻值
+                sor_temp = []
+                df_sor_time = pd.to_datetime(input_data['时间戳'])
+                df_sor_soc_data = input_data.iloc[0]#静置最后时刻数据,计算SOC用
+                delta_time_sor = round((df_sor_time.iloc[-1] - df_sor_time.iloc[0])/pd.Timedelta(1, 'min'), 3)#计算内阻使用数据段的时长
+                df_soc_volt = df_sor_soc_data[cellvolt_name]/1000
+                df_soc_volt[df_soc_volt > max_volt] = max_volt - 0.0005
+                df_soc_volt[df_soc_volt < min_volt] = min_volt + 0.0005
+                df_soc_temp = soc_interplt(list(df_soc_volt))#插值计算电芯SOC
+                df_soc = [round(i, 3) for i in df_soc_temp]
+                df_sor_volt = input_data[cellvolt_name]/1000
+                df_sor_crnt = input_data['总电流[A]']
+                df_sorvolt_dif = np.diff(df_sor_volt, axis = 0)
+                df_sorcrnt_dif = np.diff(df_sor_crnt, axis = 0)
+                df_sorvolt_dif_csv = pd.DataFrame(df_sorvolt_dif)
+                df_sorvolt_dif_csv.columns = cellvolt_name
+                df_sor_volt_csv = pd.DataFrame(df_sor_volt)
+                df_sor_volt_csv.columns = cellvolt_name
+                if np.sum(df_sor_crnt != 0) > 0.3*len(df_sorcrnt_dif):
+                    if np.sum(df_sorcrnt_dif != 0) > 0.2*len(df_sorcrnt_dif):
+                        for item in cellvolt_name:
+                            lineModel = LinearRegression()
+                            lineModel.fit(np.array(df_sorcrnt_dif).reshape(-1, 1), df_sorvolt_dif_csv[item])
+                            sor_temp.append(1000*lineModel.coef_[0])
+                            sor_temp_formt = [round(i, 3) for i in sor_temp]
+                        sor_sort_temp = np.sort(sor_temp)
+                        sor_sort_del = sor_sort_temp[1:-2]
+                        sor_sort_del_mean = np.mean(sor_sort_del)#去除最值的均值
+                        sor_sort_del_std = np.std(sor_sort_del)#去除最值的均方差
+                        sor_sigma_temp = list((sor_temp - sor_sort_del_mean)/sor_sort_del_std)
+                        sor_sigma = [round(i, 3) for i in sor_sigma_temp]
+                        df_sor_result_cal = pd.DataFrame({"sn":[self.sn], "time":[input_data['时间戳'].iloc[0]], "sor":[str(sor_temp_formt)], "sor_sigma":[str(sor_sigma)],
+                                                                "soc":[str(list(df_soc))], "temp":[str(list(input_data[celltemp_name].iloc[0]))], "delta_time":[delta_time_sor]})
+                if np.sum(df_sor_crnt != 0) > 0.6*len(df_sorcrnt_dif):
+                    if np.sum(df_sorcrnt_dif != 0) < 0.05*len(df_sorcrnt_dif):
+                        for item in cellvolt_name:
+                            sor_item = (df_sor_volt_csv[item].iloc[0] - df_sor_volt_csv[item].iloc[-1])/np.mean(df_sor_crnt)
+                            sor_temp.append(1000*sor_item)
+                            sor_temp_formt = [round(i, 3) for i in sor_temp]
+                        sor_sort_temp = np.sort(sor_temp)
+                        sor_sort_del = sor_sort_temp[1:-2]
+                        sor_sort_del_mean = np.mean(sor_sort_del)#去除最值的均值
+                        sor_sort_del_std = np.std(sor_sort_del)#去除最值的均方差
+                        sor_sigma_temp = list((sor_temp - sor_sort_del_mean)/sor_sort_del_std)
+                        sor_sigma = [round(i, 3) for i in sor_sigma_temp]
+                        df_sor_result_cal = pd.DataFrame({"sn":[self.sn], "time":[input_data['时间戳'].iloc[0]], "sor":[str(sor_temp_formt)], "sor_sigma":[str(sor_sigma)],
+                                                                "soc":[str(list(df_soc))], "temp":[str(list(input_data[celltemp_name].iloc[0]))], "delta_time":[delta_time_sor]})
+            return df_sor_result_cal
+        start_time = time.time()
+        cellvolt_name = self.cellvolt_list#电芯数量
+        celltemp_name = self.celltemp_name#电芯温度数量
+        LookTab_OCV = self.LookTab_OCV
+        LookTab_SOC = self.LookTab_SOC
+        max_volt = max(LookTab_OCV)
+        min_volt = min(LookTab_OCV)
+        soc_interplt = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#OCV-SOC插值函数
+        data = self.df_bms
+        data.fillna(0, inplace=True)
+        df_sor_result = pd.DataFrame(columns = ["sn", "time", "sor", "sor_sigma", "soc", "temp", "delta_time"])
+        df_dschrg_data_temp = data.loc[data['充电状态'] == 3]#筛选放电数据
+        df_dschrg_data = df_dschrg_data_temp.reset_index(drop = True)
+        np_dschrg_time = pd.to_datetime(df_dschrg_data['时间戳'])
+        dff_dschrg_time = np.diff(np_dschrg_time)/pd.Timedelta(1, 'min')#放电过程前后时间差
+        rest_dschrg_pos = np.where(dff_dschrg_time > 30)#筛选前后时间差大于30min的位置及时间点,判断为两次放电  
+        df_dschrg_time = pd.to_datetime(df_dschrg_data['时间戳'])
+        df_origin_time = pd.to_datetime(data['时间戳'])
+        k = 1
+        if len(rest_dschrg_pos[0]) > 0:
+            if len(np_dschrg_time) > 0:
+                if rest_dschrg_pos[0][0] > 20:#首个放电过程采样点大于20
+                    if (df_dschrg_time.iloc[0] - df_origin_time.iloc[0])/pd.Timedelta(1, 'min') > 30:#对比数据中行车数据与充电后静置开始时间,确认初始静置时间是否充足
+                        df_rest_chrg_data_temp = data.loc[pd.to_datetime(data['时间戳']) < df_dschrg_time.iloc[0]]#筛选首次放电前的数据
+                        df_rest_chrg_data = df_rest_chrg_data_temp.reset_index(drop = True)
+                        df_zerocrnt_st_temp = df_rest_chrg_data.loc[df_rest_chrg_data['总电流[A]'] == 0]#电流为0的数据
+                        df_zerocrnt_st = df_zerocrnt_st_temp.reset_index(drop = True)
+                        df_nonzerocrnt_st_temp = df_rest_chrg_data.loc[df_rest_chrg_data['总电流[A]'] != 0]#电流非0的数据
+                        df_nonzerocrnt_st = df_nonzerocrnt_st_temp.reset_index(drop = True)
+                        df_time_zerocrnt = pd.to_datetime(df_zerocrnt_st['时间戳'])
+                        df_time_nonzerocrnt = pd.to_datetime(df_nonzerocrnt_st['时间戳'])
+                        if len(df_time_zerocrnt) != 0:
+                            if len(df_time_nonzerocrnt) == 0:#均是静置
+                                if (df_time_zerocrnt.iloc[-1] - df_time_zerocrnt.iloc[0])/pd.Timedelta(1, 'min') > 30:
+                                    df_sor_cal = data.loc[(pd.to_datetime(data['时间戳']) >= df_origin_time.iloc[-1]) & (pd.to_datetime(data['时间戳']) < df_origin_time.iloc[-1] + datetime.timedelta(minutes = 15))]#筛选首次放电前的数据
+                                    if len(df_sor_cal) > 20:
+                                        df_sor_result_temp = sor_cal_prog(df_sor_cal)
+                                        df_sor_result = df_sor_result.append(df_sor_result_temp)
+                                        df_sor_result.reset_index(drop = True, inplace = True)
+                            if len(df_time_nonzerocrnt) != 0:#存在充电
+                                if (df_time_zerocrnt.iloc[-1] - df_time_nonzerocrnt.iloc[-1])/pd.Timedelta(1, 'min') > 30:
+                                    df_sor_cal = data.loc[(pd.to_datetime(data['时间戳']) >= df_origin_time.iloc[-1]) & (pd.to_datetime(data['时间戳']) < df_origin_time.iloc[-1] + datetime.timedelta(minutes = 15))]#筛选首次放电前的数据
+                                    if len(df_sor_cal) > 20:
+                                        df_sor_result_temp = sor_cal_prog(df_sor_cal)
+                                        df_sor_result = df_sor_result.append(df_sor_result_temp)
+                                        df_sor_result.reset_index(drop = True, inplace = True)
+                for item in range(0, len(rest_dschrg_pos[0]) - 1):#
+                    #---------------------------------------------------判断放电数据是否足够计算-----------------------------------------------------------
+                    if (rest_dschrg_pos[0][item + 1] - rest_dschrg_pos[0][item]) > 20:#判断数据点个数,数据点过少的不计算
+                        #---------------------------------------------------判断静置时间是否充足--------------------------------------------------------------
+                        df_rest_chrg_data_temp = data.loc[(pd.to_datetime(data['时间戳']) > df_dschrg_time.iloc[rest_dschrg_pos[0][item]]) & 
+                                                        (pd.to_datetime(data['时间戳']) < df_dschrg_time.iloc[rest_dschrg_pos[0][item] + 1])]#筛选首次放电前的数据#筛选放电之间的数据段
+                        df_rest_chrg_data = df_rest_chrg_data_temp.reset_index(drop = True)
+                        df_zerocrnt_st_temp = df_rest_chrg_data.loc[df_rest_chrg_data['总电流[A]'] == 0]#电流为0的数据
+                        df_zerocrnt_st = df_zerocrnt_st_temp.reset_index(drop = True)
+                        df_nonzerocrnt_st_temp = df_rest_chrg_data.loc[df_rest_chrg_data['总电流[A]'] != 0]#电流非0的数据
+                        df_nonzerocrnt_st = df_nonzerocrnt_st_temp.reset_index(drop = True)
+                        df_time_zerocrnt = pd.to_datetime(df_zerocrnt_st['时间戳'])
+                        df_time_nonzerocrnt = pd.to_datetime(df_nonzerocrnt_st['时间戳'])
+                        st_caltime = time.time()
+                        print('第' + str(k) + '个内阻计算')
+                        k = k + 1
+                        if (len(df_zerocrnt_st) != 0):
+                            if ((df_time_zerocrnt.iloc[-1] - df_time_zerocrnt.iloc[0])/pd.Timedelta(1, 'min') > 30):#无电流最大最小时间差大于45分钟
+                                if (len(df_nonzerocrnt_st) == 0):#放电前的静置过程无电流
+                                    if df_dschrg_data['总电流[A]'].iloc[rest_dschrg_pos[0][item] + 1] != 0:#放电过程第一个数据的电流非0
+                                        df_sor_cal = data.loc[(pd.to_datetime(data['时间戳']) >= df_time_zerocrnt.iloc[-1]) & (pd.to_datetime(data['时间戳']) < df_time_zerocrnt.iloc[-1] + datetime.timedelta(minutes = 15))]#筛选首次放电前的数据
+                                        df_sor_result_temp = sor_cal_prog(df_sor_cal)
+                                        df_sor_result = df_sor_result.append(df_sor_result_temp)
+                                        df_sor_result.reset_index(drop = True, inplace = True)
+                                    if df_dschrg_data['总电流[A]'].iloc[rest_dschrg_pos[0][item] + 1] == 0:#放电阶段首个采样时刻无电流时,需选取放电过程中有电流的时间段
+                                        df_dschrg_item_temp = df_dschrg_data.iloc[(rest_dschrg_pos[0][item] + 1):rest_dschrg_pos[0][item + 1]]#放电数据
+                                        df_dschrg_item = df_dschrg_item_temp.reset_index(drop = True)
+                                        df_dschrg_crnt_data = df_dschrg_item.loc[df_dschrg_item['总电流[A]'] != 0]#有电流数据
+                                        if len(df_dschrg_crnt_data) > 0:
+                                            np_frst_crnt_pos = df_dschrg_crnt_data[df_dschrg_crnt_data['时间戳'] == df_dschrg_crnt_data['时间戳'].iloc[0]].index.tolist()#首个出现电流点
+                                            np_frst_crnt_time = pd.to_datetime(df_dschrg_item['时间戳'].iloc[np_frst_crnt_pos[0] - 1])
+                                            df_sor_cal = data.loc[(pd.to_datetime(data['时间戳']) >= np_frst_crnt_time) & (pd.to_datetime(data['时间戳']) < np_frst_crnt_time + datetime.timedelta(minutes = 15))]#筛选首次放电前的数据
+                                            df_sor_result_temp = sor_cal_prog(df_sor_cal)
+                                            df_sor_result = df_sor_result.append(df_sor_result_temp)
+                                            df_sor_result.reset_index(drop = True, inplace = True)
+                                if (len(df_nonzerocrnt_st) != 0):#有电流时需判断有电流的最后时刻与无电流的最后时刻的时间差
+                                    if ((df_time_zerocrnt.iloc[-1] - df_time_nonzerocrnt.iloc[-1])/pd.Timedelta(1, 'min') > 30):
+                                        if (len(df_nonzerocrnt_st) == 0):#放电前的静置过程无电流
+                                            df_sor_cal = data.loc[(pd.to_datetime(data['时间戳']) >= df_time_zerocrnt.iloc[-1]) & (pd.to_datetime(data['时间戳']) < df_time_zerocrnt.iloc[-1] + datetime.timedelta(minutes = 15))]#筛选首次放电前的数据
+                                            df_sor_result_temp = sor_cal_prog(df_sor_cal)
+                                            df_sor_result = df_sor_result.append(df_sor_result_temp)
+                                            df_sor_result.reset_index(drop = True, inplace = True)
+                                        if df_dschrg_data['总电流[A]'].iloc[rest_dschrg_pos[0][item] + 1] == 0:#放电阶段首个采样时刻无电流时,需选取放电过程中有电流的时间段
+                                            df_dschrg_item_temp = df_dschrg_data.iloc[(rest_dschrg_pos[0][item] + 1):rest_dschrg_pos[0][item + 1]]#放电数据
+                                            df_dschrg_item = df_dschrg_item_temp.reset_index(drop = True)
+                                            df_dschrg_crnt_data = df_dschrg_item.loc[df_dschrg_item['总电流[A]'] != 0]#有电流数据
+                                            if len(df_dschrg_crnt_data) > 0:
+                                                np_frst_crnt_pos = df_dschrg_crnt_data[df_dschrg_crnt_data['时间戳'] == df_dschrg_crnt_data['时间戳'].iloc[0]].index.tolist()#首个出现电流点
+                                                np_frst_crnt_time = pd.to_datetime(df_dschrg_item['时间戳'].iloc[np_frst_crnt_pos[0] - 1])
+                                                df_sor_cal = data.loc[(pd.to_datetime(data['时间戳']) >= np_frst_crnt_time) & (pd.to_datetime(data['时间戳']) < np_frst_crnt_time + datetime.timedelta(minutes = 15))]#筛选首次放电前的数据
+                                                df_sor_result_temp = sor_cal_prog(df_sor_cal)
+                                                df_sor_result = df_sor_result.append(df_sor_result_temp)
+                                                df_sor_result.reset_index(drop = True, inplace = True)
+                        end_caltime = time.time()
+                        print(end_caltime - st_caltime)
+        end_time = time.time()
+        print(end_time - start_time)
+        if not df_sor_result.empty:
+            return df_sor_result
+        else:
+            return pd.DataFrame()

Файловите разлики са ограничени, защото са твърде много
+ 275 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/vol_sor_est.ipynb


+ 24 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/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=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\01算法开发\\'+self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

+ 165 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/main.py

@@ -0,0 +1,165 @@
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+import time, datetime
+from apscheduler.schedulers.blocking import BlockingScheduler
+from pandas.core.frame import DataFrame
+import matplotlib as plt
+from pylab import*
+import vol_sor_est
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+import log
+
+#...................................电池包电芯安全诊断函数......................................................................................................................
+def cell_volsor_test():
+    global SNnums
+    global df_diag_sor
+    global df_diag_vol
+    global df_diag_volsor
+    start=time.time()
+    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=3)
+    end_time=str(now_time)
+    start_time=str(start_time)
+    k = 1
+    for sn in SNnums:
+        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三元电芯
+        elif 'TJMCL' in sn: 
+            celltype=100 #金茂电芯
+        else:
+            print('SN:{},未找到对应电池类型!!!'.format(sn))
+            continue
+            # sys.exit()
+        print('计算的第' + str(k) + '个:' + sn)
+        k = k + 1
+        #读取原始数据库数据........................................................................................................................................................
+        start_time = '2021-12-01 00:00:00'
+        end_time = '2021-12-04 00:00:00'
+        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']
+        df_del_sor_add = pd.DataFrame()
+        df_del_vol_add = pd.DataFrame()
+        df_diag_sor_add = pd.DataFrame()
+        df_diag_vol_add = pd.DataFrame() 
+        param = BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        cellvolt_name=['单体电压'+str(x) for x in range(1,param.CellVoltNums+1)]
+        #........................................................电压内阻估计.....................................................................
+        if not df_bms.empty:
+            Diag_sorvol_temp = vol_sor_est.vol_sor_est(sn,celltype,df_bms)#电压内阻估计
+            [df_del_sor_add, df_del_vol_add, df_diag_sor_add, df_diag_vol_add, df_diag_sorvol_add] = Diag_sorvol_temp.volsor_cal()        
+            if not df_del_sor_add.empty:
+                #..................................................估计电压内阻作图.........................................................
+                m = max(df_del_sor_add['dischrgr_num'] + 1)
+                for i in range(1,m):#m
+                    df_time_data = []
+                    fig = plt.figure(figsize=(20,10))
+                    df_fig = df_del_sor_add.loc[df_del_sor_add['dischrgr_num'] == i]
+                    df_fig.reset_index(drop = True, inplace = True)
+                    length = len(df_fig)
+                    df_time = pd.to_datetime(df_fig['时间戳'])
+                    for df_time_num in range(0, length):
+                        df_time_data.append(df_time[df_time_num].strftime('%H:%M:%S'))
+                    for volt_num in cellvolt_name:
+                        plt.plot(df_time_data, df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+                    mpl.rcParams['font.sans-serif']=['SimHei']
+                    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+                    plt.legend(fontsize=18)
+                    title = sn + '-内阻估计' + df_time[0].strftime('%Y-%m-%d') #df_fig['device_id'][0] + '-' + 
+                    plt.xlabel('时间', fontsize=24)
+                    plt.ylabel('估计电压与电压均值偏离度', fontsize=24)
+                    plt.xticks(df_time_data[0:(length-1):20],fontsize=20,rotation = 45)
+                    plt.yticks(fontsize=20)
+                    plt.title(title, fontsize=30)
+                    plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\估计内阻\\'+title+'.png', dpi=300)
+                for i in range(1,m):#m
+                    df_time_data = []
+                    fig = plt.figure(figsize=(20,10))
+                    df_fig = df_del_vol_add.loc[df_del_vol_add['dischrgr_num'] == i]
+                    df_fig.reset_index(drop = True, inplace = True)
+                    length = len(df_fig)
+                    df_time = pd.to_datetime(df_fig['时间戳'])
+                    for df_time_num in range(0, length):
+                        df_time_data.append(df_time[df_time_num].strftime('%H:%M:%S'))
+                    for volt_num in cellvolt_name:
+                        plt.plot(df_time_data, df_fig[volt_num],linewidth = 2, linestyle = '-', marker = 's',label=volt_num)
+                    mpl.rcParams['font.sans-serif']=['SimHei']
+                    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
+                    plt.legend(fontsize=18)
+                    title = sn + '电压估计' + df_time[0].strftime('%Y-%m-%d') #df_fig['device_id'][0] + '-' + 
+                    plt.xlabel('时间', fontsize=24)
+                    plt.ylabel('估计电压与电压均值偏离度', fontsize=24)
+                    plt.xticks(df_time_data[0:(length-1):20],fontsize=20,rotation = 45)
+                    plt.yticks(fontsize=20)
+                    plt.title(title, fontsize=30)
+                    plt.savefig(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\估计电压\\'+title+'.png', dpi=300)
+            if not df_diag_sor_add.empty:
+                df_diag_sor = df_diag_sor.append(df_diag_sor_add)
+                df_diag_sor = df_diag_sor.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)
+                df_diag_sor.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\内阻偏离.csv',index=False,encoding='GB18030')
+            if not df_diag_vol_add.empty:
+                df_diag_vol = df_diag_vol.append(df_diag_vol_add)
+                df_diag_vol = df_diag_vol.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)
+                df_diag_vol.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\电压偏离.csv',index=False,encoding='GB18030')
+            if not df_diag_sorvol_add.empty:
+                df_diag_volsor = df_diag_volsor.append(df_diag_sorvol_add)
+                df_diag_volsor = df_diag_volsor.drop_duplicates(subset = ['sn','time'], keep = 'first', inplace = False)
+                df_diag_volsor.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\电压内阻偏离.csv',index=False,encoding='GB18030')
+        end=time.time()
+        print(end-start)
+        
+
+#...............................................主函数...............................................................................................
+if __name__ == "__main__":
+    global SNnums
+    global df_diag_sor
+    global df_diag_vol
+    global df_diag_volsor
+    
+    excelpath=r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\00项目sn号\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_6040 + SNnums_4840 + SNnums_U7255+ SNnums_6060
+    # SNnums=['TJMCL120502305010','TJMCL120502305012','TJMCL120502305048','TJMCL120502305044','TJMCL120502305026','TJMCL120502305022','TJMCL120502305032','TJMCL120502305038']
+    SNnums = ['PK504B00100004003'] #SNnums_6040 #SNnums_C7255 #SNnums_6040['MGMCLN750N215N049'] 
+    # SNnums = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\liplated\疑似析锂电池sn.csv',encoding='GB18030')
+    
+    mylog=log.Mylog('log_diag.txt','error')
+    mylog.logcfg()
+    #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取................
+    df_diag_sor = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\内阻偏离.csv',encoding='GB18030')
+    df_diag_vol = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\电压偏离.csv',encoding='GB18030')
+    df_diag_volsor = pd.read_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\电压内阻偏离.csv',encoding='GB18030')
+    
+    print('----------------输入--------')
+    print('-------计算中-----------')
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(cell_volsor_test, 'interval', seconds=10, id='diag_job')
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        print(repr(e))
+        mylog.logopt(e)

Файловите разлики са ограничени, защото са твърде много
+ 275 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/vol_sor_est.ipynb


+ 255 - 0
USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻电压联合估计/vol_sor_est.py

@@ -0,0 +1,255 @@
+import pandas as pd
+import numpy as np
+import datetime
+import time, datetime
+import scipy
+import math
+import itertools
+import log
+from scipy.signal import savgol_filter
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
+
+class vol_sor_est:
+    def __init__(self,sn,celltype,df_bms):  #参数初始化
+
+        self.sn=sn
+        self.celltype=celltype
+        self.param=BatParam.BatParam(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
+        self.df_bms=pd.DataFrame(df_bms)
+        self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+
+        self.cellvolt_list=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
+        self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
+        self.bmssta = df_bms['充电状态']
+    #定义加权滤波函数..................................................................................................
+    def moving_average(interval, windowsize):
+        window = np.ones(int(windowsize)) / float(windowsize)
+        re = np.convolve(interval, window, 'same')
+        return re
+#.............................................内阻及电压估计............................................................................
+    def volsor_cal(self):
+        start_time = time.time()
+        dischrg_data_temp = self.df_bms.loc[(self.df_bms['充电状态'] == 3) & (self.df_bms['SOC[%]'] > 50)]#放电数据&(self.df_bms['总电流[A]'] > 0.1)
+        dischrg_data = dischrg_data_temp.reset_index(drop=True)
+        df_voltout_result = pd.DataFrame(columns = ['sn','time','volout_confr','volout_amplt'])
+        if not dischrg_data_temp.empty:
+            temp_rest_time = dischrg_data['时间戳']
+            rest_time = pd.to_datetime(temp_rest_time)
+            delta_time = (np.diff(rest_time)/pd.Timedelta(1, 'min'))#计算时间差的分钟数
+            pos = np.where(delta_time > 10)
+            pos_ful_tem = np.insert(pos, 0, 0)
+            pos_len = len(pos_ful_tem)
+            data_len = len(rest_time)
+            pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
+            splice_num = []
+            for item in range(0,len(pos_ful)-1):
+                splice_num.extend(item*np.ones(pos_ful[item +1]-pos_ful[item]))
+            splice_num = np.insert(splice_num, 0, 0)
+            dischrg_data_temp['dischrgr_rest'] = splice_num
+            #---------------------------对分段数据使用RLS算法估计电压及内阻-------------------------------------------
+            def theta2RC(theta, dt):
+                #计算电池OCV及阻值
+                OCV = theta[0,0] / (1-theta[0,1])
+                R0 = (theta[0,3] - theta[0,2]) / (1 + theta[0,1])
+                R1 = -(theta[0,3] + theta[0,2]) / (1 - theta[0,1]) - R0
+                Tau = dt/2*(1 + theta[0,1]) / (1 - theta[0,1])
+                return [OCV,R0,R1,Tau]
+            cellvolt_name = self.cellvolt_list
+            dischrgr_check_data = dischrg_data_temp.drop(['GSM信号','故障等级','故障代码','单体压差','绝缘电阻','总电压[V]','充电状态','单体压差'],axis=1,inplace=False)
+            dischrgr_check_data.fillna(value=0)
+            df_est_vol_ful = pd.DataFrame()
+            df_est_sor_ful = pd.DataFrame()
+            k = 0
+            print(len(pos_ful))
+            for i in range(0,len(pos_ful)):#len(pos_ful)-1#每段放电数据计算
+                df_distest_data_temp = dischrgr_check_data.loc[dischrgr_check_data['dischrgr_rest'] == i]
+                df_distest_data = df_distest_data_temp.reset_index(drop = True)
+                df_distime = pd.to_datetime(df_distest_data['时间戳'])
+                df_disvolt = df_distest_data[cellvolt_name]/1000
+                df_discrnt = df_distest_data['总电流[A]']
+                df_dissoc = df_distest_data['SOC[%]']
+                df_est_vol = pd.DataFrame()
+                df_est_sor = pd.DataFrame()
+                if len(df_discrnt) > 120:
+                    end = time.time()
+                    print('第' + str(k) + '段数据' + str(df_distime[0]))
+                    print(end - start_time)
+                    for item in cellvolt_name:#每个电芯的循环计算
+                        dt_temp = np.diff(df_distime)/pd.Timedelta(1, 'seconds')
+                        data_len = len(dt_temp)#时间微分后的长度
+                        dt = np.append(dt_temp, dt_temp[data_len-1])#计算时间间隔并补充
+                        crnt = df_discrnt
+                        Ut = df_disvolt[item]
+                        unit_mat = np.mat(np.eye(4))
+
+                        for j in range(data_len + 1):#每个电芯的实际计算过程
+                            theta = [3.4, 0.448, -0.0108, 0.0106]
+                            P = np.mat(10**6*np.eye(4))
+                            lambd = 0.96
+                            Err = [0]
+                            Err2 = [0]*(data_len + 1)
+                            OCV = [0]
+                            R0 = [0]
+                            R1 = [0]
+                            Tau = [0]
+                            Theta = np.mat(np.zeros([data_len + 1, 4]))
+                            Theta[0,:] = theta
+                            U1 = [0]
+                            Vt = [0]
+                            for m in range(1,data_len + 1):
+                                phi = np.mat([1 , Ut[m], crnt[m], crnt[m-1]]).T #测量向量4×1的向量
+                                K = np.dot(P, phi)/(lambd + np.dot(np.dot(phi.T, P),phi)) #增益的递推公式,为4×1的向量
+                                P = np.dot((unit_mat - np.dot(K, phi.T)),P)/lambd #协方差矩阵的递归公式
+                                Err.append(Ut[m] - np.dot(Theta[m-1,:], phi)) #误差
+                                theta = Theta[m-1, :] + Err[m]*K.T #待估向量theta的递归公式
+                                Theta[m,:] = theta #theta估计向量矩阵化
+                                [ocv,r0,r1,tau] = theta2RC(Theta[m,:], dt[m])
+                                Errtemp = []
+                                for ss in range(0, min(m-1, 29) + 1):
+                                    ocv,r0,r1,tau = theta2RC(Theta[m - ss, :], dt[m])
+                                    U1.append(U1[m-1]*math.exp(-dt[m]/tau) + (1 - math.exp(-dt[m]/tau))*r1*crnt[m])
+                                    Vt.append(ocv - U1[m] - crnt[m]*r0)
+                                    Err2[m] = Ut[m] - Vt[m]
+                                    if abs(Err2[m] <= 0.05):
+                                        break
+                                    elif ss == 29:
+                                        id, Err2[m] = min(enumerate(Errtemp))
+                                        [ocv,r0,r1,tau] = theta2RC(Theta[m - id, :], dt[m])
+                                    else:
+                                        Errtemp.append(abs(Err2[m]))
+                                OCV.append(ocv)
+                                R0.append(r0)
+                                R1.append(r1)
+                                Tau.append(tau)
+                        df_est_vol[item] = OCV
+                        df_est_sor[item] = R0
+                    df_est_vol['dischrgr_num'] = k
+                    df_est_vol['时间戳'] = df_distest_data['时间戳']
+                    df_est_sor['dischrgr_num'] = k
+                    df_est_sor['时间戳'] = df_distest_data['时间戳']
+                    k = k + 1
+                    df_est_vol_ful = df_est_vol_ful.append(df_est_vol)
+                    df_est_sor_ful = df_est_sor_ful.append(df_est_sor)
+            df_est_vol_ful.reset_index(drop = True)
+            df_est_sor_ful.reset_index(drop = True)
+            #---------------------------------------------------------统计内阻及电压估计状态-------------------------------------------------------
+            df_voltout_result = pd.DataFrame(columns = ['sn','time','volout_confr','volout_amplt'])
+            df_sortout_result = pd.DataFrame(columns = ['sn','time','sorout_confr','sorout_amplt'])
+            df_volsortout_result = pd.DataFrame(columns = ['sn','time','volsorout_confr','volsorout_amplt'])
+            df_delt_vol_total = pd.DataFrame()
+            df_delt_sor_total = pd.DataFrame()
+            m = 1
+            for i in range(0,k):#有多少段数据
+                df_ana_vol_temp = df_est_vol_ful.loc[df_est_vol_ful['dischrgr_num'] == i].reset_index(drop = True)#选取某段数据
+                df_ana_sor_temp = df_est_sor_ful.loc[df_est_sor_ful['dischrgr_num'] == i].reset_index(drop = True)#选取某段数据
+                df_vol_cho = df_ana_vol_temp[cellvolt_name[0]]#挑选某个电池的估计电压,判断估计范围是否正常
+                df_vol_logi = [(df_vol_cho > 2.5) & (df_vol_cho < 4.3)]
+                df_vol_arr = np.array(df_vol_logi).astype(int)
+                df_vol_cho_logi = df_vol_arr[0]
+                num_times = [(k, len(list(v))) for k, v in itertools.groupby(df_vol_cho_logi)]
+                num_times_len = len(num_times)
+                fitter_len = num_times[num_times_len - 1][1]#拟合好后的数据长度
+                ini_len = len(df_vol_cho)#初始数据长度
+                if (num_times[num_times_len - 1][0] == 1) & (num_times[num_times_len - 1][1] > 0.6*fitter_len):
+                    df_delt_vol_accum = pd.DataFrame()
+                    df_delt_sor_accum = pd.DataFrame()
+                    df_delt_vol = pd.DataFrame()
+                    df_delt_sor = pd.DataFrame()
+                    volout_confr = []#偏离与否
+                    volout_amplt = []#偏离幅度
+                    sorout_confr = []#偏离与否
+                    sorout_amplt = []#偏离幅度
+                    volsorout_confr = []
+                    volsorout_amplt = []
+                    df_ana_vol_spl = df_ana_vol_temp[(ini_len-fitter_len):(ini_len-1)]#筛选出拟合至合理范围的电压及内阻
+                    df_ana_sor_spl = df_ana_sor_temp[(ini_len-fitter_len):(ini_len-1)]
+                    df_ana_vol = df_ana_vol_spl[cellvolt_name]#筛选出的拟合电压在合理范围内的数据
+                    df_ana_sor = df_ana_sor_spl[cellvolt_name]
+                    df_ana_vol_min = np.min(df_ana_vol, axis = 1)
+                    df_ana_vol_max = np.max(df_ana_vol, axis = 1)
+                    df_ana_sor_max = np.max(df_ana_sor, axis = 1)
+                    df_ana_sor_min = np.min(df_ana_sor, axis = 1)
+                    df_ana_vol_mean = (np.sum(df_ana_vol, axis = 1) - df_ana_vol_min - df_ana_vol_max)/(df_ana_vol.shape[1] - 2)#估计电压均值
+                    df_ana_sor_mean = (np.sum(df_ana_sor, axis = 1) - df_ana_sor_min - df_ana_sor_max)/(df_ana_sor.shape[1] - 2)#估计内阻均值
+                    for item in cellvolt_name:
+                        df_delt_vol[item] = df_ana_vol[item] - df_ana_vol_mean#计算各电芯拟合电压与同时刻电压均值的差值
+                        df_delt_sor[item] = df_ana_sor[item] - df_ana_sor_mean
+                    df_delt_vol_min = np.min(df_delt_vol, axis = 1)
+                    df_delt_vol_max = np.max(df_delt_vol, axis = 1)
+                    df_delt_sor_min = np.min(df_delt_sor, axis = 1)
+                    df_delt_sor_max = np.max(df_delt_sor, axis = 1)
+                    df_delt_vol_mean = (np.sum(df_delt_vol, axis = 1) - df_delt_vol_min - df_delt_vol_max)/(df_delt_vol.shape[1] - 2)#估计电压差值的均值
+                    df_delt_sor_mean = (np.sum(df_delt_sor, axis = 1) - df_delt_sor_min - df_delt_sor_max)/(df_delt_sor.shape[1] - 2)#估计电压差值的均值
+                    df_delt_vol_std = np.std(df_delt_vol, axis = 1)
+                    df_delt_sor_std = np.std(df_delt_sor, axis = 1)
+                    df_delt_data_len = len(df_delt_vol_std)
+                    for cell_num in cellvolt_name:
+                        df_delt_vol_cal = (df_delt_vol[cell_num] - df_delt_vol_mean)/df_delt_vol_std#计算每个电压与均值的偏差
+                        df_delt_sor_cal = (df_delt_sor[cell_num] - df_delt_sor_mean)/df_delt_sor_std#计算每个内阻与均值的偏差
+                        df_delt_vol_confr = abs(df_delt_vol_cal) > 3#电压估计值与均值差值大于3sigma
+                        df_delt_sor_confr = abs(df_delt_sor_cal) > 3#电压估计值与均值差值大于3sigma
+                        df_delt_vol_confr_num = np.sum(df_delt_vol_confr!=0)#统计电压离群度的非零数
+                        df_delt_sor_confr_num = np.sum(df_delt_sor_confr!=0)#统计电阻离群度的非零数
+                        df_delt_vol_sor_cal = df_delt_vol_cal*df_delt_sor_cal
+                        df_delt_vol_sor_confr = abs(df_delt_vol_sor_cal) > 9#电压估计值内阻估计值乘积与均值差值大于3sigma
+                        df_delt_vol_sor_confr_num = np.sum(df_delt_vol_sor_confr!=0)#统计非零数
+                        df_length_limit = df_delt_data_len/10
+                        df_delt_vol_accum = pd.concat([df_delt_vol_accum, df_delt_vol_cal], axis = 1)
+                        df_delt_sor_accum = pd.concat([df_delt_sor_accum, df_delt_sor_cal], axis = 1)
+                        if df_delt_vol_confr_num > df_length_limit:
+                            volout_confr.append(1)#1为偏离,0为非偏离
+                            volout_amplt.append(max(abs(df_delt_vol_cal)))#偏离度
+                        else:
+                            volout_confr.append(0)#1为偏离,0为非偏离
+                            volout_amplt.append(0)#偏离度
+                        if df_delt_sor_confr_num > df_length_limit:
+                            sorout_confr.append(1)#1为偏离,0为非偏离
+                            sorout_amplt.append(max(abs(df_delt_vol_cal)))#偏离度
+                        else:
+                            sorout_confr.append(0)#1为偏离,0为非偏离
+                            sorout_amplt.append(0)#偏离度
+                        if df_delt_vol_sor_confr_num > df_length_limit:
+                            volsorout_confr.append(1)
+                            volsorout_amplt.append(max(abs(df_delt_vol_sor_cal)))#偏离度
+                        else:
+                            volsorout_confr.append(0)
+                            volsorout_amplt.append(0)#偏离度
+                    df_delt_vol_accum.columns = cellvolt_name
+                    df_delt_sor_accum.columns = cellvolt_name
+                    df_delt_vol_accum['dischrgr_num'] = m
+                    df_delt_sor_accum['dischrgr_num'] = m
+                    df_delt_vol_accum['时间戳'] = list(df_ana_vol_spl['时间戳'])
+                    df_delt_sor_accum['时间戳'] = list(df_ana_vol_spl['时间戳'])
+                    m = m + 1
+                    if any(volout_confr):
+                        df_volout_temp = pd.DataFrame({"sn":[self.sn], "time":[df_ana_vol_temp['时间戳'][0]], "volout_confr":[str(volout_confr)], "volout_amplt":[str(volout_amplt)]})
+                        df_voltout_result = df_voltout_result.append(df_volout_temp)
+                        df_voltout_result = df_voltout_result.reset_index(drop = True)
+                        df_voltout_result.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+                        # df_voltout_result.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\电压偏离.csv',index=False,encoding='GB18030')
+                    if any(sorout_confr):
+                        df_sorout_temp = pd.DataFrame({"sn":[self.sn], "time":[df_ana_vol_temp['时间戳'][0]], "sorout_confr":[str(sorout_confr)], "sorout_amplt":[str(sorout_amplt)]})
+                        df_sortout_result = df_sortout_result.append(df_sorout_temp)
+                        df_sortout_result = df_sortout_result.reset_index(drop = True)
+                        df_sortout_result.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+                        # df_sortout_result.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\内阻偏离.csv',index=False,encoding='GB18030')
+                    if any(volsorout_confr):
+                        df_volsorout_temp = pd.DataFrame({"sn":[self.sn], "time":[df_ana_vol_temp['时间戳'][0]], "volsorout_confr":[str(volsorout_confr)], "volsorout_amplt":[str(volsorout_amplt)]})
+                        df_volsortout_result = df_volsortout_result.append(df_volsorout_temp)
+                        df_volsortout_result = df_volsortout_result.reset_index(drop = True)
+                        df_volsortout_result.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
+                        # df_volsortout_result.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\05内阻及电压估计\02算法检测\判断结果\电压内阻偏离.csv',index=False,encoding='GB18030')
+                df_delt_vol_total = df_delt_vol_total.append(df_delt_vol_accum)
+                df_delt_vol_total.reset_index(drop = True, inplace = True)
+                df_delt_sor_total = df_delt_sor_total.append(df_delt_sor_accum)
+                df_delt_sor_total.reset_index(drop = True, inplace = True)
+        end_time = time.time()
+        print(end_time - start_time)
+        if not df_voltout_result.empty:
+            return [df_delt_sor_total, df_delt_vol_total, df_sortout_result, df_voltout_result, df_volsortout_result]
+        else:
+            return [pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame()]
+        #----------------------------------------------------对估计电压及内阻作图-----------------------------------------------------------------

Някои файлове не бяха показани, защото твърде много файлове са промени