浏览代码

Merge branch 'dev' of http://git.fast-fun.cn:92/lmstack/data_analyze_platform into dev

Eric412V 1 年之前
父节点
当前提交
5f8cc9bf0f
共有 100 个文件被更改,包括 10088 次插入62 次删除
  1. 178 0
      LIB/FRONTEND/FaultDetection/main_pred.py
  2. 3 0
      LIB/FRONTEND/FaultDetection/run.bat
  3. 2 2
      LIB/MIDDLE/CellStateEstimation/BatSafetyWarning/V1_0_1/CBMSSafetyWarning.py
  4. 41 33
      LIB/MIDDLE/CellStateEstimation/BatSafetyWarning/main.py
  5. 452 0
      LIB/MIDDLE/FaultClass/V1_0_0/faultclass.py
  6. 42 0
      LIB/MIDDLE/FaultClass/V1_0_0/main_input.py
  7. 164 0
      LIB/MIDDLE/FaultClass/V1_0_0/main_pred.py
  8. 158 0
      LIB/MIDDLE/FaultClass/V1_0_0/main_train.py
  9. 二进制
      LIB/MIDDLE/FaultClass/V1_0_0/models/model_B板采样失效.h5
  10. 二进制
      LIB/MIDDLE/FaultClass/V1_0_0/models/model_传感器_电芯NTC漂移.h5
  11. 二进制
      LIB/MIDDLE/FaultClass/V1_0_0/models/model_电压采样断线.h5
  12. 二进制
      LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_B板采样失效.pkl
  13. 二进制
      LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_传感器_电芯NTC漂移.pkl
  14. 二进制
      LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_电压采样断线.pkl
  15. 262 0
      LIB/MIDDLE/FaultDetection/V1_0_2/aelstm.py
  16. 179 0
      LIB/MIDDLE/FaultDetection/V1_0_2/main_pred.py
  17. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_MGMCL_10.h5
  18. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_MGMLX_10.h5
  19. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_PK500_10.h5
  20. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_PK502_10.h5
  21. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_PK504_10.h5
  22. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_MGMCL_10.h5
  23. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_MGMLX_10.h5
  24. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_PK500_10.h5
  25. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_PK502_10.h5
  26. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_PK504_10.h5
  27. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_MGMCL_10.pkl
  28. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_MGMLX_10.pkl
  29. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_PK500_10.pkl
  30. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_PK502_10.pkl
  31. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_PK504_10.pkl
  32. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_MGMCL_10.pkl
  33. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_MGMLX_10.pkl
  34. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_PK500_10.pkl
  35. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_PK502_10.pkl
  36. 二进制
      LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_PK504_10.pkl
  37. 27 2
      LIB/MIDDLE/InfoChrgDrive/Charge/V1_0_0/coreV0.py
  38. 二进制
      LIB/MIDDLE/InfoChrgDrive/Charge/kmeans4.pkl
  39. 二进制
      LIB/MIDDLE/InfoChrgDrive/Charge/kmeans5.pkl
  40. 65 25
      LIB/MIDDLE/InfoChrgDrive/Charge/main_V0.py
  41. 283 0
      LIB/MIDDLE/ThermoRunaway/V1_0_2/Trunaway.py
  42. 167 0
      LIB/MIDDLE/ThermoRunaway/V1_0_2/main_pred.py
  43. 二进制
      LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_MGMCL_05.h5
  44. 二进制
      LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_PK500_05.h5
  45. 二进制
      LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_PK504_05.h5
  46. 二进制
      LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_MGMCL_05.pkl
  47. 二进制
      LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_PK500_05.pkl
  48. 二进制
      LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_PK504_05.pkl
  49. 16 0
      USER/LZX/01算法开发/.vscode/launch.json
  50. 129 0
      USER/LZX/01算法开发/01电压排序/01算法/BatParam.py
  51. 276 0
      USER/LZX/01算法开发/01电压排序/01算法/CBMSBatChrg.py
  52. 276 0
      USER/LZX/01算法开发/01电压排序/01算法/CBMSBatChrgcopy.py
  53. 157 0
      USER/LZX/01算法开发/01电压排序/01算法/QX_BatteryParam.py
  54. 24 0
      USER/LZX/01算法开发/01电压排序/01算法/log.py
  55. 58 0
      USER/LZX/01算法开发/01电压排序/01算法/main.py
  56. 161 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopy.py
  57. 274 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopycopy.py
  58. 95 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopycopycopy.py
  59. 101 0
      USER/LZX/01算法开发/01电压排序/01算法/maincopyvoltrange.py
  60. 71 0
      USER/LZX/01算法开发/01电压排序/01算法/mainvoltrange.py
  61. 14 0
      USER/LZX/01算法开发/01电压排序/01算法/test.py
  62. 61 0
      USER/LZX/01算法开发/01电压排序/01算法/voltrange.py
  63. 29 0
      USER/LZX/01算法开发/01电压排序/01算法/voltrangecopy.py
  64. 24 0
      USER/LZX/01算法开发/02析锂检测/01下载数据/log.py
  65. 84 0
      USER/LZX/01算法开发/02析锂检测/01下载数据/main.py
  66. 78 0
      USER/LZX/01算法开发/02析锂检测/01下载数据/plot.py
  67. 132 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/chrgr_soc_confrm.py
  68. 329 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/data_analy.py
  69. 24 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/log.py
  70. 101 0
      USER/LZX/01算法开发/02析锂检测/03车辆分析/main.py
  71. 728 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/chrgr_state.ipynb
  72. 128 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/chrgr_statics_pack.py
  73. 24 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/log.py
  74. 105 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/main.py
  75. 133 0
      USER/LZX/01算法开发/02析锂检测/04充电行为/soc_total.py
  76. 221 0
      USER/LZX/01算法开发/02析锂检测/liplated/BatParam.py
  77. 557 0
      USER/LZX/01算法开发/02析锂检测/liplated/CBMSBatDiag.py
  78. 168 0
      USER/LZX/01算法开发/02析锂检测/liplated/Li_plated.py
  79. 84 0
      USER/LZX/01算法开发/02析锂检测/liplated/SC_SamplingSafty.py
  80. 185 0
      USER/LZX/01算法开发/02析锂检测/liplated/liplated_range.py
  81. 316 0
      USER/LZX/01算法开发/02析锂检测/liplated/liplited_test.py
  82. 24 0
      USER/LZX/01算法开发/02析锂检测/liplated/log.py
  83. 100 0
      USER/LZX/01算法开发/02析锂检测/liplated/main.py
  84. 71 0
      USER/LZX/01算法开发/02析锂检测/析锂检测/liplated_test.ipynb
  85. 65 0
      USER/LZX/01算法开发/02析锂检测/析锂检测/liplated_test2.ipynb
  86. 52 0
      USER/LZX/01算法开发/03电压信息熵/01算法开发/entropy.ipynb
  87. 208 0
      USER/LZX/01算法开发/04故障诊断/BatParam.py
  88. 557 0
      USER/LZX/01算法开发/04故障诊断/CBMSBatDiag.py
  89. 63 0
      USER/LZX/01算法开发/04故障诊断/FeiShuData.py
  90. 66 0
      USER/LZX/01算法开发/04故障诊断/GetFeiShuData.py
  91. 157 0
      USER/LZX/01算法开发/04故障诊断/QX_BatteryParam.py
  92. 84 0
      USER/LZX/01算法开发/04故障诊断/SC_SamplingSafty.py
  93. 491 0
      USER/LZX/01算法开发/04故障诊断/diagfault/CBMSBatDiag.py
  94. 84 0
      USER/LZX/01算法开发/04故障诊断/diagfault/SC_SamplingSafty.py
  95. 164 0
      USER/LZX/01算法开发/04故障诊断/diagfault/main.py
  96. 224 0
      USER/LZX/01算法开发/04故障诊断/main.py
  97. 235 0
      USER/LZX/01算法开发/04故障诊断/maincopy.py
  98. 178 0
      USER/LZX/01算法开发/04故障诊断/maincopy_v1.py
  99. 55 0
      USER/LZX/01算法开发/04故障诊断/test.py
  100. 24 0
      USER/LZX/01算法开发/05内阻及电压估计/01算法开发/内阻估计/log.py

+ 178 - 0
LIB/FRONTEND/FaultDetection/main_pred.py

@@ -0,0 +1,178 @@
+
+from LIB.MIDDLE.FaultDetection.V1_0_2.aelstm import *
+import pymysql
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager
+dbManager = DBManager.DBManager()
+from sqlalchemy import create_engine
+from urllib import parse
+import datetime, time
+from apscheduler.schedulers.blocking import BlockingScheduler
+import traceback
+import pickle
+from keras.models import load_model
+import logging
+import logging.handlers
+import os
+import re
+
+
+#...................................故障检测函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global scaler_dict, scaler2_dict, model_dict, model2_dict
+
+    start=time.time()
+    now_time=datetime.datetime.now()
+    start_time=now_time-datetime.timedelta(hours=3)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=now_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    #数据库配置
+    host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+    port=3306
+    db='safety_platform'
+    user='qx_read'
+    password='Qx@123456'
+
+    #读取结果库数据......................................................
+    param='product_id,start_time,end_time,diff_min,SOC,AnoScoreV_sum_max,AnoScoreV_max_max,AnoScoreT_sum_max,AnoScoreT_max_max'
+    tablename='fault_detection'
+    mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+    cursor = mysql.cursor()
+    sql =  "select {} from {} where end_time='0000-00-00 00:00:00'".format(param,tablename)
+    cursor.execute(sql)
+    res = cursor.fetchall()
+    df_diag_ram= pd.DataFrame(res,columns=param.split(','))
+    
+
+    db_res_engine = create_engine(
+        "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
+            user, parse.quote_plus(password), host, port, db
+        ))
+
+
+    #调用主函数................................................................................................................................................................
+    for sn in SNnums:
+        try:
+            group=sn[:5]
+            df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms'])
+            data_bms = df_data['bms']
+            data_bms['sn']=sn
+            if len(data_bms)>0:
+                logger.info("SN: {} 数据开始预处理".format(sn))
+                data_stand=data_groups(data_bms,sn,start_time,end_time)
+                df_stand=split(data_stand)   
+                res=pd.DataFrame()
+                if len(df_stand)>0:
+                    #读取训练产出的缩放指标:均值&方差
+                    logger.info("SN: {} 数据开始模型预测".format(sn))
+                    scaler = scaler_dict[group]
+                    scaler2 = scaler2_dict[group]
+                    #读取训练产出的模型状态空间:电压模型&温度模型
+                    model = model_dict[group]
+                    model2 = model2_dict[group]
+                    res=prediction(df_stand,scaler,scaler2,model,model2)
+                    if len(res)>0:
+                        df_res2,diff=threshold(res,group,end_time)
+                        df_diag_ram_sn=df_diag_ram[df_diag_ram['product_id']==sn]
+                        if not df_diag_ram_sn.empty:   #该sn相关结果非空
+                            new_res,update_res=arrange(df_res2,df_diag_ram_sn,start_time,diff)
+                            if len(update_res)>0:
+                                cursor.execute("DELETE FROM fault_detection WHERE end_time = '0000-00-00 00:00:00' and product_id='{}'".format(sn))
+                                mysql.commit()
+                                update_res.to_sql("fault_detection",con=db_res_engine, if_exists="append",index=False)
+                            #新增结果存入结果库................................................................
+                            if len(new_res)>0:
+                                new_res.to_sql("fault_detection",con=db_res_engine, if_exists="append",index=False)
+                        else:
+                            df_res2.to_sql("fault_detection",con=db_res_engine, if_exists="append",index=False)
+
+            # end=time.time()
+            # print(end-start)  
+                
+        except Exception as e:
+            logger.error(str(e))
+            logger.error(traceback.format_exc())
+
+    cursor.close()
+    mysql.close()
+
+#...............................................主函数起定时作用.......................................................................................................................
+if __name__ == "__main__":
+    
+    # 日志
+    log_path = 'log/'
+    if not os.path.exists(log_path):
+        os.makedirs(log_path)
+    logger = logging.getLogger("main")
+    logger.setLevel(logging.DEBUG)
+    
+     # 根据日期滚动(每天产生1个文件)
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_info.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.INFO)
+    logger.addHandler(fh)
+
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_error.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.ERROR)
+    logger.addHandler(fh)
+
+    logger.info("pid is {}".format(os.getpid()))
+    
+     # # 更新sn列表
+    host='rm-bp10j10qy42bzy0q7.mysql.rds.aliyuncs.com'
+    port=3306
+    db='qixiang_oss'
+    user='qixiang_oss'
+    password='Qixiang2021'
+    conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db)
+    cursor = conn.cursor()
+    cursor.execute("select sn, imei, add_time from app_device where status in (1,2,3)")
+    res = cursor.fetchall()
+    df_sn = pd.DataFrame(res, columns=['sn', 'imei', 'add_time'])
+    df_sn = df_sn.reset_index(drop=True)
+    conn.close();
+    
+    SNnums = list(df_sn['sn'])
+    
+    scaler_list=[]
+    scaler2_list=[]
+    model_list=[]
+    model2_list=[]
+    for group in ['MGMLX','PK504','PK502','PK500','MGMCL']:
+        scaler = pickle.load(open('D:/deploy/python_platform/data_analyze_platform/LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_'+group+'_10.pkl', 'rb'))
+        scaler2 = pickle.load(open('D:/deploy/python_platform/data_analyze_platform/LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_'+group+'_10.pkl', 'rb'))
+        model = load_model('D:/deploy/python_platform/data_analyze_platform/LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_'+group+'_10.h5')
+        model2 = load_model('D:/deploy/python_platform/data_analyze_platform/LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_'+group+'_10.h5')
+        scaler_list.append(scaler)
+        scaler2_list.append(scaler2)
+        model_list.append(model)
+        model2_list.append(model2)
+    scaler_dict={'MGMLX':scaler_list[0],'PK504':scaler_list[1],'PK502':scaler_list[2],'PK500':scaler_list[3],'MGMCL':scaler_list[4]}
+    scaler2_dict={'MGMLX':scaler2_list[0],'PK504':scaler2_list[1],'PK502':scaler2_list[2],'PK500':scaler2_list[3],'MGMCL':scaler2_list[4]}
+    model_dict={'MGMLX':model_list[0],'PK504':model_list[1],'PK502':model_list[2],'PK500':model_list[3],'MGMCL':model_list[4]}
+    model2_dict={'MGMLX':model2_list[0],'PK504':model2_list[1],'PK502':model2_list[2],'PK500':model2_list[3],'MGMCL':model2_list[4]}
+    logger.info("模型加载完成")
+
+    diag_cal()
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', hours=3)
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        logger.error(str(e))
+        logger.error(traceback.format_exc())

+ 3 - 0
LIB/FRONTEND/FaultDetection/run.bat

@@ -0,0 +1,3 @@
+cd /d D:\deploy\python_platform\data_analyze_platform\LIB\FRONTEND\FaultDetection
+title cal_FaultDetection
+D:\env\py_pro\python.exe D:\deploy\python_platform\data_analyze_platform\LIB\FRONTEND\FaultDetection\main_pred.py

+ 2 - 2
LIB/MIDDLE/CellStateEstimation/BatSafetyWarning/V1_0_1/CBMSSafetyWarning.py

@@ -134,8 +134,8 @@ class SafetyWarning:
                 # 故障判断:1.压降累计最大>6mV,次大<3mV,2.最近一次对应电芯的压降>3mV,且离群
                 if min(deltvolt_rst)<-6:
                     deltvolt_rst1=list(deltvolt_rst)
-                    deltvolt_min_index = list(deltvolt_rst).index(min(deltvolt_rst))
-                    deltvolt_last_list1 = deltvolt_last_list
+                    deltvolt_min_index = deltvolt_rst1.index(min(deltvolt_rst))
+                    deltvolt_last_list1 = deltvolt_last_list.copy()
                     deltvolt_last_list1.pop(deltvolt_min_index)
                     deltvolt_rst1.remove(min(deltvolt_rst))
                     if min(deltvolt_rst1)>-3 and deltvolt_last_list[deltvolt_min_index]<-3 and min(deltvolt_last_list1)>-2.5:

+ 41 - 33
LIB/MIDDLE/CellStateEstimation/BatSafetyWarning/main.py

@@ -4,11 +4,11 @@ from LIB.BACKEND import DBManager, Log
 from apscheduler.schedulers.blocking import BlockingScheduler
 import datetime
 from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import DBDownload
-from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
-import CBMSBatInterShort
-import CBMSBatUniform
-import VoltStray
-import CBMSSafetyWarning
+# from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import log
+from LIB.MIDDLE.CellStateEstimation.BatSafetyWarning.V1_0_1 import CBMSBatInterShort
+from LIB.MIDDLE.CellStateEstimation.BatSafetyWarning.V1_0_1 import CBMSBatUniform
+from LIB.MIDDLE.CellStateEstimation.BatSafetyWarning.V1_0_1 import VoltStray
+from LIB.MIDDLE.CellStateEstimation.BatSafetyWarning.V1_0_1 import CBMSSafetyWarning
 
 #电池热安全预警核心算法函数......................................................................................................................
 def saftywarning_cal():
@@ -19,6 +19,7 @@ def saftywarning_cal():
     global df_warning_ram3
     global df_lfp_ram
     global df_lfp_ram1
+    global df_chrgvolt_ram
 
     pd.set_option('display.width', 300) # 设置字符显示宽度
     pd.set_option('display.max_rows', None) # 设置显示最大行
@@ -94,10 +95,12 @@ def saftywarning_cal():
             df_warning_ram_sn1=df_warning_ram1[df_warning_ram1['sn']==sn]
             df_warning_ram_sn2=df_warning_ram2[df_warning_ram2['sn']==sn]
             df_warning_ram_sn3=df_warning_ram3[df_warning_ram3['sn']==sn]
+            df_chrgvolt_ram_sn=df_chrgvolt_ram[df_chrgvolt_ram['sn']==sn]
             df_warning_ram_sn.reset_index(inplace=True,drop=True)     #重置索引
             df_warning_ram_sn1.reset_index(inplace=True,drop=True)     #重置索引
             df_warning_ram_sn2.reset_index(inplace=True,drop=True)     #重置索引
             df_warning_ram_sn3.reset_index(inplace=True,drop=True)     #重置索引
+            df_chrgvolt_ram_sn.reset_index(inplace=True,drop=True)
             if celltype>50 and (not df_lfp_ram.empty):
                 df_lfp_ram_sn=df_lfp_ram[df_lfp_ram['sn']==sn]
                 df_lfp_ram_sn.reset_index(inplace=True,drop=True)     #重置索引
@@ -112,36 +115,40 @@ def saftywarning_cal():
                 df_lfp_ram1=pd.DataFrame(columns=df_bms.columns.tolist()+['sn'])
 
             #内短路计算..................................................................................................................................................
-            BatShort=CBMSBatInterShort.BatInterShort(sn,celltype,df_bms,df_soh,df_warning_ram_sn,df_warning_ram_sn1,df_warning_ram_sn2,df_warning_ram_sn3,df_lfp_ram_sn)
-            df_short_res, df_ram_res, df_ram_res1, df_ram_res2, df_ram_res3, df_ram_res4=BatShort.intershort() 
+            BatShort=CBMSBatInterShort.BatInterShort(sn,celltype,df_bms,df_soh,df_warning_ram_sn,df_warning_ram_sn1,df_warning_ram_sn2,df_warning_ram_sn3,df_lfp_ram_sn,df_chrgvolt_ram_sn)
+            df_short_res, df_ram_res, df_ram_res1, df_ram_res2, df_ram_res3, df_ram_res4, df_chrgvolt_ram_sn=BatShort.intershort() 
             if not df_short_res.empty:
-                with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\07BatSafetyWarning\内短路.txt','a') as file:
-                    file.write(str(df_short_res)+'\n')
+                pass
+                # with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\07BatSafetyWarning\内短路.txt','a') as file:
+                #     file.write(str(df_short_res)+'\n')
             
             #静置电压排名..................................................................................................................................................
             BatUniform=CBMSBatUniform.BatUniform(sn,celltype,df_bms,df_uniform,df_ram_res3,df_lfp_ram_sn1)
             df_rank_res, df_ram_res3, df_ram_res5=BatUniform.batuniform()
             if not df_rank_res.empty:
                 df_uniform=df_rank_res
-                with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\07BatSafetyWarning\电压排名.txt','a') as file:
-                    file.write(str(df_rank_res)+'\n')
+                # with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\07BatSafetyWarning\电压排名.txt','a') as file:
+                #     file.write(str(df_rank_res)+'\n')
             
             #电压离群.....................................................................................................................................................
             df_voltsigma=VoltStray.main(sn,df_bms,celltype)
             if not df_voltsigma.empty:
-                with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\07BatSafetyWarning\电压离群.txt','a') as file:
-                    file.write(str(df_voltsigma)+'\n')
+                pass
+                # with open(r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\07BatSafetyWarning\电压离群.txt','a') as file:
+                #     file.write(str(df_voltsigma)+'\n')
 
             #ram处理................................................................................................................
             df_warning_ram=df_warning_ram.drop(df_warning_ram[df_warning_ram.sn==sn].index)
             df_warning_ram1=df_warning_ram1.drop(df_warning_ram1[df_warning_ram1.sn==sn].index)
             df_warning_ram2=df_warning_ram2.drop(df_warning_ram2[df_warning_ram2.sn==sn].index)
             df_warning_ram3=df_warning_ram3.drop(df_warning_ram3[df_warning_ram3.sn==sn].index)
+            df_chrgvolt_ram=df_chrgvolt_ram.drop(df_chrgvolt_ram[df_chrgvolt_ram.sn==sn].index)
 
             df_warning_ram=pd.concat([df_warning_ram,df_ram_res],ignore_index=True)
             df_warning_ram1=pd.concat([df_warning_ram1,df_ram_res1],ignore_index=True)
             df_warning_ram2=pd.concat([df_warning_ram2,df_ram_res2],ignore_index=True)
             df_warning_ram3=pd.concat([df_warning_ram3,df_ram_res3],ignore_index=True)
+            df_chrgvolt_ram=pd.concat([df_chrgvolt_ram,df_chrgvolt_ram_sn],ignore_index=True)
             
             if celltype>50:
                 df_lfp_ram=df_lfp_ram.drop(df_lfp_ram[df_lfp_ram.sn==sn].index)
@@ -159,7 +166,7 @@ def saftywarning_cal():
         tablename4='outlier_voltchangeratio'   #电压离群表单
         DBRead=DBDownload.DBDownload(host, port, db, user, password,mode)
         with DBRead as DBRead:
-            df_short=DBRead.getdata('time_sp,sn,short_current', tablename=tablename1, sn=sn, timename='time_sp', st=start_time1, sp=end_time)
+            df_short=DBRead.getdata('time_sp,sn,method,short_current', tablename=tablename1, sn=sn, timename='time_sp', st=start_time1, sp=end_time)
             df_uniform=DBRead.getdata('time,sn,cellsoc_diff,cellvolt_diff,cellmin_num,cellmax_num,cellvolt_rank', tablename=tablename3, sn=sn, timename='time', st=start_time2, sp=end_time)
             df_voltsigma=DBRead.getdata('time,sn,VolOl_Uni,VolChng_Uni', tablename=tablename4, sn=sn, timename='time', st=start_time3, sp=end_time)
 
@@ -187,24 +194,24 @@ def saftywarning_cal():
 #...............................................主函数起定时作用.......................................................................................................................
 if __name__ == "__main__":
     
-    excelpath=r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\sn-20210903.xlsx'
-    SNdata_6060 = pd.read_excel(excelpath, sheet_name='科易6060')
-    SNdata_6040 = pd.read_excel(excelpath, sheet_name='科易6040')
-    SNdata_4840 = pd.read_excel(excelpath, sheet_name='科易4840')
-    SNdata_L7255 = pd.read_excel(excelpath, sheet_name='格林美-力信7255')
-    SNdata_C7255 = pd.read_excel(excelpath, sheet_name='格林美-CATL7255')
-    SNdata_U7255 = pd.read_excel(excelpath, sheet_name='优旦7255')
-    SNnums_6060=SNdata_6060['SN号'].tolist()
-    SNnums_6040=SNdata_6040['SN号'].tolist()
-    SNnums_4840=SNdata_4840['SN号'].tolist()
-    SNnums_L7255=SNdata_L7255['SN号'].tolist()
-    SNnums_C7255=SNdata_C7255['SN号'].tolist()
-    SNnums_U7255=SNdata_U7255['SN号'].tolist()
-    SNnums=SNnums_L7255 + SNnums_C7255 + SNnums_U7255 + SNnums_6040 + SNnums_4840 + SNnums_6060
-    SNnums=['MGMCLN750N215I091']
+    # excelpath=r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\sn-20210903.xlsx'
+    # SNdata_6060 = pd.read_excel(excelpath, sheet_name='科易6060')
+    # SNdata_6040 = pd.read_excel(excelpath, sheet_name='科易6040')
+    # SNdata_4840 = pd.read_excel(excelpath, sheet_name='科易4840')
+    # SNdata_L7255 = pd.read_excel(excelpath, sheet_name='格林美-力信7255')
+    # SNdata_C7255 = pd.read_excel(excelpath, sheet_name='格林美-CATL7255')
+    # SNdata_U7255 = pd.read_excel(excelpath, sheet_name='优旦7255')
+    # SNnums_6060=SNdata_6060['SN号'].tolist()
+    # SNnums_6040=SNdata_6040['SN号'].tolist()
+    # SNnums_4840=SNdata_4840['SN号'].tolist()
+    # SNnums_L7255=SNdata_L7255['SN号'].tolist()
+    # SNnums_C7255=SNdata_C7255['SN号'].tolist()
+    # SNnums_U7255=SNdata_U7255['SN号'].tolist()
+    # SNnums=SNnums_L7255 + SNnums_C7255 + SNnums_U7255 + SNnums_6040 + SNnums_4840 + SNnums_6060
+    SNnums=['PK50001A100000577']
     
-    mylog=log.Mylog('log_warning.txt','error')
-    mylog.logcfg()
+    # mylog=log.Mylog('log_warning.txt','error')
+    # mylog.logcfg()
 
     #............................模块运行前,先读取数据库中所有结束时间为0的数据,需要从数据库中读取...................................
     df_warning_ram=pd.DataFrame(columns=['sn','time','deltsoc','cellsoc'])
@@ -213,15 +220,16 @@ if __name__ == "__main__":
     df_warning_ram3=pd.DataFrame(columns=['sn','time3','standingtime','standingtime1','standingtime2'])
     df_lfp_ram=pd.DataFrame()
     df_lfp_ram1=pd.DataFrame()
+    df_chrgvolt_ram=pd.DataFrame(columns=['sn','time','deltvolt','packcrnt_avg','temp_avg'])
 
 
     #定时任务.......................................................................................................................................................................
     scheduler = BlockingScheduler()
-    scheduler.add_job(saftywarning_cal, 'interval', hours=6)
+    scheduler.add_job(saftywarning_cal, 'interval', seconds=6)
 
     try:  
         scheduler.start()
     except Exception as e:
         scheduler.shutdown()
         print(repr(e))
-        mylog.logopt(e)
+        # mylog.logopt(e)

+ 452 - 0
LIB/MIDDLE/FaultClass/V1_0_0/faultclass.py

@@ -0,0 +1,452 @@
+import pandas as pd
+import numpy as np
+import datetime
+from random import shuffle
+from sklearn.preprocessing import StandardScaler
+from keras.layers import Activation,Dense,Input
+from keras.layers.recurrent import GRU
+from keras.models import Model
+from keras.optimizers import adam_v2
+from keras.layers import Dropout
+import random
+
+#### Process1 - Prediction - Model1+Model2 ###
+
+# Step1 Features
+
+# Model1 
+def features1(dataset2):
+    dataset2=dataset2.drop(['GSM信号','故障等级','故障代码','开关状态','绝缘电阻','外电压','总输出状态','上锁状态','加热状态','单体均衡状态','充电状态','SOH[%]','SOC[%]','总电流[A]'],axis=1,errors='ignore')
+    cellvolt_list = [s for s in list(dataset2) if '单体电压' in s] 
+    celltemp_name = [s for s in list(dataset2) if '温度' in s] 
+    dataset2=dataset2.drop(celltemp_name,axis=1)
+    dataset2['volt_max']=dataset2[cellvolt_list].max(axis=1)
+    dataset2['volt_min']=dataset2[cellvolt_list].min(axis=1) 
+    dataset2=dataset2.drop(cellvolt_list,axis=1)
+    dataset2.reset_index(drop=True,inplace=True)
+    return dataset2
+# Model2
+def features2(dataset2):
+    dataset2=dataset2.drop(['GSM信号','故障等级','故障代码','开关状态','绝缘电阻','外电压','总输出状态','上锁状态','加热状态','单体均衡状态','充电状态','SOH[%]','SOC[%]','单体压差','总电压[V]'],axis=1,errors='ignore')
+    cellvolt_list = [s for s in list(dataset2) if '单体电压' in s] 
+    celltemp_name = [s for s in list(dataset2) if '单体温度' in s] 
+    celltemp_name2 = [s for s in list(dataset2) if '其他温度' in s]
+    dataset2=dataset2.drop(cellvolt_list+celltemp_name2,axis=1)
+    dataset2['temp_max']=dataset2[celltemp_name].max(axis=1)
+    dataset2['temp_min']=dataset2[celltemp_name].min(axis=1) 
+    dataset2['temp_diff']=list(np.array(dataset2['temp_max'])-np.array(dataset2['temp_min']))
+    dataset2=dataset2.drop(celltemp_name,axis=1)
+    dataset2.reset_index(drop=True,inplace=True)
+    return dataset2
+
+# Step2 Splits
+def split(df_bms_tot):
+    df_bms_tot['split']=0
+    for k in range(1,len(df_bms_tot)):
+        timek=df_bms_tot.loc[k,'时间戳']
+        timek1=df_bms_tot.loc[k-1,'时间戳']
+        timek=datetime.datetime.strptime(timek,'%Y-%m-%d %H:%M:%S')     #type: datetime
+        timek1=datetime.datetime.strptime(timek1,'%Y-%m-%d %H:%M:%S')
+        deltatime=(timek-timek1).total_seconds()
+        if (deltatime>600) | (df_bms_tot.loc[k,'sn']!=df_bms_tot.loc[k-1,'sn']):
+            df_bms_tot.loc[k,'split']=df_bms_tot.loc[k-1,'split']+1
+        else:
+            df_bms_tot.loc[k,'split']=df_bms_tot.loc[k-1,'split']
+    return df_bms_tot
+
+# Step3 MakeDataset: TimeSeries
+def makedataset(dataset):
+    df_bms=pd.DataFrame()
+    for split in list(set(dataset['split'])):
+        set2=dataset[dataset['split']==split]
+        set2.reset_index(drop=True,inplace=True)
+        data_set=pd.DataFrame()
+        start=set2.loc[0,'时间戳']
+        end=set2.loc[len(set2)-1,'时间戳']
+        data_set['Time']=pd.date_range(start=start, end=end, freq='S')  #每分钟一条记录
+        data_set['Time']=list(map(lambda x:str(x),list(data_set['Time'])))
+        dfbms=pd.merge(data_set,set2,left_on='Time',right_on='时间戳',how='left')
+        dfbms=dfbms.fillna(method='ffill')
+        dfbms=dfbms.fillna(method='bfill')  
+        dfbms=dfbms.drop(['时间戳'],axis=1)
+        dfbms['Time']=list(map(lambda x:x[:18]+'0',list(dfbms['Time'])))
+        dfbms.drop_duplicates(subset='Time',keep='last',inplace=True)
+        df_bms=df_bms.append(dfbms)
+        df_bms.reset_index(drop=True,inplace=True)
+    return df_bms
+
+# Step4 Scaler
+def scaler_pred(df_bms,scaler):
+    Xtest=df_bms.drop(['Time','sn','split'],axis=1)
+    Xsc_colnames=list(Xtest.columns)
+    Xtsc=scaler.transform(np.array(Xtest))
+    Xtsc=pd.DataFrame(Xtsc)
+    Xtsc.columns=Xsc_colnames
+    return Xtsc
+
+# Step5 MakeIndex
+def make_index(train):
+    indextr=[]
+    for i in list(set(train['split'])):
+        tr=train[train['split'] == i].index.tolist()
+        indextr.append(min(tr))
+    indextr=sorted(indextr)
+    indextr.append(len(train))
+    return indextr
+
+# Step5 CreateWindows
+def create_win_pred(X2,Xtest,index,time_steps=12): 
+    conf=pd.DataFrame() 
+    a=[]
+    for k in range(1,len(index)):
+        dataset=X2[index[k-1]:index[k]]
+        dataset=dataset.reset_index(drop=True)
+        dataset2=Xtest[index[k-1]:index[k]]
+        dataset2=dataset2.reset_index(drop=True)
+        if len(dataset)>time_steps:
+            dataX = []
+            win_step=[]
+            for i in range(len(dataset)-time_steps): 
+                win_step.append(i)
+                #v1 = np.array(dataset.iloc[i:(i+time_steps)],dtype='float32')
+                v1 = dataset.iloc[i:(i+time_steps)].values
+                dataX.append(v1)
+            test=dataset2.iloc[:len(dataset)-time_steps]
+            dataX2=np.array(dataX,dtype='float32')
+            conf=conf.append(test)
+            a.append(dataX2)
+    if len(a)>0:
+        aa=np.vstack(a)
+    else:
+        aa=[]
+    conf.reset_index(drop=True,inplace=True)
+    return aa,conf
+
+# Step6 Prediction
+def prediction(model,cc,conf,col):
+    predict_dd = model.predict(cc)  
+    df_pred=pd.DataFrame(predict_dd)
+    df_pred.columns=col
+    df_pred2 = df_pred.idxmax(axis=1)
+    conf['pred']=df_pred2
+    return conf
+
+# Step7 Output
+def makeres(res,end_time):  
+    df_res=pd.DataFrame(columns=['product_id','start_time','end_time','fault_class','update_time'])
+    result_faults=res[res['pred']!='正常']
+    list_faults=list(set(list(result_faults['pred'])))
+    for fault in list_faults:
+        res_faults=result_faults[result_faults['pred']==fault]
+        res_faults.reset_index(drop=True,inplace=True)
+        update_time=str(res_faults.loc[len(res_faults)-1,'Time'])
+        end=datetime.datetime.strptime(str(res_faults.loc[len(res_faults)-1,'Time']),'%Y-%m-%d %H:%M:%S')
+        end_time=datetime.datetime.strptime(str(end_time),'%Y-%m-%d %H:%M:%S')
+        if (end_time-end).total_seconds()<900:
+            res_faults.loc[len(res_faults)-1,'Time']='0000-00-00 00:00:00'
+        df_res=df_res.append(pd.DataFrame({'product_id':[res_faults.loc[0,'sn']],'start_time':[str(res_faults.loc[0,'Time'])],
+                        'end_time':[str(res_faults.loc[len(res_faults)-1,'Time'])],'fault_class':[res_faults.loc[0,'pred']],
+                        'update_time':[update_time]}))
+    return df_res
+
+# Step7 Merge
+def arrange(result,result_final,start_time):
+    result.reset_index(drop=True,inplace=True)
+    result_final.reset_index(drop=True,inplace=True)
+    list_faults=list(set(list(result_final['fault_class'])))
+    res_update=pd.DataFrame()
+    res_new=result.copy()
+    for fault in list_faults:
+        result0=result_final[result_final['fault_class']==fault]
+        result1=result[result['fault_class']==fault]
+        st=datetime.datetime.strptime(str(result.loc[0,'start_time']),'%Y-%m-%d %H:%M:%S')
+        start_time=datetime.datetime.strptime(str(start_time),'%Y-%m-%d %H:%M:%S')
+        if len(result1)>0:
+            if (start_time-st).total_seconds()<900:
+                result0['end_time']=result1['end_time']
+                result0['update_time']=result1['update_time']
+                res_update=res_update.append(result0)
+                res_new.drop(result1.index,inplace=True)
+            else:
+                result0['end_time']=result0['update_time']
+                res_update=res_update.append(result0)
+                res_new.drop(result1.index,inplace=True)
+        else:
+            result0['end_time']=result0['update_time']
+            res_update=res_update.append(result0)
+    return res_new,res_update
+
+def arrange2(dataorg,df_res,start_time,fault_name):
+    res_new=df_res.copy()
+    res_update=pd.DataFrame()
+    if len(dataorg)>0:
+        dataorg=dataorg[dataorg['fault_class']==fault_name]
+        res_new,res_update=arrange(df_res,dataorg,start_time)
+    return res_new,res_update
+
+# Step8 Process
+def pred(data_fea,model,scaler,col,end_time,time_steps):
+    df_res=pd.DataFrame()
+    fea=split(data_fea)
+    f=makedataset(fea)
+    sc=scaler_pred(f,scaler)
+    index=make_index(f)
+    dataX,pred=create_win_pred(sc,f,index,time_steps=time_steps)
+    if len(dataX)>0:
+        res=prediction(model,dataX,pred,col)
+        df_res=makeres(res,end_time)
+    return df_res
+
+
+
+#################################################################################################################################
+
+#### Process1 - New Model ###
+
+# Step1 Features Filtre
+def features_filtre(dataset2,cols):
+    dataset2=dataset2.drop(['GSM信号','故障等级','故障代码','开关状态','绝缘电阻','外电压','总输出状态','上锁状态','加热状态','单体均衡状态','充电状态','SOH[%]'],axis=1,errors='ignore')
+    cellvolt_list = [s for s in list(dataset2) if '单体电压' in s] 
+    celltemp_name = [s for s in list(dataset2) if '单体温度' in s] 
+    celltemp_name2 = [s for s in list(dataset2) if '其他温度' in s]
+    dataset2['volt_max']=dataset2[cellvolt_list].max(axis=1)
+    dataset2['volt_min']=dataset2[cellvolt_list].min(axis=1)
+    dataset2['volt_mean'] = round(dataset2[cellvolt_list].mean(axis=1),3)  #每行平均
+    dataset2['volt_sigma'] =list(dataset2[cellvolt_list].apply(lambda x: np.std(x.values),axis=1))
+    cell_volt_max =list(dataset2[cellvolt_list].apply(lambda x: np.argmax(x.values)+1,axis=1))
+    cell_volt_min =list(dataset2[cellvolt_list].apply(lambda x: np.argmin(x.values)+1,axis=1))
+    dataset2['mm_volt_cont'] = list(np.array(cell_volt_max) - np.array(cell_volt_min)) 
+    dataset2['mm_volt_cont']=list(map(lambda x : 1 if (abs(x)==1) | (abs(x)==len(cellvolt_list)-1) else 0, list(dataset2['mm_volt_cont'])))
+    #for k in range(len(dataset2)):
+        #dataset2.loc[k,'mm_volt_cont']=1 if (abs(list(dataset2['mm_volt_cont'])[k])==1) | (abs(list(dataset2['mm_volt_cont'])[k])==len(cellvolt_list)-1) else 0 
+    dataset2=dataset2.drop(cellvolt_list+celltemp_name2,axis=1)
+    dataset2['temp_max']=dataset2[celltemp_name].max(axis=1)
+    dataset2['temp_min']=dataset2[celltemp_name].min(axis=1) 
+    dataset2['temp_diff']=list(np.array(dataset2['temp_max'])-np.array(dataset2['temp_min']))
+    dataset2=dataset2.drop(celltemp_name,axis=1)
+    datatest3=dataset2[cols]
+    datatest3.reset_index(drop=True,inplace=True)
+    return datatest3
+    
+# Step2 Data Filtre
+def data_filtre(datatest3,col_key,compare,threshold):
+    if compare==0:
+        datatest4=datatest3[datatest3[col_key]==threshold]
+    elif compare==1:
+        datatest4=datatest3[datatest3[col_key]>threshold]
+    else:
+        datatest4=datatest3[datatest3[col_key]<threshold]
+    datatest4.reset_index(drop=True,inplace=True)
+    return datatest4
+
+# Step3 Faults Pre-processing
+def make_fault_set(dataset,cols,col_key,compare,threshold_filtre,fault_name):
+    datatest3=features_filtre(dataset,cols)
+    datatest4=data_filtre(datatest3,col_key,compare,threshold_filtre)
+    df_tot=split(datatest4)
+    df_bms=makedataset(df_tot)
+    df_bms['fault_class']=fault_name
+    return df_bms
+
+# Step4 Normal Pre-processing
+def normalset(df_bms,cols):
+    df_bms.drop(['Unnamed: 0'],axis=1,inplace=True)
+    nor_fea1=features_filtre(df_bms,cols)
+    norfea1=split(nor_fea1)
+    normalf1=makedataset(norfea1)
+    normalf1['fault_class']='正常'
+    return normalf1
+
+def normalset2(df_bms1,df_bms2,df_bms3,df_bms4,df_bms5,df_bms6,cols):
+    normalf1=normalset(df_bms1,cols)
+    normalf2=normalset(df_bms2,cols)
+    normalf3=normalset(df_bms3,cols)
+    normalf4=normalset(df_bms4,cols)
+    normalf5=normalset(df_bms5,cols)
+    normalf6=normalset(df_bms6,cols)
+    nor=pd.concat([normalf1,normalf2,normalf3,normalf4,normalf5,normalf6])
+    nor.reset_index(drop=True,inplace=True)
+    return nor
+
+# Step5 Resample
+def resample(nor,df_bms):
+    if len(nor)>2*len(df_bms):
+        sp=list(set(list(nor['split'])))
+        sp_ran=random.sample(sp, k=int(len(sp)*(len(df_bms)/len(nor))))
+        nor=nor[nor['split'].isin(sp_ran)]
+        nor.reset_index(drop=True,inplace=True)
+    if 2*len(nor)<len(df_bms):
+        sp=list(set(list(df_bms['split'])))
+        sp_ran=random.sample(sp, k=int(len(sp)*(len(nor)/len(df_bms))))
+        df_bms=df_bms[df_bms['split'].isin(sp_ran)]
+        df_bms.reset_index(drop=True,inplace=True)
+    return nor,df_bms
+
+# Step6 Shuffle Data
+def shuffle_data(nor,dataset_faults):
+    sn_nor=list(set(nor['sn']))
+    sn_fau=list(set(dataset_faults['sn']))
+    shuffle(sn_nor)
+    shuffle(sn_fau)
+    newtrain=pd.DataFrame()
+    newtest=pd.DataFrame()
+    for s1 in sn_nor[:int(0.8*len(sn_nor))]:
+        nortrain=nor[nor['sn']==s1]
+        nortrain.reset_index(drop=True,inplace=True)
+        newtrain=newtrain.append(nortrain)
+    for s2 in sn_nor[int(0.8*len(sn_nor)):]:
+        nortest=nor[nor['sn']==s2]
+        nortest.reset_index(drop=True,inplace=True)
+        newtest=newtest.append(nortest)
+    for s3 in sn_fau[:int(0.8*len(sn_fau))]:
+        fautrain=dataset_faults[dataset_faults['sn']==s3]
+        fautrain.reset_index(drop=True,inplace=True)
+        newtrain=newtrain.append(fautrain)
+    for s4 in sn_fau[int(0.8*len(sn_fau)):]:
+        fautest=dataset_faults[dataset_faults['sn']==s4]
+        fautest.reset_index(drop=True,inplace=True)
+        newtest=newtest.append(fautest)
+    newtrain.reset_index(drop=True,inplace=True)
+    newtest.reset_index(drop=True,inplace=True)
+    return newtrain,newtest
+
+def shuffle_data2(dftrain):
+    sp=list(set(dftrain['sn']))
+    shuffle(sp)
+    newtrain=pd.DataFrame()
+    for s in sp:
+        ntr=dftrain[dftrain['sn']==s]
+        newtrain=newtrain.append(ntr)
+    newtrain.reset_index(drop=True,inplace=True)
+    return newtrain
+
+# Step7 X & Y
+def xy(train):
+    Xtrain=train.drop(['fault_class','Time','sn','split'],axis=1)
+    Ytrain=train[['fault_class']]          
+    Ytrain2=pd.get_dummies(Ytrain,columns=['fault_class'],prefix_sep='_')
+    return Xtrain,Ytrain,Ytrain2
+
+# Step8 Scaler 
+def scaler_train(Xtrain):
+    Xsc_colnames=list(Xtrain.columns)
+    scaler=StandardScaler()
+    scaler.fit(Xtrain)  #保存train_sc的均值和标准差
+    Xsc=scaler.transform(np.array(Xtrain))
+    Xsc=pd.DataFrame(Xsc)
+    Xsc.columns=Xsc_colnames
+    return Xsc,scaler
+
+def scaler_test(Xtest,scaler):
+    Xsc_colnames=list(Xtest.columns)
+    Xtsc=scaler.transform(np.array(Xtest))
+    Xtsc=pd.DataFrame(Xtsc)
+    Xtsc.columns=Xsc_colnames
+    return Xtsc
+
+# Step9 Create windows 
+def create_win_train(X2,Y2,index,time_steps=6):  
+    a,b=[],[] 
+    for k in range(1,len(index)):
+        dataset=X2[index[k-1]:index[k]]
+        dataset=dataset.reset_index(drop=True)
+        datay=Y2[index[k-1]:index[k]]
+        datay=datay.reset_index(drop=True)
+        if len(dataset)>time_steps:
+            dataX, dataY = [], []
+            for i in range(len(dataset)-time_steps): 
+                v1 = dataset.iloc[i:(i+time_steps)].values
+                v2 = datay.iloc[i].values
+                dataX.append(v1)
+                dataY.append(v2)
+            dataX2=np.array(dataX,dtype='float32')
+            dataY2=np.array(dataY)
+        else:
+            continue
+        a.append(dataX2)             
+        b.append(dataY2)
+    aa=np.vstack(a)
+    bb=np.vstack(b)  
+    return aa,bb
+
+def create_win_test(X2,Y2,Xtest,index,time_steps=12):  
+    a,b=[],[] 
+    conf=pd.DataFrame()
+    for k in range(1,len(index)):
+        dataset=X2[index[k-1]:index[k]]
+        dataset=dataset.reset_index(drop=True)
+        datay=Y2[index[k-1]:index[k]]
+        datay=datay.reset_index(drop=True)
+        dataset2=Xtest[index[k-1]:index[k]]
+        dataset2=dataset2.reset_index(drop=True)
+        if len(dataset)>time_steps:
+            dataX, dataY = [], []
+            win_step=[]
+            for i in range(len(dataset)-time_steps): 
+                win_step.append(i)
+                v1 = dataset.iloc[i:(i+time_steps)].values
+                v2 = datay.iloc[i].values
+                dataX.append(v1)
+                dataY.append(v2)
+            test=dataset2.iloc[:len(dataset)-time_steps]
+            test['win']=win_step
+            test=pd.merge(test,datay,left_index=True,right_index=True)
+            dataX2=np.array(dataX,dtype='float32')
+            dataY2=np.array(dataY)
+        else:
+            continue
+        a.append(dataX2)             
+        b.append(dataY2)
+        conf=conf.append(test)
+    aa=np.vstack(a)
+    bb=np.vstack(b)
+    conf.reset_index(drop=True,inplace=True)
+    return aa,bb,conf 
+
+# Step10 Create Model
+def modelGRU(time_steps,nbr_features,nbr_neurons,nbr_class,Xwin,Ywin,Xtwin,Ytwin,batch_size,epochs,dropout,lr,activation,loss,metrics):
+    time_steps=time_steps
+    inputs = Input(shape=[time_steps,nbr_features])
+    x = GRU(nbr_neurons, input_shape = (time_steps,nbr_features),return_sequences=False, return_state=False)(inputs)
+    x = Dropout(dropout)(x)
+    x = Dense(nbr_class)(x)
+    x = Dropout(dropout)(x)
+    x = Activation(activation)(x)
+    LR = lr
+    model = Model(inputs,x)
+    adam = adam_v2.Adam(LR)
+    model.compile(loss = loss,optimizer = adam,metrics = [metrics])
+    model.fit(Xwin,Ywin,epochs=epochs,validation_data=(Xtwin,Ytwin),batch_size=batch_size,verbose=1,shuffle=True)
+    return model
+
+# Step11 Process
+def pre_model(nor,df_bms,time_steps,nbr_features,nbr_neurons,nbr_class,batch_size,epochs,dropout,lr,activation,loss):
+    nor,df_bms=resample(nor,df_bms)
+    newtrain,newtest=shuffle_data(nor,df_bms)
+    train_sh=shuffle_data2(newtrain)
+    test_sh=shuffle_data2(newtest)
+    Xtrain,Ytrain,Ytrain2=xy(train_sh)
+    Xtest,Ytest,Ytest2=xy(test_sh)                           
+    Xsc,scaler=scaler_train(Xtrain)
+    Xtsc=scaler_test(Xtest,scaler)
+    indextr=make_index(train_sh)
+    indexte=make_index(test_sh)
+    Xwin,Ywin=create_win_train(Xsc,Ytrain2,indextr,time_steps=time_steps)
+    Xtwin,Ytwin,conf=create_win_test(Xtsc,Ytest2,test_sh,indexte,time_steps=time_steps)
+    model=modelGRU(time_steps=time_steps,nbr_features=nbr_features,nbr_neurons=nbr_neurons,nbr_class=nbr_class,Xwin=Xwin,Ywin=Ywin,
+                    Xtwin=Xtwin,Ytwin=Ytwin,batch_size=batch_size,epochs=epochs,dropout=dropout,lr=lr,activation=activation,
+                    loss=loss,metrics='accuracy')
+    loss,acc=model.evaluate(Xtwin,Ytwin)
+    return scaler,model,acc
+
+
+
+
+
+
+
+
+
+
+
+

+ 42 - 0
LIB/MIDDLE/FaultClass/V1_0_0/main_input.py

@@ -0,0 +1,42 @@
+from sqlalchemy import create_engine
+from urllib import parse
+import pandas as pd
+import pymysql
+
+#用户输入参数
+fault_name='电压采样断线'
+cols=str(['时间戳','sn','单体压差','volt_max','volt_min','volt_mean','volt_sigma','mm_volt_cont'])
+col_key='mm_volt_cont'
+compare=0
+threshold_filtre=1
+
+time_steps=12
+nbr_features=6
+nbr_neurons=5
+nbr_class=2
+batch_size=100
+epochs=5
+dropout=0.5
+lr=1e-3
+activation='softmax'
+loss='categorical_crossentropy'
+
+threshold_accuracy=0.95
+
+#数据库配置
+host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+port=3306
+db='qx_cas'
+user='qx_algo_rw'
+password='qx@123456'
+
+db_res_engine = create_engine(
+    "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
+        user, parse.quote_plus(password), host, port, db
+    ))
+#mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+input_param=pd.DataFrame({'fault_name':[fault_name],'cols':[cols],'col_key':[col_key],'compare':[compare],'threshold_filtre':[threshold_filtre],
+                        'time_steps':[time_steps],'nbr_features':[nbr_features],'nbr_neurons':[nbr_neurons],'nbr_class':[nbr_class],'batch_size':[batch_size],
+                        'epochs':[epochs],'dropout':[dropout],'lr':[lr],'activation':[activation],'loss':[loss],'threshold_accuracy':[threshold_accuracy]})
+input_param.to_sql("faultclass_input",con=db_res_engine, if_exists="append",index=False)
+#mysql.close()

+ 164 - 0
LIB/MIDDLE/FaultClass/V1_0_0/main_pred.py

@@ -0,0 +1,164 @@
+
+from LIB.MIDDLE.FaultClass.V1_0_0.faultclass import *
+import pymysql
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager
+dbManager = DBManager.DBManager()
+from sqlalchemy import create_engine
+from urllib import parse
+import datetime, time
+from apscheduler.schedulers.blocking import BlockingScheduler
+import traceback
+import pickle
+from keras.models import load_model
+import logging
+import logging.handlers
+import os
+import re
+
+
+#...................................故障检测函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global scaler1,scaler2,model1,model2,col1,col2,time_steps1,time_steps2
+
+    start=time.time()
+    now_time=datetime.datetime.now()
+    start_time=now_time-datetime.timedelta(hours=1)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=now_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    #数据库配置
+    host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+    port=3306
+    db='safety_platform'
+    user='qx_read'
+    password='Qx@123456'
+
+    #读取结果库数据......................................................
+    param='product_id,start_time,end_time,diff_min,SOC,AnoScoreV_sum_max,AnoScoreV_max_max,AnoScoreT_sum_max,AnoScoreT_max_max'
+    tablename='fault_detection'
+    mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+    cursor = mysql.cursor()
+    sql =  "select {} from {} where end_time='0000-00-00 00:00:00'".format(param,tablename)
+    cursor.execute(sql)
+    res = cursor.fetchall()
+    df_diag_ram= pd.DataFrame(res,columns=param.split(','))
+    
+
+    db_res_engine = create_engine(
+        "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
+            user, parse.quote_plus(password), host, port, db
+        ))
+
+
+    #调用主函数................................................................................................................................................................
+    for sn in SNnums:
+        try:
+            df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms'])
+            data_bms = df_data['bms']
+            data_bms['sn']=sn
+            if len(data_bms)>0:
+                logger.info("SN: {} 数据开始预处理".format(sn))
+                data_fea1=features1(data_bms)
+                data_fea2=features2(data_bms)
+                logger.info("SN: {} 数据开始模型预测".format(sn))
+                df_res1=pred(data_fea1,model1,scaler1,col1,end_time,time_steps1)
+                df_res2=pred(data_fea2,model2,scaler2,col2,end_time,time_steps2)
+                df_diag_ram_sn=df_diag_ram[df_diag_ram['product_id']==sn]
+                res_new1,res_update1=arrange2(df_diag_ram_sn,df_res1,start_time,'B板采样失效')
+                res_new2,res_update2=arrange2(df_diag_ram_sn,df_res2,start_time,'传感器_电芯NTC漂移')
+               
+                if len(res_update1)>0:
+                    cursor.execute("DELETE FROM fault_class WHERE end_time = '0000-00-00 00:00:00' and product_id='{}' and fault_class='{}'".format(sn,'B板采样失效'))
+                    mysql.commit()
+                    res_update1.to_sql("fault_class",con=db_res_engine, if_exists="append",index=False)
+                res_new1.to_sql("fault_class",con=db_res_engine, if_exists="append",index=False)
+                if len(res_update2)>0:
+                    cursor.execute("DELETE FROM fault_class WHERE end_time = '0000-00-00 00:00:00' and product_id='{}' and fault_class='{}'".format(sn,'传感器_电芯NTC漂移'))
+                    mysql.commit()
+                    res_update2.to_sql("fault_class",con=db_res_engine, if_exists="append",index=False)
+                res_new2.to_sql("fault_class",con=db_res_engine, if_exists="append",index=False)
+            
+                        #新增结果存入结果库................................................................
+
+
+            # end=time.time()
+            # print(end-start)  
+                
+        except Exception as e:
+            logger.error(str(e))
+            logger.error(traceback.format_exc())
+
+    cursor.close()
+    mysql.close()
+
+#...............................................主函数起定时作用.......................................................................................................................
+if __name__ == "__main__":
+    
+    # 日志
+    log_path = 'log/'
+    if not os.path.exists(log_path):
+        os.makedirs(log_path)
+    logger = logging.getLogger("main")
+    logger.setLevel(logging.DEBUG)
+    
+     # 根据日期滚动(每天产生1个文件)
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_info.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.INFO)
+    logger.addHandler(fh)
+
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_error.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.ERROR)
+    logger.addHandler(fh)
+
+    logger.info("pid is {}".format(os.getpid()))
+    
+     # # 更新sn列表
+    host='rm-bp10j10qy42bzy0q7.mysql.rds.aliyuncs.com'
+    port=3306
+    db='qixiang_oss'
+    user='qixiang_oss'
+    password='Qixiang2021'
+    conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db)
+    cursor = conn.cursor()
+    cursor.execute("select sn, imei, add_time from app_device where status in (1,2,3)")
+    res = cursor.fetchall()
+    df_sn = pd.DataFrame(res, columns=['sn', 'imei', 'add_time'])
+    df_sn = df_sn.reset_index(drop=True)
+    conn.close();
+    
+    SNnums = list(df_sn['sn'])
+    
+    scaler1=pickle.load(open('LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_B板采样失效.pkl','rb'))
+    scaler2=pickle.load(open('LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_传感器_电芯NTC漂移.pkl','rb'))
+    model1=load_model('LIB/MIDDLE/FaultClass/V1_0_0/models/model_B板采样失效.h5')
+    model2=load_model('LIB/MIDDLE/FaultClass/V1_0_0/models/model_传感器_电芯NTC漂移.h5')
+    col1=['B板采样失效','正常']
+    col2=['传感器_电芯NTC漂移','正常']
+    time_steps1=60
+    time_steps2=60
+    logger.info("模型加载完成")
+
+    diag_cal()
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', hours=1)
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        logger.error(str(e))
+        logger.error(traceback.format_exc())

+ 158 - 0
LIB/MIDDLE/FaultClass/V1_0_0/main_train.py

@@ -0,0 +1,158 @@
+from faultclass import *
+import pymysql
+import datetime
+import pandas as pd
+import datetime
+import pickle
+from LIB.BACKEND import DBManager
+dbManager = DBManager.DBManager()
+from LIB.MIDDLE.CellStateEstimation.Common import log
+mylog=log.Mylog('log.txt','error')
+mylog.logcfg()
+from sqlalchemy import create_engine
+from urllib import parse
+
+#故障
+fault_name='电压采样断线'
+
+#读取文件:正常数据
+
+df_bms1=pd.read_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/dataset2.csv')
+df_bms2=pd.read_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/dataset3.csv')
+df_bms3=pd.read_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/dataset4.csv')
+df_bms4=pd.read_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/dataset5.csv')
+df_bms5=pd.read_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/dataset6.csv')
+df_bms6=pd.read_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/dataset7.csv')
+
+#数据库配置
+host0='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+port0=3306
+db0='qx_cas'
+user0='qx_algo_rw'
+password0='qx@123456'
+
+#读取结果库数据......................................................
+param='fault_name,cols,col_key,compare,threshold_filtre,time_steps,nbr_features,nbr_neurons,nbr_class,batch_size,epochs,dropout,lr,activation,loss,threshold_accuracy'
+tablename='faultclass_input'
+mysql = pymysql.connect (host=host0, user=user0, password=password0, port=port0, database=db0)
+cursor = mysql.cursor()
+sql =  "select {} from {} where fault_name='{}'".format(param,tablename,fault_name)
+cursor.execute(sql)
+res = cursor.fetchall()
+list_param= pd.DataFrame(res,columns=param.split(','))
+list_param.reset_index(drop=True,inplace=True)
+
+db_res_engine = create_engine(
+    "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
+        user0, parse.quote_plus(password0), host0, port0, db0
+    ))
+
+#用户输入参数
+cols=eval(list_param.loc[0,'cols'])
+col_key=list_param.loc[0,'col_key']
+compare=list_param.loc[0,'compare']
+threshold_filtre=list_param.loc[0,'threshold_filtre']
+
+time_steps=list_param.loc[0,'time_steps']
+nbr_features=list_param.loc[0,'nbr_features']
+nbr_neurons=list_param.loc[0,'nbr_neurons']
+nbr_class=list_param.loc[0,'nbr_class']
+batch_size=list_param.loc[0,'batch_size']
+epochs=list_param.loc[0,'epochs']
+dropout=list_param.loc[0,'dropout']
+lr=list_param.loc[0,'lr']
+activation=list_param.loc[0,'activation']
+loss=list_param.loc[0,'loss']
+
+threshold_accuracy=list_param.loc[0,'threshold_accuracy']
+
+#数据库配置
+host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+port=3306
+db='safety_platform'
+user='qx_read'
+password='Qx@123456'
+
+#读取故障结果库中当前故障......................................................
+param='start_time,end_time,product_id,code,info'
+tablename='all_fault_info'
+mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+cursor = mysql.cursor()
+#sql =  "select %s from %s where end_time='0000-00-00 00:00:00'" %(param,tablename)
+sql =  "select %s from %s" %(param,tablename)
+cursor.execute(sql)
+res = cursor.fetchall()
+df_diag_ram= pd.DataFrame(res,columns=param.split(','))
+
+df_diag_ram.dropna(inplace=True)
+df_diag_ram.reset_index(drop=True,inplace=True)
+
+#数据库配置
+host2='rm-bp10j10qy42bzy0q7.mysql.rds.aliyuncs.com'
+port=3306
+db2='zhl_omp_v2'
+user2='zhl_omp'
+password='Qx@123456'
+
+#读取故障结果库中当前故障......................................................
+param='fault_time,fault_code,sn,child_tag,tag_type,update_time'
+tablename='t_cloud_control'
+mysql = pymysql.connect (host=host2, user=user2, password=password, port=port, database=db2)
+cursor = mysql.cursor()
+#sql =  "select %s from %s where end_time='0000-00-00 00:00:00'" %(param,tablename)
+sql =  "select %s from %s" %(param,tablename)
+cursor.execute(sql)
+res = cursor.fetchall()
+df_diag_ram2= pd.DataFrame(res,columns=param.split(','))
+
+df_diag_ram2.dropna(inplace=True)
+df_diag_ram2.reset_index(drop=True,inplace=True)
+
+#读取故障结果库中当前故障......................................................
+param='id,parent_id,name'
+tablename='t_child_problem'
+mysql = pymysql.connect (host=host2, user=user2, password=password, port=port, database=db2)
+cursor = mysql.cursor()
+#sql =  "select %s from %s where end_time='0000-00-00 00:00:00'" %(param,tablename)
+sql =  "select %s from %s" %(param,tablename)
+cursor.execute(sql)
+res = cursor.fetchall()
+df_diag_ram3= pd.DataFrame(res,columns=param.split(','))
+
+df_diag_ram3['id']=list(map(lambda x:str(x),list(df_diag_ram3['id'])))
+df_diag=pd.merge(df_diag_ram2,df_diag_ram3,how='left',left_on=['child_tag','tag_type'],right_on=['id','parent_id'])
+
+df_diag['fault_time']=list(map(lambda x:str(x),list(df_diag['fault_time'])))
+df_diag2=pd.merge(df_diag,df_diag_ram,how='left',left_on=['fault_time','sn','fault_code'],right_on=['start_time','product_id','code'])
+df_diag3=df_diag2.sort_values(by='update_time',ascending=False)
+
+df=df_diag2[df_diag2['name']==fault_name]
+df.reset_index(drop=True,inplace=True)
+
+dataset=pd.DataFrame()
+for k in range(len(df)):
+    try: 
+        sn =df.loc[k,'product_id']
+        start_time=str(df.loc[k,'start_time'])
+        end_time=df.loc[k,'end_time']
+        if end_time=='0000-00-00 00:00:00':
+            end_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')   #type: str
+        df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms'])
+        data_bms = df_data['bms']
+        data_bms['sn']=sn   
+        dataset=dataset.append(data_bms)
+        dataset.to_csv('LIB/MIDDLE/FaultClass/V1_0_0/data/fault_'+fault_name+'.csv')
+    except Exception as e:
+        print(repr(e))
+        mylog.logopt(sn,e)
+        pass 
+
+df_bms=make_fault_set(dataset,cols,col_key,compare,threshold_filtre,fault_name)
+nor=normalset2(df_bms1,df_bms2,df_bms3,df_bms4,df_bms5,df_bms6,cols)
+scaler,model,acc=pre_model(nor,df_bms,time_steps,nbr_features,nbr_neurons,nbr_class,batch_size,epochs,dropout,lr,activation,loss)
+df_acc=pd.DataFrame({'fault_name':[fault_name],'accuracy':[acc]})
+df_acc.to_sql("faultclass_output",con=db_res_engine, if_exists="append",index=False)
+
+if acc>threshold_accuracy:
+    model.save('models/model_'+fault_name+'.h5')
+    pickle.dump(scaler,open('models/scaler_'+fault_name+'.pkl','wb'))

二进制
LIB/MIDDLE/FaultClass/V1_0_0/models/model_B板采样失效.h5


二进制
LIB/MIDDLE/FaultClass/V1_0_0/models/model_传感器_电芯NTC漂移.h5


二进制
LIB/MIDDLE/FaultClass/V1_0_0/models/model_电压采样断线.h5


二进制
LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_B板采样失效.pkl


二进制
LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_传感器_电芯NTC漂移.pkl


二进制
LIB/MIDDLE/FaultClass/V1_0_0/models/scaler_电压采样断线.pkl


+ 262 - 0
LIB/MIDDLE/FaultDetection/V1_0_2/aelstm.py

@@ -0,0 +1,262 @@
+import pandas as pd
+import numpy as np
+import datetime
+from sklearn.preprocessing import StandardScaler
+import tensorflow.keras as keras
+from LIB.BACKEND import DataPreProcess
+
+def data_groups(data_bms,sn,start_time,end_time):
+    data_bms=data_bms.drop(['GSM信号','外电压','开关状态','故障等级','故障代码','绝缘电阻','上锁状态','加热状态','单体均衡状态','总输出状态'],axis=1,errors='ignore')
+    data_set=pd.DataFrame()
+    data_set['时间戳'] = pd.date_range(start=start_time, end=end_time, freq='T')  #每分钟一条记录
+    for i in range(len(data_set)):
+        data_set.loc[i,'时间戳'] = data_set.loc[i,'时间戳'].replace(second=0) 
+    #给数据重建新特征:充放电状态,序列
+    if len(data_bms['总电流[A]']==0)>0:
+        if sn[:4] in ['MGMC','UD02']:
+            data_bms=DataPreProcess.DataPreProcess.data_split_by_status_forMGMCUD02(DataPreProcess, data_bms, drive_interval_threshold=120, charge_interval_threshold=300,drive_stand_threshold=120, charge_stand_threshold=300)
+        else:
+            data_bms=DataPreProcess.DataPreProcess.data_split_by_status(DataPreProcess, data_bms, drive_interval_threshold=120, charge_interval_threshold=300,drive_stand_threshold=120, charge_stand_threshold=300)
+    else:
+        data_bms['data_split_by_status']=1
+        data_bms['data_status']='work'     
+    #构建等差时间序列
+    data_bms['时间戳']=pd.to_datetime(data_bms['时间戳'])
+    for i in range(len(data_bms)):
+        data_bms.loc[i,'时间戳'] = data_bms.loc[i,'时间戳'].replace(second=0) 
+    data_bms.drop_duplicates(subset='时间戳',keep='last',inplace=False)
+    data_bms2=pd.merge(data_set,data_bms,on='时间戳',how='left')
+    data_bms2=data_bms2.fillna(method='ffill')
+    data_bms2=data_bms2.fillna(method='bfill')   
+    data_bms2.drop_duplicates(subset='时间戳',keep='last',inplace=True)
+    data_bms2=data_bms2.reset_index()
+    #删除无用特征
+    data_bms2=data_bms2.drop(['Unnamed: 0','level_0','index','Unnamed: 0.1','充电状态','data_split_by_crnt'],axis=1,errors='ignore')
+    #按状态分表
+    data_stand=data_bms2[data_bms2['data_status']=='stand']
+    return data_stand
+
+def split(data0):
+    data0=data0.reset_index(drop=True)
+    data0=data0.drop(['Unnamed: 0','Unnamed: 0.1'],axis=1,errors='ignore')
+    data0['n_split']=np.nan
+    data1=data0.copy()
+    data1.drop_duplicates(subset=['data_split_by_status'],keep='first',inplace=True)
+    data1['n_split']=range(1,len(data1)+1)
+    data0.loc[data1.index,'n_split']=list(data1['n_split'])
+    data0['n_split']=list(data0['n_split'].fillna(method='ffill'))
+    return data0
+          
+#特征工程I
+def makedataset(data_set):
+    listT1=[s for s in list(data_set) if '单体温度' in s]
+    listT2=[s for s in list(data_set) if '其他温度' in s]
+    data_set=data_set.drop(["单体温度"+str(i) for i in range(1,len(listT1)+1)],axis=1)
+    data_set=data_set.drop(["其他温度"+str(i) for i in range(1,len(listT2)+1)],axis=1)
+    data_set=data_set.drop(['单体压差'],axis=1)
+    return data_set
+#特征工程II
+def makedataset2(data_set):
+    listV=[s for s in list(data_set) if '单体电压' in s]
+    data_set=data_set.drop(["单体电压"+str(i) for i in range(1,len(listV)+1)],axis=1)
+    data_set=data_set.drop(['总电压[V]','单体压差','SOC[%]','其他温度3'],axis=1,errors='ignore')
+    return data_set
+
+def makescaler_test(scaler,data_test):
+    data_test=data_test.reset_index(drop=True)
+    data_test_pro=data_test.drop(['时间戳','sn'],axis=1)
+    test_sc=data_test_pro.drop('n_split',axis=1)
+    test_sc=scaler.transform(np.array(test_sc))
+    test_sc=pd.DataFrame(test_sc)
+    test_sc['n_split']=data_test_pro['n_split'].values
+    return test_sc
+
+#滑窗
+def create_dataset(data_set,data_train,time_steps=5):   #X为dataframe,y为serie
+    a,b=[],[] 
+    index=pd.DataFrame()
+    List_n_split=sorted(list(set(data_set['n_split'])))
+    for k in List_n_split:
+        dataset=data_set[data_set['n_split']==k]
+        datatrain=data_train[data_train['n_split']==k]
+        if len(dataset)>time_steps:
+            dataset2=dataset.reset_index(drop=True)
+            dataset=dataset.drop(['n_split'],axis=1)
+            dataX, dataY = [], []
+            index_step=[]
+            for i in range(len(dataset)-time_steps):      
+                v1 = dataset.iloc[i:(i+time_steps)].values
+                v2 = dataset.iloc[i+time_steps]
+                dataX.append(v1)
+                dataY.append(v2)
+                index_step.append(i)
+            dataset3=dataset2.iloc[:len(dataset2)-time_steps]
+            newdatatrain=datatrain[:len(dataset3)]
+            newdatatrain2=newdatatrain.copy()
+            newdatatrain2['window_step']=index_step
+            dataX2=np.array(dataX)
+            dataY2=np.array(dataY)
+            a.append(dataX2)             
+            b.append(dataY2)
+            index=index.append(newdatatrain2)
+    aa=np.vstack(a)
+    bb=np.vstack(b) 
+    return aa,bb,index
+
+def pred(Test,model):
+    test_pred = model.predict(Test)
+    test_loss = np.mean(np.abs(test_pred - Test), axis=1)
+    return test_loss
+
+def ref(test_loss,new_test):
+    test_loss_sum=test_loss.sum(axis=1)
+    test_loss_max=test_loss.max(axis=1)
+    ref_test=new_test[['n_split','window_step']].reset_index(drop=True)
+    ref_test['test_loss_sum']=list(map(lambda x: round(x,3),test_loss_sum))
+    ref_test['test_loss_max']=list(map(lambda x: round(x,3),test_loss_max))
+    return ref_test
+
+def prediction(df_stand,scaler,scaler2,model,model2):
+    data_set_test=df_stand.drop(['Unnamed: 0','index','总电流[A]','SOH[%]','data_split_by_status','data_status'],axis=1,errors='ignore')
+    dataset1_test=makedataset(data_set_test)
+    dataset2_test=makedataset2(data_set_test)
+    test_sc=makescaler_test(scaler,dataset1_test)
+    test_sc2=makescaler_test(scaler2,dataset2_test)
+    data_test_int=create_dataset(test_sc,dataset1_test,5)
+    Test=data_test_int[0]
+    data_test_int2=create_dataset(test_sc2,dataset2_test,5)
+    Test2=data_test_int2[0]
+    new_test=data_test_int[2]
+    new_test2=data_test_int2[2]
+    test_loss1=pred(Test,model)
+    test_loss2=pred(Test2,model2)
+    ref_test=ref(test_loss1,new_test)
+    ref_test2=ref(test_loss2,new_test2)
+    new_test['test_lossV_sum']=list(ref_test['test_loss_sum'])
+    new_test['test_lossV_max']=list(ref_test['test_loss_max']) 
+    new_test2['test_lossTemp_sum']=list(ref_test2['test_loss_sum'])
+    new_test2['test_lossTemp_max']=list(ref_test2['test_loss_max'])
+    res_test=pd.merge(new_test, new_test2, left_index=True, right_index=True,suffixes=('', '_y'))
+    res_test=res_test.drop(['sn_y','n_split_y','window_step_y','时间戳_y'],axis=1)
+    #根据异常指数设置阈值判定异常
+    res=res_test[(res_test['test_lossTemp_sum']>5) | (res_test['test_lossV_sum']>10) | (res_test['test_lossV_max']>4) | (res_test['test_lossTemp_max']>2)]
+    return res
+
+def makeres1(res):
+    df_res=pd.DataFrame(columns=['product_id','n_split','AnoScoreV_sum_max','AnoScoreV_max_max','AnoScoreT_sum_max','AnoScoreT_max_max'])
+    maxVsum=list(res['test_lossV_sum'].groupby(res['n_split']).max())
+    maxTsum=list(res['test_lossTemp_sum'].groupby(res['n_split']).max())
+    maxTmax=list(res['test_lossTemp_max'].groupby(res['n_split']).max())
+    maxVmax=list(res['test_lossV_max'].groupby(res['n_split']).max())
+    df_res['n_split']=list(res['test_lossV_sum'].groupby(res['n_split']).max().index)
+    sn= list(map(lambda x: list(res[res['n_split']==x]['sn'])[0], list(df_res['n_split'].values)))
+    df_res['product_id']=sn
+    df_res['AnoScoreV_sum_max']=maxVsum
+    df_res['AnoScoreV_max_max']=maxVmax
+    df_res['AnoScoreT_sum_max']=maxTsum
+    df_res['AnoScoreT_max_max']=maxTmax
+    listT2=[s for s in list(res) if '其他温度' in s]
+    if len(listT2)>0:
+        for k in listT2:
+            temp=list(res[k].groupby(res['n_split']).max())
+            df_res[k]=temp
+    df_res['最大其他温度']= df_res[[k for k in listT2]].max(axis=1)
+    df_res=df_res.drop([k for k in listT2],axis=1)
+    return df_res
+
+def makeres2(res):  
+    df_res=pd.DataFrame(columns=['start_time','end_time','product_id','n_split','code','level','SOC[%]','AnoScoreV_sum_start','AnoScoreT_sum_start','AnoScoreV_sum_end','AnoScoreT_sum_end','AnoScoreV_max_start','AnoScoreT_max_start','AnoScoreV_max_end','AnoScoreT_max_end','info','advice'])
+    res_start=res.drop_duplicates(subset=['n_split'],keep='first',inplace=False)
+    res_end=res.drop_duplicates(subset=['n_split'],keep='last',inplace=False)
+    start=list(res_start['时间戳'].values)
+    end=list(res_end['时间戳'].values)
+    product_id=list(res_start['sn'].values)
+    soc=list(res_start['SOC[%]'].values)
+    AnoScoreV_sum_start=list(res_start['test_lossV_sum'].values)
+    AnoScoreT_sum_start=list(res_start['test_lossTemp_sum'].values)
+    AnoScoreV_sum_end=list(res_end['test_lossV_sum'].values)
+    AnoScoreT_sum_end=list(res_end['test_lossTemp_sum'].values)
+    AnoScoreV_max_start=list(res_start['test_lossV_max'].values)
+    AnoScoreT_max_start=list(res_start['test_lossTemp_max'].values)
+    AnoScoreV_max_end=list(res_end['test_lossV_max'].values)
+    AnoScoreT_max_end=list(res_end['test_lossTemp_max'].values)
+    df_res['n_split']=list(res['test_lossV_sum'].groupby(res['n_split']).max().index)
+    df_res['start_time']=start
+    df_res['end_time']=end
+    df_res['product_id']=product_id
+    df_res['SOC[%]']=soc
+    df_res['AnoScoreV_sum_start']=AnoScoreV_sum_start
+    df_res['AnoScoreT_sum_start']=AnoScoreT_sum_start
+    df_res['AnoScoreV_sum_end']=AnoScoreV_sum_end
+    df_res['AnoScoreT_sum_end']=AnoScoreT_sum_end
+    df_res['AnoScoreV_max_start']=AnoScoreV_max_start
+    df_res['AnoScoreT_max_start']=AnoScoreT_max_start
+    df_res['AnoScoreV_max_end']=AnoScoreV_max_end
+    df_res['AnoScoreT_max_end']=AnoScoreT_max_end
+    return df_res
+
+def difftime(delta):
+    seconds = delta.total_seconds() 
+    minutes = seconds/60 
+    return minutes
+
+def diffmin(res):
+    start=list(res['start_time'])
+    end=list(res['end_time'])
+    start=list(map(lambda x: datetime.datetime.strptime(str(x),'%Y-%m-%d %H:%M:%S'),start))
+    end=list(map(lambda x: datetime.datetime.strptime(str(x),'%Y-%m-%d %H:%M:%S'),end))
+    diff=np.array(end)-np.array(start)
+    diff_min=list(map(lambda x: difftime(x),diff))
+    return diff_min
+
+def makeres(res,end_time): 
+    df_res1=makeres1(res)
+    df_res2=makeres2(res)
+    df_res=pd.merge(df_res1,df_res2,left_on='n_split', right_on='n_split')
+    diff_min=diffmin(df_res)
+    df_res['diff_min']=diff_min
+    df_res.reset_index(drop=True,inplace=True)
+    end=datetime.datetime.strptime(str(df_res.loc[len(df_res)-1,'end_time']),'%Y-%m-%d %H:%M:%S')
+    end_time=datetime.datetime.strptime(str(end_time),'%Y-%m-%d %H:%M:%S')
+    diff=(end_time-end).total_seconds()
+    if diff<600:
+        df_res.loc[len(df_res)-1,'end_time']='0000-00-00 00:00:00'
+    return df_res,diff
+
+def threshold(res,group,end_time):
+    df_res,diff=makeres(res,end_time)
+    #删除SOC过低导致的欠压
+    df_res=df_res[(df_res['diff_min']>60) | (df_res['SOC[%]']>10) | (df_res['AnoScoreT_sum_max']>5) | (df_res['AnoScoreV_sum_max']>50) | (df_res['AnoScoreV_max_max']>9) | (df_res['AnoScoreT_max_max']>2)]
+    #删除PK系列其他温度非故障升高
+    if group in ['PK504','PK502','PK500']:
+        df_res=df_res[(df_res['diff_min']>20) | (df_res['最大其他温度']>80) |(df_res['AnoScoreT_sum_max']>15) | (df_res['AnoScoreV_sum_max']>10) | (df_res['AnoScoreV_max_max']>4) | (df_res['AnoScoreT_max_max']>8)]
+    #删除PK504满充导致的过压
+    if group=='PK504':
+        df_res=df_res[((df_res['diff_min']>10) & (df_res['AnoScoreV_sum_max']>35)) | (df_res['SOC[%]']<93)| (df_res['AnoScoreT_sum_max']>5) | (df_res['AnoScoreV_max_max']>6) | (df_res['AnoScoreT_max_max']>2)]
+    df_res=df_res.drop(['n_split','product_id_y','AnoScoreV_sum_start','AnoScoreV_max_start','AnoScoreT_sum_start','AnoScoreT_max_start','AnoScoreV_sum_end','AnoScoreT_sum_end','AnoScoreT_max_end','AnoScoreV_max_end','最大其他温度'],axis=1,errors='ignore')
+    df_res=df_res.rename(columns = {"product_id_x": "product_id"})
+    df_res=df_res.rename(columns = {"SOC[%]": "SOC"})
+    df_res2=df_res[['product_id','start_time','end_time','diff_min','SOC','AnoScoreV_sum_max','AnoScoreV_max_max','AnoScoreT_sum_max','AnoScoreT_max_max']]
+    df_res2['start_time']=list(map(lambda x:str(x),list(df_res2['start_time'])))
+    df_res2['end_time']=list(map(lambda x:str(x),list(df_res2['end_time'])))
+    return df_res2,diff
+
+def arrange(result,result_final,start_time,diff):
+    result=result.reset_index(drop=True)
+    start=datetime.datetime.strptime(str(result.loc[0,'start_time']),'%Y-%m-%d %H:%M:%S')
+    start_time=datetime.datetime.strptime(str(start_time),'%Y-%m-%d %H:%M:%S')
+    diff_time=(start-start_time).total_seconds()
+    if diff_time<600:
+        result_final['end_time']=result.loc[0,'end_time']
+        diff_min_org=result_final['diff_min']
+        diff_min_new=result.loc[0,'diff_min']
+        result_final['diff_min']=diff_min_org+diff_time+diff+diff_min_new
+        result=result.drop(0)
+    return result,result_final
+
+
+
+
+
+
+

+ 179 - 0
LIB/MIDDLE/FaultDetection/V1_0_2/main_pred.py

@@ -0,0 +1,179 @@
+
+from LIB.MIDDLE.FaultDetection.V1_0_2.aelstm import *
+import pymysql
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager
+dbManager = DBManager.DBManager()
+from sqlalchemy import create_engine
+from urllib import parse
+import datetime, time
+from apscheduler.schedulers.blocking import BlockingScheduler
+import traceback
+import pickle
+from keras.models import load_model
+import logging
+import logging.handlers
+import os
+import re
+
+
+#...................................故障检测函数......................................................................................................................
+def diag_cal():
+    global SNnums
+    global scaler_dict, scaler2_dict, model_dict, model2_dict
+
+    start=time.time()
+    now_time=datetime.datetime.now()
+    start_time=now_time-datetime.timedelta(hours=3)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=now_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    #数据库配置
+    host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+    port=3306
+    db='safety_platform'
+    user='qx_read'
+    password='Qx@123456'
+
+    #读取结果库数据......................................................
+    param='product_id,start_time,end_time,diff_min,SOC,AnoScoreV_sum_max,AnoScoreV_max_max,AnoScoreT_sum_max,AnoScoreT_max_max'
+    tablename='fault_detection'
+    mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+    cursor = mysql.cursor()
+    sql =  "select {} from {} where end_time='0000-00-00 00:00:00'".format(param,tablename)
+    cursor.execute(sql)
+    res = cursor.fetchall()
+    df_diag_ram= pd.DataFrame(res,columns=param.split(','))
+    
+
+    db_res_engine = create_engine(
+        "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
+            user, parse.quote_plus(password), host, port, db
+        ))
+        
+    #调用主函数................................................................................................................................................................
+    for sn in SNnums:
+        try:
+            group=sn[:5]
+            if group=='UD020':
+                group='MGMCL'
+            df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms'])
+            data_bms = df_data['bms']
+            data_bms['sn']=sn
+            if len(data_bms)>0:
+                logger.info("SN: {} 数据开始预处理".format(sn))
+                data_stand=data_groups(data_bms,sn,start_time,end_time)
+                df_stand=split(data_stand)   
+                res=pd.DataFrame()
+                if len(df_stand)>0:
+                    #读取训练产出的缩放指标:均值&方差
+                    logger.info("SN: {} 数据开始模型预测".format(sn))
+                    scaler = scaler_dict[group]
+                    scaler2 = scaler2_dict[group]
+                    #读取训练产出的模型状态空间:电压模型&温度模型
+                    model = model_dict[group]
+                    model2 = model2_dict[group]
+                    res=prediction(df_stand,scaler,scaler2,model,model2)
+                    if len(res)>0:
+                        df_res2,diff=threshold(res,group,end_time)
+                        df_diag_ram_sn=df_diag_ram[df_diag_ram['product_id']==sn]
+                        if not df_diag_ram_sn.empty:   #该sn相关结果非空
+                            new_res,update_res=arrange(df_res2,df_diag_ram_sn,start_time,diff)
+                            if len(update_res)>0:
+                                cursor.execute("DELETE FROM fault_detection WHERE end_time = '0000-00-00 00:00:00' and product_id='{}'".format(sn))
+                                mysql.commit()
+                                update_res.to_sql("fault_detection",con=db_res_engine, if_exists="append",index=False)
+                            #新增结果存入结果库................................................................
+                            if len(new_res)>0:
+                                new_res.to_sql("fault_detection",con=db_res_engine, if_exists="append",index=False)
+                        else:
+                            df_res2.to_sql("fault_detection",con=db_res_engine, if_exists="append",index=False)
+
+            # end=time.time()
+            # print(end-start)  
+                
+        except Exception as e:
+            logger.error(str(e))
+            logger.error(traceback.format_exc())
+
+    cursor.close()
+    mysql.close()
+
+#...............................................主函数起定时作用.......................................................................................................................
+if __name__ == "__main__":
+    
+    # 日志
+    log_path = 'log/'
+    if not os.path.exists(log_path):
+        os.makedirs(log_path)
+    logger = logging.getLogger("main")
+    logger.setLevel(logging.DEBUG)
+    
+     # 根据日期滚动(每天产生1个文件)
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_info.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.INFO)
+    logger.addHandler(fh)
+
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_error.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.ERROR)
+    logger.addHandler(fh)
+
+    logger.info("pid is {}".format(os.getpid()))
+    
+     # # 更新sn列表
+    host='rm-bp10j10qy42bzy0q7.mysql.rds.aliyuncs.com'
+    port=3306
+    db='qixiang_oss'
+    user='qixiang_oss'
+    password='Qixiang2021'
+    conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db)
+    cursor = conn.cursor()
+    cursor.execute("select sn, imei, add_time from app_device where status in (1,2,3)")
+    res = cursor.fetchall()
+    df_sn = pd.DataFrame(res, columns=['sn', 'imei', 'add_time'])
+    df_sn = df_sn.reset_index(drop=True)
+    conn.close();
+    
+    SNnums = list(df_sn['sn'])
+    
+    scaler_list=[]
+    scaler2_list=[]
+    model_list=[]
+    model2_list=[]
+    for group in ['MGMLX','PK504','PK502','PK500','MGMCL']:
+        scaler = pickle.load(open('LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_'+group+'_10.pkl', 'rb'))
+        scaler2 = pickle.load(open('LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_'+group+'_10.pkl', 'rb'))
+        model = load_model('LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_'+group+'_10.h5')
+        model2 = load_model('LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_'+group+'_10.h5')
+        scaler_list.append(scaler)
+        scaler2_list.append(scaler2)
+        model_list.append(model)
+        model2_list.append(model2)
+    scaler_dict={'MGMLX':scaler_list[0],'PK504':scaler_list[1],'PK502':scaler_list[2],'PK500':scaler_list[3],'MGMCL':scaler_list[4]}
+    scaler2_dict={'MGMLX':scaler2_list[0],'PK504':scaler2_list[1],'PK502':scaler2_list[2],'PK500':scaler2_list[3],'MGMCL':scaler2_list[4]}
+    model_dict={'MGMLX':model_list[0],'PK504':model_list[1],'PK502':model_list[2],'PK500':model_list[3],'MGMCL':model_list[4]}
+    model2_dict={'MGMLX':model2_list[0],'PK504':model2_list[1],'PK502':model2_list[2],'PK500':model2_list[3],'MGMCL':model2_list[4]}
+    logger.info("模型加载完成")
+
+    diag_cal()
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', hours=3)
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        logger.error(str(e))
+        logger.error(traceback.format_exc())

二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_MGMCL_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_MGMLX_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_PK500_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_PK502_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelT_PK504_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_MGMCL_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_MGMLX_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_PK500_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_PK502_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/modelV_PK504_10.h5


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_MGMCL_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_MGMLX_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_PK500_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_PK502_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerT_PK504_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_MGMCL_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_MGMLX_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_PK500_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_PK502_10.pkl


二进制
LIB/MIDDLE/FaultDetection/V1_0_2/train_out/scalerV_PK504_10.pkl


+ 27 - 2
LIB/MIDDLE/InfoChrgDrive/Charge/V1_0_0/coreV0.py

@@ -435,7 +435,7 @@ def pro_output(df_merge,sn,gpscity,chrg_last):
     return new,change
 
 ############################ Test ##########################
-def prediction(datatest,kmeans1,kmeans2,kmeans3):
+def prediction(datatest,kmeans1,kmeans2,kmeans3,kmeans4,kmeans5):
     if len(datatest)>0:
         datatest.reset_index(drop=True,inplace=True)
         #筛选充电数据
@@ -447,7 +447,8 @@ def prediction(datatest,kmeans1,kmeans2,kmeans3):
         Xt=pd.concat([X00t,X01t])
         #按温度切分数据
         Xt1=Xt[Xt['airtemp_st']>=18]
-        Xt2=Xt[Xt['airtemp_st']<18]
+        Xt2=Xt[(Xt['airtemp_st']<18)&(Xt['airtemp_st']>=10)]
+        Xt3=Xt[Xt['airtemp_st']<10]
         #温暖天气模型预测
         if len(Xt1)>0:
             #KMeans1
@@ -484,4 +485,28 @@ def prediction(datatest,kmeans1,kmeans2,kmeans3):
                     Xt182=Xt17[Xt17['cluster_db']==1]
                     for k in list(Xt182.index):
                         datatest.loc[k,'charge_env']='疑似室内'
+        if len(Xt2)>0:
+            #KMeans4
+            Xt21=Xt2[['standtime_f','temp_incr']]
+            y_hat = kmeans4.predict(np.array(Xt21))
+            Xt21['cluster_db']=y_hat
+            Xt221=Xt21[(Xt21['cluster_db']==0)|(Xt21['cluster_db']==1)]
+            Xt221['charge_env']='室外'
+            datatest=pd.merge(datatest,Xt221['charge_env'],how='outer',right_index=True,left_index=True)
+            #KMeans5
+            Xt22=Xt21[(Xt21['cluster_db']==2)|(Xt21['cluster_db']==3)]
+            if len(Xt22)>0:
+                Xt23=pd.merge(Xt22['cluster_db'],Xt2,how='left',right_index=True,left_index=True)
+                Xt24=Xt23[['standtime_f','delta_time']]
+                y_hat2 = kmeans5.predict(np.array(Xt24))
+                Xt24['cluster_db']=y_hat2
+                Xt251=Xt24[(Xt24['cluster_db']==0)|(Xt24['cluster_db']==2)]
+                for k in list(Xt251.index):
+                    datatest.loc[k,'charge_env']='室外'
+                Xt250=Xt24[Xt24['cluster_db']==1]
+                for k in list(Xt250.index):
+                    datatest.loc[k,'charge_env']='室内'
+                Xt252=Xt24[Xt24['cluster_db']==3]
+                for k in list(Xt252.index):
+                    datatest.loc[k,'charge_env']='疑似室内'
     return datatest

二进制
LIB/MIDDLE/InfoChrgDrive/Charge/kmeans4.pkl


二进制
LIB/MIDDLE/InfoChrgDrive/Charge/kmeans5.pkl


+ 65 - 25
LIB/MIDDLE/InfoChrgDrive/Charge/main_V0.py

@@ -1,19 +1,22 @@
-from coreV0 import *
+from LIB.MIDDLE.InfoChrgDrive.Charge.V1_0_0.coreV0 import *
 import pymysql
 import datetime
 import pandas as pd
 from LIB.BACKEND import DBManager
+dbManager = DBManager.DBManager()
 from sqlalchemy import create_engine
 from urllib import parse
 import datetime, time
 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 LIB.MIDDLE.CellStateEstimation.Common import log
+import os
+import traceback
+import logging
+import logging.handlers
 
 #...................................充电技术指标统计函数......................................................................................................................
 def diag_cal():
     global SNnums
+    global kmeans1,kmeans2,kmeans3,kmeans4,kmeans5
 
     start=time.time()
     now_time=datetime.datetime.now()
@@ -24,9 +27,9 @@ def diag_cal():
     #数据库配置
     host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
     port=3306
-    db='qx_cas'
-    user='qx_read'
-    password='Qx@123456'
+    db='safety_platform'
+    user='qx_algo_rw'
+    password='qx@123456'
 
     #读取结果库数据......................................................
     param='sn,time_st,time_end,status,delta_time,soc_st,soc_end,volt_st,volt_end,diffvolt_st,diffvolt_end, \
@@ -46,8 +49,6 @@ def diag_cal():
             user, parse.quote_plus(password), host, port, db
         ))
 
-    mylog=log.Mylog('log_info_charge.txt','error')
-    mylog.logcfg()
 
     for sn in SNnums:
         try:
@@ -59,7 +60,7 @@ def diag_cal():
             df_gps = df_data['gps']
 
             #读取城市天气数据........................................................................................................................................................
-            gpscity=pd.read_csv('gps.csv')
+            gpscity=pd.read_csv('LIB/MIDDLE/InfoChrgDrive/Charge/gps.csv')
             
 
             #调用主函数................................................................................................................................................................
@@ -78,11 +79,9 @@ def diag_cal():
                         time_end=chrg_last['time_end']
 
                 df_diag_new,df_diag_change=pro_output(df_merge,sn,gpscity,chrg_last)
-                kmeans1 = joblib.load('kmeans1.pkl')
-                kmeans2 = joblib.load('kmeans2.pkl')
-                kmeans3 = joblib.load('kmeans3.pkl')
-                df_diag_new=prediction(df_diag_new,kmeans1,kmeans2,kmeans3)
-                df_diag_change=prediction(df_diag_change,kmeans1,kmeans2,kmeans3)
+
+                df_diag_new=prediction(df_diag_new,kmeans1,kmeans2,kmeans3,kmeans4,kmeans5)
+                df_diag_change=prediction(df_diag_change,kmeans1,kmeans2,kmeans3,kmeans4,kmeans5)
                 if not df_diag_change.empty:   #需变更的结果非空
                     cursor.execute("DELETE FROM algo_charge_info WHERE time_end = '{}' and sn='{}'".format(time_end,sn))
                     mysql.commit()
@@ -96,22 +95,63 @@ def diag_cal():
             print(end-start)  
             
         except Exception as e:
-            print(repr(e))
-            mylog.logopt(e)
+            logger.error(str(e))
+            logger.error(traceback.format_exc())
 
     cursor.close()
     mysql.close()
 
 #...............................................主函数起定时作用.......................................................................................................................
 if __name__ == "__main__":
+    # 日志
+    log_path = 'log/'
+    if not os.path.exists(log_path):
+        os.makedirs(log_path)
+    logger = logging.getLogger("main")
+    logger.setLevel(logging.DEBUG)
     
-    #excelpath=r'D:\Platform\platform_python\data_analyze_platform\USER\spf\01qixiang\sn-20210903.xlsx'
-    excelpath='sn-20210903.xlsx'
-    dataSOH = pd.read_excel('sn-20210903.xlsx',sheet_name='sn-20210903')
-    SNnums = list(dataSOH['sn'])
+     # 根据日期滚动(每天产生1个文件)
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_info.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.INFO)
+    logger.addHandler(fh)
+
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_error.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.ERROR)
+    logger.addHandler(fh)
+
+    logger.info("pid is {}".format(os.getpid()))
+
+    # # 更新sn列表
+    host='rm-bp10j10qy42bzy0q7.mysql.rds.aliyuncs.com'
+    port=3306
+    db='qixiang_oss'
+    user='qixiang_oss'
+    password='Qixiang2021'
+    conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db)
+    cursor = conn.cursor()
+    cursor.execute("select sn, imei, add_time from app_device where status in (1,2,3)")
+    res = cursor.fetchall()
+    df_sn = pd.DataFrame(res, columns=['sn', 'imei', 'add_time'])
+    df_sn = df_sn.reset_index(drop=True)
+    conn.close();
     
-    mylog=log.Mylog('log_info_charge.txt','error')
-    mylog.logcfg()
+    SNnums = list(df_sn['sn'])
+
+    kmeans1 = joblib.load('LIB/MIDDLE/InfoChrgDrive/Charge/kmeans1.pkl')
+    kmeans2 = joblib.load('LIB/MIDDLE/InfoChrgDrive/Charge/kmeans2.pkl')
+    kmeans3 = joblib.load('LIB/MIDDLE/InfoChrgDrive/Charge/kmeans3.pkl')
+    kmeans4 = joblib.load('LIB/MIDDLE/InfoChrgDrive/Charge/kmeans4.pkl')
+    kmeans5 = joblib.load('LIB/MIDDLE/InfoChrgDrive/Charge/kmeans5.pkl')
 
     diag_cal()
     #定时任务.......................................................................................................................................................................
@@ -122,5 +162,5 @@ if __name__ == "__main__":
         scheduler.start()
     except Exception as e:
         scheduler.shutdown()
-        print(repr(e))
-        mylog.logopt(e)
+        logger.error(str(e))
+        logger.error(traceback.format_exc())

+ 283 - 0
LIB/MIDDLE/ThermoRunaway/V1_0_2/Trunaway.py

@@ -0,0 +1,283 @@
+from sklearn.preprocessing import StandardScaler 
+import keras
+import os
+import pandas as pd
+import numpy as np
+from LIB.BACKEND import DataPreProcess
+import datetime
+
+#数据预处理
+
+#删除采样异常点
+def delete(data_bms):
+    listV=[s for s in list(data_bms) if '单体电压' in s]
+    listT=[s for s in list(data_bms) if '单体温度' in s]
+    listT2=[s for s in list(data_bms) if '其他温度' in s]
+    #data_bms2=data_bms.copy()
+    for i in range(1,len(listV)+1):
+        data_bms=data_bms[(data_bms['单体电压'+str(i)]>1000) & (data_bms['单体电压'+str(i)]<6000)]
+    for i in range(1,len(listT)+1):
+        data_bms=data_bms[(data_bms['单体温度'+str(i)]>-20) & (data_bms['单体温度'+str(i)]<100)]
+    #for i in range(1,len(listT2)+1):
+        #data_bms=data_bms[(data_bms['其他温度'+str(1)]>-20) & (data_bms['其他温度'+str(1)]<100)]
+    #data_outliers=data_bms2.iloc[list(set(list(data_bms2.index)).difference(set(list(data_bms.index))))]
+    data_bms=data_bms.reset_index(drop=True)
+    return data_bms
+ 
+#构建时间序列&选取静置状态
+def data_groups(data_bms,sn,start_time,end_time):
+    data_bms=data_bms.drop(['GSM信号','外电压','开关状态','故障等级','故障代码','绝缘电阻','上锁状态','加热状态','单体均衡状态','总输出状态'],axis=1,errors='ignore')
+    data_set=pd.DataFrame()
+    start_time=start_time[:17]+'00'
+    end_time=end_time[:17]+'00'
+    data_set['时间戳'] = pd.date_range(start=start_time, end=end_time, freq='T')  #每分钟一条记录
+    #给数据重建新特征:充放电状态,序列
+    if len(data_bms['总电流[A]']==0)>0:
+        if sn[:4] in ['MGMC','UD02']:
+            #data_bms=rest_stscs_v1.cell_statistic.rest_sta(data_bms)
+            data_bms=DataPreProcess.DataPreProcess.data_split_by_status_forMGMCUD02(DataPreProcess, data_bms, drive_interval_threshold=120, charge_interval_threshold=300,drive_stand_threshold=120, charge_stand_threshold=300)
+        else:
+            data_bms=DataPreProcess.DataPreProcess.data_split_by_status(DataPreProcess, data_bms, drive_interval_threshold=120, charge_interval_threshold=300,drive_stand_threshold=120, charge_stand_threshold=300)
+    else:
+        data_bms['data_split_by_status']=1
+        data_bms['data_status']='work'     
+    #构建等差时间序列
+    data_bms['时间戳']=pd.to_datetime(data_bms['时间戳'])
+    for i in range(len(data_bms)):
+        data_bms.loc[i,'时间戳'] = data_bms.loc[i,'时间戳'].replace(second=0) 
+    data_bms.drop_duplicates(subset='时间戳',keep='last',inplace=False)
+    data_bms2=pd.merge(data_set,data_bms,on='时间戳',how='left')
+    data_bms2=data_bms2.fillna(method='ffill')
+    data_bms2=data_bms2.fillna(method='bfill')   
+    data_bms2.drop_duplicates(subset='时间戳',keep='last',inplace=True)
+    data_bms2=data_bms2.reset_index()
+    #删除无用特征
+    data_bms2=data_bms2.drop(['Unnamed: 0','level_0','index','Unnamed: 0.1','充电状态','data_split_by_crnt'],axis=1,errors='ignore')
+    #按状态分表
+    data_stand=data_bms2[data_bms2['data_status']=='stand']
+    return data_stand
+
+#标记时段
+def split(data0):
+    data0=data0.reset_index(drop=True)
+    data0=data0.drop(['Unnamed: 0','Unnamed: 0.1'],axis=1,errors='ignore')
+    data0['n_split']=np.nan
+    data1=data0.copy()
+    data1.drop_duplicates(subset=['data_split_by_status'],keep='first',inplace=True)
+    data1['n_split']=range(1,len(data1)+1)
+    data0.loc[data1.index,'n_split']=list(data1['n_split'])
+    data0['n_split']=list(data0['n_split'].fillna(method='ffill'))
+    time=list(map(lambda x: str(x),list(data0['时间戳'])))
+    data0['时间戳']=time
+    return data0
+
+
+
+####################################################################################################################
+
+#每10min一条记录:平均
+def create_dataset(data_set):   #X为dataframe,y为serie
+    data_set=data_set.drop(['总电流[A]','SOH[%]','data_status','data_split_by_status'],axis=1,errors='ignore')
+    time=list(map(lambda x: x[:15]+'0'+x[16:],list(data_set['时间戳'])))
+    data_set['时间戳']=time
+    List_n_split=sorted(list(set(data_set['n_split'])))
+    data_set2=pd.DataFrame()
+    for k in List_n_split:
+        dataset=data_set[data_set['n_split']==k]
+        if len(dataset)>10:
+            dataset=dataset.reset_index(drop=True)
+            sn=list(dataset['sn'].values)[0]
+            dataset=dataset.drop(['sn','n_split'],axis=1)
+            dataset2=dataset.groupby(dataset['时间戳']).mean()
+            dataset2=dataset2.reset_index()
+            dataset2['sn']=sn
+            dataset2['n_split']=k
+            data_set2=data_set2.append(dataset2)
+    return data_set2
+
+# 计算各单体电压下降量
+def cal_dataset(df_stand):   #X为dataframe,y为serie
+    List_n_split=sorted(list(set(df_stand['n_split'])))
+    listV=[s for s in list(df_stand) if '单体电压' in s]
+    listT=[s for s in list(df_stand) if '温度' in s]
+    newdataset=pd.DataFrame()
+    for k in List_n_split:
+        dataset=df_stand[df_stand['n_split']==k]
+        dataset=dataset.reset_index(drop=True)
+        dataset2=dataset[listV]
+        dataset3=dataset2.diff()   #periods=1, axis=0  
+        dataset3['最大电压下降']=dataset3[listV].min(axis=1)
+        dataset3['平均电压下降']=dataset3[listV].mean(axis=1)
+        dataset3['电压下降低偏']=dataset3[listV].mean(axis=1)-dataset3[listV].min(axis=1)
+        dataset3=dataset3.drop(listV+['平均电压下降'],axis=1)
+        dataset4=dataset.drop(listT+listV+['总电压[V]'],axis=1)
+        dataset5=pd.merge(dataset4,dataset3,left_index=True,right_index=True)
+        dataset5=dataset5.dropna(axis=0) 
+        newdataset=newdataset.append(dataset5) 
+    return newdataset 
+
+#每1hour一条记录:总和
+def timeserie(data_set):   #X为dataframe,y为serie
+    List_n_split=sorted(list(set(data_set['n_split'])))
+    time=list(map(lambda x: x[:14]+'00'+x[16:],list(data_set['时间戳'])))
+    data_set['时间戳']=time
+    data_set2=pd.DataFrame()
+    for k in List_n_split:
+        dataset=data_set[data_set['n_split']==k]
+        if len(dataset)>10:
+            dataset=dataset.reset_index(drop=True)
+            sn=list(dataset['sn'].values)[0]
+            soc=list(dataset['SOC[%]'].values)[0]
+            dataset=dataset.drop(['sn','n_split'],axis=1)
+            dataset2=dataset.groupby(dataset['时间戳']).sum()
+            dataset2=dataset2.reset_index()
+            dataset2['sn']=sn
+            dataset2['n_split']=k
+            dataset2['SOC[%]']=soc
+            data_set2=data_set2.append(dataset2)
+    return data_set2
+
+def makescaler_test(scaler,data_test):
+    data_test=data_test.reset_index(drop=True)
+    data_test_pro=data_test.drop(['n_split','时间戳','sn','SOC[%]'],axis=1)
+    test_sc=scaler.transform(np.array(data_test_pro))
+    test_sc=pd.DataFrame(test_sc)
+    test_sc['n_split']=data_test['n_split'].values
+    return test_sc
+
+#滑窗
+def create_win(data_set,data_train,time_steps=5):   #X为dataframe,y为serie
+    a,b=[],[] 
+    index=pd.DataFrame()
+    List_n_split=sorted(list(set(data_set['n_split'])))
+    for k in List_n_split:
+        dataset=data_set[data_set['n_split']==k]
+        datatrain=data_train[data_train['n_split']==k]
+        if len(dataset)>time_steps:
+            dataset2=dataset.reset_index(drop=True)
+            dataset=dataset.drop(['n_split'],axis=1)
+            dataX, dataY = [], []
+            index_step=[]
+            for i in range(len(dataset)-time_steps):      
+                v1 = dataset.iloc[i:(i+time_steps)].values
+                v2 = dataset.iloc[i+time_steps]
+                dataX.append(v1)
+                dataY.append(v2)
+                index_step.append(i)
+            dataset3=dataset2.iloc[:len(dataset2)-time_steps]
+            newdatatrain=datatrain[:len(dataset3)]
+            newdatatrain2=newdatatrain.copy()
+            newdatatrain2['window_step']=index_step
+            dataX2=np.array(dataX)
+            dataY2=np.array(dataY)
+            a.append(dataX2)             
+            b.append(dataY2)
+            index=index.append(newdatatrain2)
+    aa=np.vstack(a)
+    bb=np.vstack(b) 
+    return aa,bb,index
+
+def pred(Test,model):
+    test_pred = model.predict(Test)
+    test_loss = np.mean(np.abs(test_pred - Test), axis=1)
+    return test_loss
+
+def ref(test_loss,new_test):
+    test_loss_sum=test_loss.sum(axis=1)
+    test_loss_max=test_loss.max(axis=1)
+    ref_test=new_test.reset_index(drop=True)
+    ref_test['test_loss_sum']=test_loss_sum
+    ref_test['test_loss_max']=test_loss_max
+    ref_test['test_loss压差']=test_loss[:,0]
+    ref_test['test_loss降幅']=test_loss[:,1]
+    ref_test['test_loss降差']=test_loss[:,2]
+    return ref_test
+
+def difftime(delta):
+    seconds = delta.total_seconds() 
+    minutes = seconds/60 
+    return minutes
+
+def diffmin(res):
+    start=list(res['start_time'])
+    end=list(res['end_time'])
+    start=list(map(lambda x: datetime.datetime.strptime(str(x),'%Y-%m-%d %H:%M:%S'),start))
+    end=list(map(lambda x: datetime.datetime.strptime(str(x),'%Y-%m-%d %H:%M:%S'),end))
+    diff=np.array(end)-np.array(start)
+    diff_min=list(map(lambda x: difftime(x),diff))
+    return diff_min
+
+def res_output(TestOrg,scaler,model,group,end_time):
+    df_res=pd.DataFrame(columns=['product_id', 'start_time', 'end_time', 'diff_min','SOC','loss_sum','loss_max','diffV','downV','diffdownV'])
+    diff=0
+    test2=create_dataset(TestOrg)
+    test3=cal_dataset(test2)
+    newtest=timeserie(test3)
+    if len(newtest)>0:
+        test_sc=makescaler_test(scaler,newtest)
+        Test,y_test,win_test=create_win(test_sc,newtest,time_steps=3)
+        test_loss=pred(Test,model)
+        ref_test=ref(test_loss,win_test)
+        ref_test['test_loss_diff']=list(map(lambda x: x[0]-x[1], zip(list(ref_test['test_loss_sum']), list(ref_test['test_loss_max']))))
+
+        if group=='MGMCL':
+            res=ref_test[(ref_test['test_loss_max']>0.04) & (ref_test['SOC[%]']>15) & (ref_test['test_loss_sum']>0.06) & (ref_test['window_step']>0) &  (ref_test['最大电压下降']<-3)]
+        elif group=='PK504':
+            res=ref_test[(ref_test['test_loss_diff']>0.03) & (ref_test['test_loss_max']>0.03) & (ref_test['SOC[%]']>15) & (ref_test['window_step']>0) &  (ref_test['最大电压下降']<-3) &((ref_test['test_loss_sum']>3) | (ref_test['SOC[%]']<90))]
+        else:
+            res=ref_test[(ref_test['test_loss_diff']>0.6) & (ref_test['test_loss_max']>0.6) & (ref_test['SOC[%]']>15) & (ref_test['window_step']>0) &  (ref_test['电压下降低偏']>3.5) &((ref_test['test_loss_sum']>3) | (ref_test['SOC[%]']<90))]
+        
+        if len(res)>0:
+            res=res.reset_index()
+            for k in range(len(res)):
+                if res.loc[k,'最大电压下降']<-130:
+                    sn=res.loc[k,'sn']
+                    win=res.loc[k,'window_step']
+                    index = res[(res["sn"]== sn)&(res["window_step"]== win)].index.tolist()[0]
+                    res=res.drop([index-2,index-1,index],errors='ignore')
+           
+        if len(res)>0:  
+            maxsum=list(res['test_loss_sum'].groupby(res['n_split']).max())
+            maxmax=list(res['test_loss_max'].groupby(res['n_split']).max())
+            res_start=res.drop_duplicates(subset=['n_split'],keep='first',inplace=False)
+            res_end=res.drop_duplicates(subset=['n_split'],keep='last',inplace=False)
+            start=list(map(lambda x:str(x),list(res_start['时间戳'].values)))
+            end=list(map(lambda x:str(x),list(res_end['时间戳'].values)))
+            product_id=list(res_start['sn'].values)
+            df_res['product_id']=product_id
+            df_res['start_time']=start
+            df_res['end_time']=end
+            df_res['loss_sum']=list(map(lambda x:round(x,3),maxsum))
+            df_res['loss_max']=list(map(lambda x:round(x,3),maxmax))
+            soc=list(res_start['SOC[%]'].values)
+            df_res['SOC']=soc
+            df_res['diffV']=list(res_start['单体压差'].values)
+            df_res['downV']=list(res_start['最大电压下降'].values)
+            df_res['diffdownV']=list(res_start['电压下降低偏'].values)
+            #df_res['window_step']=list(res_start['window_step'].values)
+            diff_min=diffmin(df_res)
+            df_res['diff_min']=diff_min
+            df_res.reset_index(drop=True,inplace=True)
+            end=datetime.datetime.strptime(str(df_res.loc[len(df_res)-1,'end_time']),'%Y-%m-%d %H:%M:%S')
+            end_time=datetime.datetime.strptime(str(end_time),'%Y-%m-%d %H:%M:%S')
+            diff=(end_time-end).total_seconds()
+            if diff<600:
+                df_res.loc[len(df_res)-1,'end_time']='0000-00-00 00:00:00'
+    return df_res,diff
+
+##################################################################################################################
+
+
+def arrange(result,result_final,start_time,diff):
+    result=result.reset_index(drop=True)
+    start=datetime.datetime.strptime(str(result.loc[0,'start_time']),'%Y-%m-%d %H:%M:%S')
+    start_time=datetime.datetime.strptime(str(start_time),'%Y-%m-%d %H:%M:%S')
+    diff_time=(start-start_time).total_seconds()
+    if diff_time<600:
+        result_final['end_time']=result.loc[0,'end_time']
+        diff_min_org=result_final['diff_min']
+        diff_min_new=result.loc[0,'diff_min']
+        result_final['diff_min']=diff_min_org+(diff_time+diff)/60+diff_min_new
+        result=result.drop(0)
+    return result,result_final
+

+ 167 - 0
LIB/MIDDLE/ThermoRunaway/V1_0_2/main_pred.py

@@ -0,0 +1,167 @@
+
+from LIB.MIDDLE.ThermoRunaway.V1_0_2.Trunaway import *
+import pymysql
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager
+dbManager = DBManager.DBManager()
+from sqlalchemy import create_engine
+from urllib import parse
+import datetime, time
+from apscheduler.schedulers.blocking import BlockingScheduler
+import traceback
+import pickle
+from keras.models import load_model
+import logging
+import logging.handlers
+import os
+import re
+
+#...................................故障检测函数......................................................................................................................
+def diag_cal():
+    global SNnums
+
+    start=time.time()
+    now_time=datetime.datetime.now()
+    start_time=now_time-datetime.timedelta(hours=6)
+    start_time=start_time.strftime('%Y-%m-%d %H:%M:%S')
+    end_time=now_time.strftime('%Y-%m-%d %H:%M:%S')
+
+    #数据库配置
+    host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+    port=3306
+    db='safety_platform'
+    user='qx_read'
+    password='Qx@123456'
+
+    #读取结果库数据......................................................
+    param='product_id,start_time,end_time,diff_min,SOC,loss_sum,loss_max,diffV,downV,diffdownV'
+    tablename='thermo_runaway'
+    mysql = pymysql.connect (host=host, user=user, password=password, port=port, database=db)
+    cursor = mysql.cursor()
+    sql =  "select {} from {} where end_time='0000-00-00 00:00:00'".format(param,tablename)
+    cursor.execute(sql)
+    res = cursor.fetchall()
+    df_diag_ram= pd.DataFrame(res,columns=param.split(','))
+    
+
+    db_res_engine = create_engine(
+        "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
+            user, parse.quote_plus(password), host, port, db
+        ))
+    
+
+    
+
+    #调用主函数................................................................................................................................................................
+    for sn in SNnums:
+        try:
+            group=sn[:5]
+            df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms'])
+            data_bms = df_data['bms']
+            data_bms['sn']=sn
+            if len(data_bms)>0:
+                logger.info("SN: {} 数据开始预处理".format(sn))
+                data_bms=delete(data_bms)
+                data_stand=data_groups(data_bms,sn,start_time,end_time)
+                df_stand=split(data_stand)   
+                res=pd.DataFrame()
+                if len(df_stand)>0:
+                    #读取训练产出的缩放指标:均值&方差
+                    logger.info("SN: {} 数据开始模型预测".format(sn))
+                    scaler = scaler_dict[group]
+                    #读取训练产出的模型状态空间:电压模型&温度模型
+                    model = model_dict[group]
+                    res,diff=res_output(df_stand,scaler,model,group,end_time)
+
+                    df_diag_ram_sn=df_diag_ram[df_diag_ram['product_id']==sn]
+                    if not df_diag_ram_sn.empty:   #该sn相关结果非空
+                        new_res,update_res=arrange(res,df_diag_ram_sn,start_time,diff)
+                        if len(update_res)>0:
+                            cursor.execute("DELETE FROM thermo_runaway WHERE end_time = '0000-00-00 00:00:00' and product_id='{}'".format(sn))
+                            mysql.commit()
+                            update_res.to_sql("thermo_runaway",con=db_res_engine, if_exists="append",index=False)
+                        #新增结果存入结果库................................................................
+                        if len(new_res)>0:
+                            new_res.to_sql("thermo_runaway",con=db_res_engine, if_exists="append",index=False)
+                    else:
+                        res.to_sql("thermo_runaway",con=db_res_engine, if_exists="append",index=False)
+
+            # end=time.time()
+            # print(end-start)  
+                
+        except Exception as e:
+            logger.error(str(e))
+            logger.error(traceback.format_exc())
+
+    cursor.close()
+    mysql.close()
+
+#...............................................主函数起定时作用.......................................................................................................................
+if __name__ == "__main__":
+    
+    # 日志
+    log_path = 'log/'
+    if not os.path.exists(log_path):
+        os.makedirs(log_path)
+    logger = logging.getLogger("main")
+    logger.setLevel(logging.DEBUG)
+    
+     # 根据日期滚动(每天产生1个文件)
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_info.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.INFO)
+    logger.addHandler(fh)
+
+    fh = logging.handlers.TimedRotatingFileHandler(filename='{}/main_error.log'.format(log_path), when="D", interval=1, backupCount=30,
+                                                    encoding="utf-8")
+    formatter = logging.Formatter("%(asctime)s - %(name)s-%(levelname)s %(message)s")
+    fh.suffix = "%Y-%m-%d_%H-%M-%S"
+    fh.extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}")
+    fh.setFormatter(formatter)
+    fh.setLevel(logging.ERROR)
+    logger.addHandler(fh)
+
+    logger.info("pid is {}".format(os.getpid()))
+    
+     # # 更新sn列表
+    host='rm-bp10j10qy42bzy0q7.mysql.rds.aliyuncs.com'
+    port=3306
+    db='qixiang_oss'
+    user='qixiang_oss'
+    password='Qixiang2021'
+    conn = pymysql.connect(host=host, port=port, user=user, password=password, database=db)
+    cursor = conn.cursor()
+    cursor.execute("select sn, imei, add_time from app_device where status in (1,2,3)")
+    res = cursor.fetchall()
+    df_sn = pd.DataFrame(res, columns=['sn', 'imei', 'add_time'])
+    df_sn = df_sn.reset_index(drop=True)
+    conn.close();
+    
+    SNnums = list(df_sn['sn'])
+    
+    scaler_list=[]
+    model_list=[]
+    for group in ['PK504','MGMCL','PK500']:
+        scaler=pickle.load(open('LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_'+group+'_05.pkl', 'rb'))
+        model=load_model('LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_'+group+'_05.h5')
+        scaler_list.append(scaler)
+        model_list.append(model)
+    scaler_dict={'PK504':scaler_list[0],'MGMCL':scaler_list[1],'PK500':scaler_list[2]}
+    model_dict={'PK504':model_list[0],'MGMCL':model_list[1],'PK500':model_list[2]}
+
+    diag_cal()
+    #定时任务.......................................................................................................................................................................
+    scheduler = BlockingScheduler()
+    scheduler.add_job(diag_cal, 'interval', hours=6)
+
+    try:  
+        scheduler.start()
+    except Exception as e:
+        scheduler.shutdown()
+        logger.error(str(e))
+        logger.error(traceback.format_exc())

二进制
LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_MGMCL_05.h5


二进制
LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_PK500_05.h5


二进制
LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/model_PK504_05.h5


二进制
LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_MGMCL_05.pkl


二进制
LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_PK500_05.pkl


二进制
LIB/MIDDLE/ThermoRunaway/V1_0_2/train_out/scaler_PK504_05.pkl


+ 16 - 0
USER/LZX/01算法开发/.vscode/launch.json

@@ -0,0 +1,16 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Python: 当前文件",
+            "type": "python",
+            "request": "launch",
+            "program": "${file}",
+            "console": "integratedTerminal",
+            "justMyCode": true
+        }
+    ]
+}

+ 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())

部分文件因为文件数量过多而无法显示