Browse Source

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

lmstack 3 years ago
parent
commit
c85799d8b5

+ 478 - 0
LIB/MIDDLE/WinterCharging/V1_0_1/DataPreProcessMGMC.py

@@ -0,0 +1,478 @@
+from os import defpath
+import pandas as pd
+import numpy as np
+import pdb
+from numba import jit
+from LIB.BACKEND import Tools
+
+class DataPreProcess:
+    def __init__(self):
+        self.tools = Tools.Tools()
+        pass
+
+    # def data_split(self, dfin, drive_interval_threshold=120, charge_interval_threshold=300, 
+    #                            drive_stand_threshold=120, charge_stand_threshold=300,
+    #                            default_time_threshold = 300, drive_time_threshold=300, charge_time_threshold=300, 
+    #                            stand_time_threshold = 1800):
+    #     '''
+    #     数据分段函数,会调用_data_split_by_status和_data_split_by_time函数。
+    #     其中_data_split_by_status 将数据分为charge、drive、stand、和none段;
+    #     _data_split_by_time 将每个段内的数据,根据时间跳变继续分段。
+
+    #     '''
+    def time_filter(self, df_bms, df_gps):
+        df_bms.drop_duplicates(subset=['时间戳'], keep='first', inplace=True)
+        df_gps.drop_duplicates(subset=['时间戳'], keep='first', inplace=True)
+        df_bms = df_bms.reset_index(drop=True)
+        df_gps = df_gps.reset_index(drop=True)
+        return df_bms, df_gps
+
+    def data_split_by_status(self, dfin, drive_interval_threshold=120, charge_interval_threshold=300, 
+                                    drive_stand_threshold=120, charge_stand_threshold=300):
+        '''
+        # 数据预处理分段, 将原始数据段分为 charge、drive、stand、none段
+        # 状态判断
+        # 1、drive:(状态为2或3 且 存在电流>0 ) 或 (电流持续为0 且 持续时间<阈值 且 上一段数据为行车)
+        # 2、charge:(状态为2或3 且 不存在电流>0 ) 或 (电流持续为0 且 持续时间<阈值 且 上一段数据为充电)
+        # 3、stand:(电流持续为0 且 是数据段的第一段) 或 (电流持续为0 且 持续时间>阈值)
+        # 4、none: 其他
+
+        --------------输入参数-------------:
+        drive_interval_threshold: 行车段拼接阈值,如果两段行车的间隔时间小于该值,则两段行车合并。
+        charge_interval_threshold: 充电段拼接阈值,如果两段充电的间隔时间小于该值,则两段充电合并。
+        drive_stand_threshold: 静置段合并至行车段阈值,如果静置时间小于该值,则合并到上一段的行车中。
+        charge_stand_threshold: 静置段合并至充电段阈值,如果静置时间小于该值,则合并到上一段的充电中。
+
+        --------------输出-----------------:
+        在原始数据后面,增加data_split_by_crnt, data_split_by_status, data_status 三列
+        data_split_by_crnt: 按电流分段的序号
+        data_split_by_status:按电流和状态分段的序号
+        data_status: 状态标识
+        '''
+        # 首先根据电流是否为0 ,将数据分段
+        df = dfin.copy()
+        df['时间戳'] = pd.to_datetime(df['时间戳'])
+        
+        crnt_zero_or_not = df['总电流[A]']==0
+        last_crnt_flag = crnt_zero_or_not[0]
+        temp = 1
+        group_id = [temp]
+        for cur_crnt_flag in crnt_zero_or_not[1:]:
+            if last_crnt_flag ^ cur_crnt_flag:
+                temp = temp + 1
+            last_crnt_flag = cur_crnt_flag
+            group_id.append(temp)
+        df['data_split_by_crnt'] = group_id
+
+        # 然后判断每个段内的 充电状态及电流=0持续时长,决定当前状态
+        temp = 1
+        last_status = ""
+        status_id = []
+        status_list = []
+        data_number_list = sorted(list(set(df['data_split_by_crnt'])))
+
+        for data_number in data_number_list:
+            df_sel = df[df['data_split_by_crnt'] == data_number]
+            origin_index = list(df_sel.index)
+            df_sel = df_sel.reset_index(drop=True)
+            temp_2 = 0
+            # 如果当前数据段的电流非0,则可能分为charge、drive或none段
+            if df_sel.loc[0,'总电流[A]'] != 0:
+                # 电流 分段中可能存在状态变化的时刻, 内部根据状态进行分段.
+                # 该数据段内部,根据bms状态信号进行二次分段
+                status_drive_or_not = df_sel['充电状态']==3
+                last_status_flag = status_drive_or_not[0]
+                temp_2 = 0
+                group_id_2 = [temp_2]
+                for cur_status_flag in status_drive_or_not[1:]:
+                    if last_status_flag ^ cur_status_flag:
+                        temp_2 = temp_2 + 1
+                    last_status_flag = cur_status_flag
+                    group_id_2.append(temp_2)
+                
+                # 遍历二次状态分段
+                temp_2 = 0
+                last_status_2 = last_status
+                df_sel['index'] = group_id_2
+                data_number_list_2 = sorted(list(set(group_id_2)))
+                for data_number_2 in data_number_list_2:
+                    
+                    df_sel_2 = df_sel[df_sel['index'] == data_number_2]
+                    df_sel_2 = df_sel_2.reset_index(drop=True)
+                    
+                    # 根据bms状态 及 电流符号决定是charge还是drive
+                    # 如果状态为2或3, 且电流均>=0 则记为充电
+                    if df_sel_2.loc[0, '充电状态'] in [2, 3] and len(df_sel_2[df_sel_2['总电流[A]'] < 0]) == 0: 
+                        cur_status = 'charge'
+                    # 如果状态为2或3,且存在电流<0 则记为行车
+                    elif df_sel_2.loc[0, '充电状态'] in [2, 3] and len(df_sel_2[df_sel_2['总电流[A]'] < 0]) > 0: 
+                        cur_status = 'drive'
+                    # 否则 记为none
+                    else:
+                        cur_status = 'none'
+                    status_list.extend([cur_status] * len(df_sel_2))
+                    
+                    # 状态id号与前面电流为0的相同状态进行合并, 均判断应不应该与上一段合并    
+                    if origin_index[0] == 0: # 如果是所有数据的起始段数据,则直接赋值id号
+                        status_id.extend([temp + temp_2]*len(df_sel_2))
+                    
+                    else: # 判断是否与上一段数据合并
+                        deltaT = (df.loc[origin_index[0], '时间戳'] - df.loc[origin_index[0]-1, '时间戳']).total_seconds()
+                        # 如果 状态一致, 且 间隔时间小于阈值,则合并
+                        if last_status_2 == 'drive' and cur_status == last_status_2 and deltaT < drive_interval_threshold: 
+                            temp_2 = temp_2 - 1  
+                            status_id.extend([temp + temp_2]*len(df_sel_2)) 
+                        # 如果状态一致, 且 间隔时间小于阈值,则合并
+                        elif last_status_2 == 'charge' and cur_status == last_status_2 and deltaT < charge_interval_threshold: 
+                            temp_2 = temp_2 - 1  
+                            status_id.extend([temp + temp_2]*len(df_sel_2)) 
+                        else:
+                            status_id.extend([temp + temp_2]*len(df_sel_2))
+                    temp_2 = temp_2 + 1
+                    last_status_2 = status_list[-1]
+                temp_2 = temp_2 - 1
+            else:
+                # 如果当前数据段的电流为0,则可能分为stand,charge、drive或none段
+                if origin_index[0] == 0: # 如果是数据的起始,则无论长短,都认为是stand
+                    status_id.extend([temp]*len(df_sel))
+                    status_list.extend(['stand'] * len(df_sel))
+                else: # 不是数据的起始
+                    cur_deltaT = (df.loc[origin_index[-1], '时间戳'] - df.loc[origin_index[0], '时间戳']).total_seconds()
+                    if last_status == 'charge': # 如果上一个状态为充电
+                        if cur_deltaT < charge_stand_threshold: # 如果本次电流为0的持续时间小于 阈值,则合并
+                            status_list.extend(['charge'] * len(df_sel))
+                            temp = temp - 1  
+                            status_id.extend([temp]*len(df_sel))
+                        else: # 否则超过了阈值,记为stand
+                            status_id.extend([temp]*len(df_sel))
+                            status_list.extend(['stand'] * len(df_sel))
+                    elif last_status == 'drive': # 如果上一个状态为行车
+                        if cur_deltaT < drive_stand_threshold: # 如果本次电流为0的持续时间小于 阈值,则合并
+                            status_list.extend(['drive'] * len(df_sel))
+                            temp = temp - 1  
+                            status_id.extend([temp]*len(df_sel))
+                        else: # 否则超过了阈值,记为stand
+                            status_id.extend([temp]*len(df_sel))
+                            status_list.extend(['stand'] * len(df_sel))
+                    elif last_status == 'none': # 如果上一个状态未知
+                        status_id.extend([temp] * len(df_sel))
+                        status_list.extend(['stand'] * len(df_sel))
+            temp = temp + temp_2 + 1
+            last_status = status_list[-1] # 上一组状态
+        df['data_split_by_status'] = status_id
+        df['data_status'] = status_list
+        return df
+    def data_split_by_time(self, dfin, default_time_threshold = 300, drive_time_threshold=300, charge_time_threshold=300, 
+                                        stand_time_threshold = 1800):
+        '''
+        # 该函数用来解决数据丢失问题导致的分段序号异常,
+        # 将经过data_split_by_status分段后的数据,每个段内两行数据的时间跳变如果超过阈值,则继续分为两段
+
+        --------------输入参数-------------:
+        dfin:  调用data_split_by_status之后的函数
+        default_time_threshold: 默认时间阈值,如果状态内部时间跳变大于该值,则划分为两段
+        drive_time_threshold: 行车时间阈值,如果行车状态内部时间跳变大于该值,则划分为两段
+        charge_time_threshold: 充电时间阈值,如果充电状态内部时间跳变大于该值,则划分为两段
+        stand_time_threshold:静置时间阈值,如果静置状态内部时间跳变大于该值,则划分为两段
+
+        --------------输出-----------------:
+        在输入数据后面,增加data_split_by_status_time 一列
+        data_split_by_status_time: 按照状态和时间分段后的序号
+        '''  
+        data_id = []
+        temp = 1
+        data_number_list = sorted(list(set(dfin['data_split_by_status'])))
+        for data_number in data_number_list:
+            # if data_number == 1203:
+            #     pdb.set_trace()
+            status = list(dfin[dfin['data_split_by_status']==data_number]['data_status'])[0]
+            cur_indexes = dfin[dfin['data_split_by_status']==data_number].index
+            
+            time_array = np.array(dfin[dfin['data_split_by_status']==data_number]['时间戳'])
+            time_diff = np.diff(time_array)
+            time_diff = time_diff.astype(np.int64)
+            time_interval = default_time_threshold
+            if status == 'drive':
+                time_interval = drive_time_threshold
+            elif status == 'charge':
+                time_interval = charge_time_threshold
+            elif status == 'stand':
+                time_interval = stand_time_threshold
+            time_diff_index = (np.argwhere(((time_diff/1e9) > time_interval)==True))[:,0]
+            time_diff_origin_index = cur_indexes[time_diff_index]+1
+            if len(time_diff_index) == 0:
+                data_id.extend([temp] * len(cur_indexes))
+                temp += 1
+            else:
+                last_index = cur_indexes[0]
+                for index, cur_index in enumerate(time_diff_origin_index):
+                    if index == len(time_diff_origin_index)-1: # 如果是最后一个index,则
+                        data_id.extend([temp]* (cur_index-last_index))
+                        last_index = cur_index
+                        temp += 1
+                        data_id.extend([temp]* (cur_indexes[-1]-last_index+1))
+                    else:
+                        data_id.extend([temp]* (cur_index-last_index))
+                    last_index = cur_index
+                    temp += 1
+        dfin['data_split_by_status_time'] = data_id
+        return dfin
+    def combine_drive_stand(self, dfin):
+        '''
+        合并放电和静置段:将两次充电之间的所有数据段合并为一段, 状态分为 charge 和not charge
+        ---------------输入----------
+        dfin: 调用data_split_by_status()后输出的bms数据
+
+        ---------------输出----------
+        在输入数据后面,增加data_split_by_status_after_combine, data_status_after_combine 两列
+        data_split_by_status_after_combine: 将两次充电间的数据合并后的段序号
+        data_status_after_combine: 每段数据的状态标识
+        '''
+        df = dfin.copy()
+        data_split_by_status_1 = []
+        data_status_1 = []
+        number = 1
+        first_flag = True
+        data_number_list = sorted(list(set(df['data_split_by_status_time'])))
+        for data_number in data_number_list:
+            status = list(df[df['data_split_by_status_time']==data_number]['data_status'])
+            cur_status = status[0]
+            if first_flag:
+                first_flag = False
+            elif (last_status not in ['charge'] and cur_status in ['charge']) or (last_status in ['charge'] and cur_status not in ['charge']):
+                number += 1
+
+            data_split_by_status_1.extend([number]*len(status))
+            if cur_status in ['charge']:
+                data_status_1.extend(['charge']*len(status))
+            else:
+                data_status_1.extend(['not charge']*len(status))
+
+            last_status = cur_status
+        df['data_split_by_status_after_combine'] = data_split_by_status_1
+        df['data_status_after_combine'] = data_status_1
+
+        return df
+
+    def cal_stand_time(self, dfin):
+        '''
+        # 计算静置时间
+        # 将每次行车或充电的前后静置时间,赋值给stand_time 列, 单位为分钟
+
+        ----------------输入参数---------
+        dfin: 调用data_split_by_status()后输出的bms数据
+
+        ----------------输出参数----------
+        在输入数据后面,增加stand_time列
+        stand_time : 在行车段或充电段的起止两个位置处,表明开始前和结束后的静置时长,单位为分钟
+
+        '''
+        df = dfin.copy()
+        stand_time = []
+        first_flag = True
+        data_number_list = sorted(list(set(df['data_split_by_status_time'])))
+        for index, data_number in enumerate(data_number_list):
+            status = list(df[df['data_split_by_status_time']==data_number]['data_status'])
+            time =  list(df[df['data_split_by_status_time']==data_number]['时间戳'])
+            cur_status = status[0]
+            cur_delta_time = (time[-1]-time[0]).total_seconds() / 60.0 # 分钟
+            if len(status) >= 2:
+                if first_flag:
+                    first_flag = False
+                    if index < len(data_number_list)-1:
+                        if cur_status in ['charge', 'drive']:
+                            next_status = list(df[df['data_split_by_status_time']==data_number_list[index+1]]['data_status'])[0]
+                            stand_time.extend([None]*(len(status)-1))
+                            if next_status == 'stand':
+                                next_time =  list(df[df['data_split_by_status_time']==data_number_list[index+1]]['时间戳'])
+                                stand_time.extend([(next_time[-1]-next_time[0]).total_seconds() / 60.0])
+                            else:
+                                stand_time.extend([0])
+                        else:
+                            stand_time.extend([None]*len(status))
+                    else:
+                        stand_time.extend([None]*len(status))      
+                else:
+                    if cur_status in ['charge', 'drive']:
+                        if last_status == 'stand':
+                            stand_time.extend([last_delta_time])
+                        else:
+                            stand_time.extend([0])
+                        stand_time.extend([None]*(len(status)-2))
+                        if index < len(data_number_list)-1:
+                            next_status = list(df[df['data_split_by_status_time']==data_number_list[index+1]]['data_status'])[0]
+                            if next_status == 'stand':
+                                next_time =  list(df[df['data_split_by_status_time']==data_number_list[index+1]]['时间戳'])
+                                stand_time.extend([(next_time[-1]-next_time[0]).total_seconds() / 60.0])
+                            else:
+                                stand_time.extend([0])
+                        else:
+                            stand_time.extend([None])
+                    else:
+                        stand_time.extend([None]*len(status))
+                        
+            else:
+                stand_time.extend([None])
+            last_status = cur_status
+            last_delta_time = cur_delta_time
+        df['stand_time'] = stand_time
+        return df
+
+    # 输入GPS数据,返回本段数据的累积里程,及平均时速(如果两点之间)
+    @jit
+    def _cal_odo_speed(self, lat_list, long_list, time_list):
+        '''
+        输入:经度列表, 纬度列表, 时间列表;
+        输出:每两个经纬度坐标之间的距离,以及速度 的数组
+        '''
+        dis_array = []
+        speed_array = []
+ 
+        for i in range(len(lat_list)-1):
+            dis = self.tools.cal_distance(lat_list[i],long_list[i], lat_list[i+1],long_list[i+1])
+            dis_array.append(dis)
+            deltaT = abs(time_list[i] - time_list[i+1]).total_seconds()
+            speed_array.append(dis * 3600.0/deltaT)
+        return np.array(dis_array), np.array(speed_array)
+
+    def gps_data_judge(self, df_bms, df_gps, time_diff_thre=300, odo_sum_thre=200, drive_spd_thre=80, parking_spd_thre=2):
+        '''
+        GPS数据可靠性判断函数(基于combine前的分段)
+
+        GPS数据出现以下情况时,判定为不可靠:
+        1)如果该段对应的地理位置数据 少于2 个,则认为不可靠
+        2)如果截取的GPS数据的起止时间,与BMS数据段的起止时间相差超过阈值,则认为不可靠
+        3)如果行车段 累积里程超过阈值,车速超过阈值
+        4) 如果非行车段 车速超过阈值
+
+        --------------输入参数--------------:
+        time_diff_thre: 时间差阈值
+        odo_sum_thre: 累积里程阈值
+        drive_spd_thre: 行车车速阈值
+        parking_spd_thre: 非行车状态车速阈值
+
+        --------------输出参数--------------:
+        df_bms 增加一列gps_rely, 表明对应的GPS数据是否可靠。
+                1:可靠
+                <0: 表示不可靠的原因
+        df_gps 增加两列odo, speed, 分别表示前后两点间的距离和速度
+        '''
+        df_gps['时间戳'] = pd.to_datetime(df_gps['时间戳'])
+        res_record = {'drive':0, 'charge':0, 'stand':0, 'none':0, 'total':0}
+        rely_list = []
+        df_gps['odo'] = [None] * len(df_gps)
+        df_gps['speed'] = [None] * len(df_gps)
+        data_number_list = sorted(list(set(df_bms['data_split_by_status_time'])))
+        for data_number in data_number_list[:]:
+            df_sel = df_bms[df_bms['data_split_by_status_time'] == data_number]
+            df_sel = df_sel.reset_index(drop=True)
+            df_sel_gps = df_gps[(df_gps['时间戳']>=df_sel.loc[0,'时间戳']) & (df_gps['时间戳']<=df_sel.loc[len(df_sel)-1,'时间戳'])]
+            origin_index = list(df_sel_gps.index)
+            df_sel_gps = df_sel_gps.reset_index(drop=True)
+            # 如果当前段数据对应的地理位置数据少于2个
+            if len(df_sel_gps) <= 1:
+                rely_list.extend([-1]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status'])] = res_record[str(df_sel.loc[0, 'data_status'])] + 1
+                continue
+            # 如果GPS 起止时间段和BMS数据相差超过阈值
+            if abs(df_sel_gps.loc[0, '时间戳'] - df_sel.loc[0,'时间戳']).total_seconds() > time_diff_thre or \
+               abs(df_sel_gps.loc[len(df_sel_gps)-1, '时间戳'] - df_sel.loc[len(df_sel)-1,'时间戳']).total_seconds() > time_diff_thre:
+                rely_list.extend([-2]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status'])] = res_record[str(df_sel.loc[0, 'data_status'])] + 1
+                continue
+
+            # 计算该段数据每两点之间的里程以及速度
+            dis_array, speed_array = self._cal_odo_speed(df_sel_gps['纬度'], df_sel_gps['经度'], df_sel_gps['时间戳'])
+            # 如果 累积里程异常 或 平均车速异常 或两点间车速异常
+            avg_speed = np.sum(dis_array) *3600.0 / abs(df_sel_gps.loc[0, '时间戳'] - df_sel_gps.loc[len(df_sel_gps)-1, '时间戳']).total_seconds()
+            if np.sum(dis_array) > odo_sum_thre or avg_speed > drive_spd_thre or (speed_array > drive_spd_thre).any():
+                rely_list.extend([-3]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status'])] = res_record[str(df_sel.loc[0, 'data_status'])] + 1
+                continue
+            
+            # 如果停车,且 平均时速超过阈值,则不可靠
+            if (str(df_sel.loc[0, 'data_status']) == 'charge' or str(df_sel.loc[0, 'data_status']) == 'stand') and avg_speed > parking_spd_thre :
+                rely_list.extend([-4]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status'])] = res_record[str(df_sel.loc[0, 'data_status'])] + 1
+                continue
+            # 剩下的记录为可靠
+            rely_list.extend([1]*len(df_sel))
+            df_gps.loc[origin_index[1:], 'odo'] = dis_array
+            df_gps.loc[origin_index[1:], 'speed'] = speed_array
+        df_bms['gps_rely'] = rely_list
+        res_record['total'] = (res_record['drive'] + res_record['charge'] + res_record['stand'] + res_record['none'] )/df_bms['data_split_by_status_time'].max()
+        if len(set(df_bms[df_bms['data_status']=='drive']['data_split_by_status_time'])) > 0:
+            res_record['drive'] = (res_record['drive'])/len(set(df_bms[df_bms['data_status']=='drive']['data_split_by_status_time']))
+        if len(set(df_bms[df_bms['data_status']=='charge']['data_split_by_status_time'])) > 0:
+            res_record['charge'] = (res_record['charge'])/len(set(df_bms[df_bms['data_status']=='charge']['data_split_by_status_time']))
+        if len(set(df_bms[df_bms['data_status']=='stand']['data_split_by_status_time'])) > 0:
+            res_record['stand'] = (res_record['stand'])/len(set(df_bms[df_bms['data_status']=='stand']['data_split_by_status_time']))
+        if len(set(df_bms[df_bms['data_status']=='none']['data_split_by_status_time'])) > 0:
+            res_record['none'] = (res_record['none'])/len(set(df_bms[df_bms['data_status']=='none']['data_split_by_status_time']))
+        return df_bms, df_gps, res_record
+
+
+    def data_gps_judge_after_combine(self, df_bms, df_gps, time_diff_thre=600, odo_sum_thre=200, drive_spd_thre=80, parking_spd_thre=2):
+        '''
+        GPS数据可靠性判断函数2 (基于combine后的分段) 判别方式同data_gps_judge
+        '''
+        df_gps['时间戳'] = pd.to_datetime(df_gps['时间戳'])
+        res_record = {'not charge':0, 'charge':0, 'total':0} # 不可靠的比例
+
+        rely_list = []
+        df_gps['odo_after_combine'] = [None] * len(df_gps)
+        df_gps['speed_after_combine'] = [None] * len(df_gps)
+ 
+        data_number_list = sorted(list(set(df_bms['data_split_by_status_after_combine'])))
+        for data_number in data_number_list[:]:
+            df_sel = df_bms[df_bms['data_split_by_status_after_combine'] == data_number]
+            df_sel = df_sel.reset_index(drop=True)
+
+            # 尝试采用drive段的开始和结束时间选择GPS数据,因为stand时GPS数据可能存在丢失,影响里程的计算
+            df_sel_drive = df_sel[df_sel['data_status']=='drive'] # 
+            df_sel_drive = df_sel_drive.reset_index(drop=True)
+            if df_sel_drive.empty:
+                df_sel_1 = df_sel
+            else:
+                df_sel_1 = df_sel_drive
+            df_sel_gps = df_gps[(df_gps['时间戳']>=df_sel_1.loc[0,'时间戳']) & (df_gps['时间戳']<=df_sel_1.loc[len(df_sel_1)-1,'时间戳'])]
+            origin_index = list(df_sel_gps.index)
+            df_sel_gps = df_sel_gps.reset_index(drop=True)
+            # 如果当前段数据对应的地理位置数据少于2个
+            if len(df_sel_gps) <= 1:
+                rely_list.extend([-1]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status_after_combine'])] = res_record[str(df_sel.loc[0, 'data_status_after_combine'])] + 1
+                continue
+            # 如果GPS 起止时间段和BMS数据相差超过阈值
+            if abs(df_sel_gps.loc[0, '时间戳'] - df_sel_1.loc[0,'时间戳']).total_seconds() > time_diff_thre or \
+                abs(df_sel_gps.loc[len(df_sel_gps)-1, '时间戳'] - df_sel_1.loc[len(df_sel_1)-1,'时间戳']).total_seconds() > time_diff_thre:
+                rely_list.extend([-2]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status_after_combine'])] = res_record[str(df_sel.loc[0, 'data_status_after_combine'])] + 1
+                continue
+
+            # 计算该段数据每两点之间的里程以及速度
+            dis_array, speed_array = self._cal_odo_speed(df_sel_gps['纬度'], df_sel_gps['经度'], df_sel_gps['时间戳'])
+            # 如果 累积里程异常 或 平均车速异常 或两点间车速异常
+            avg_speed = np.sum(dis_array) *3600.0 / abs(df_sel_gps.loc[0, '时间戳'] - df_sel_gps.loc[len(df_sel_gps)-1, '时间戳']).total_seconds()
+            if np.sum(dis_array) > odo_sum_thre or avg_speed > drive_spd_thre or (speed_array > drive_spd_thre).any():
+                rely_list.extend([-3]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status_after_combine'])] = res_record[str(df_sel.loc[0, 'data_status_after_combine'])] + 1
+                continue
+            
+            # 如果充电,且 平均时速超过阈值,则不可靠
+            if str(df_sel.loc[0, 'data_status_after_combine']) == 'charge' and avg_speed > parking_spd_thre:
+                rely_list.extend([-4]*len(df_sel))
+                res_record[str(df_sel.loc[0, 'data_status_after_combine'])] = res_record[str(df_sel.loc[0, 'data_status_after_combine'])] + 1
+                continue
+            # 剩下的记录为可靠
+            rely_list.extend([1]*len(df_sel))
+            df_gps.loc[origin_index[1:], 'odo_after_combine'] = dis_array
+            df_gps.loc[origin_index[1:], 'speed_after_combine'] = speed_array
+        df_bms['gps_rely_after_combine'] = rely_list
+        res_record['total'] = (res_record['not charge'] + res_record['charge'])/df_bms['data_split_by_status_after_combine'].max()
+        if len(set(df_bms[df_bms['data_status_after_combine']=='not charge']['data_split_by_status_after_combine'])) > 0:
+            res_record['not charge'] = (res_record['not charge'])/len(set(df_bms[df_bms['data_status_after_combine']=='not charge']['data_split_by_status_after_combine']))
+        if len(set(df_bms[df_bms['data_status_after_combine']=='charge']['data_split_by_status_after_combine'])) > 0 :
+            res_record['charge'] = (res_record['charge'])/len(set(df_bms[df_bms['data_status_after_combine']=='charge']['data_split_by_status_after_combine']))
+        return df_bms, df_gps, res_record
+        

+ 114 - 0
LIB/MIDDLE/WinterCharging/V1_0_1/Data_Analyse.py

@@ -0,0 +1,114 @@
+from LIB.BACKEND import DBManager
+from LIB.MIDDLE.CellStateEstimation.Common import log
+import datetime
+import pandas as pd
+import numpy as np
+import os   
+from DataPreProcessMGMC import DataPreProcess
+from scipy import stats
+
+#log信息配置
+mylog=log.Mylog('log.txt','error')
+mylog.logcfg()
+
+dbManager = DBManager.DBManager()
+dataSOH = pd.read_excel('sn-20210903.xlsx',sheet_name='MGMC')
+fileNames = dataSOH['sn']
+fileNames = list(fileNames)
+
+data_GMGC=[]
+for k in range(len(fileNames)):
+
+    try:    
+        sn = fileNames[k]
+        df_data = dbManager.get_data(sn=sn, start_time='2021-10-15 00:00:00', end_time='2021-11-06 00:00:00', data_groups=['bms','gps'])
+        data_bms = df_data['bms']
+        data_gps = df_data['gps']
+        df_merge = pd.merge(data_bms, data_gps,how='outer',sort=True)
+        df_merge['sn'] = sn
+        df_sheetCat = DataPreProcess.data_split_by_status(DataPreProcess,df_merge, drive_interval_threshold=120, charge_interval_threshold=300, drive_stand_threshold=120, charge_stand_threshold=300)
+        unique_status_idx = np.unique(df_sheetCat.data_split_by_status.values)
+        data_result = pd.DataFrame()
+        list_result = []
+        for n in unique_status_idx:
+            list_result.append(df_sheetCat[df_sheetCat.data_split_by_status==n]) 
+        data_GMGC.append(list_result)
+
+    except Exception as e:
+        print(repr(e))
+        mylog.logopt(sn,e)
+        pass  
+
+df_result=pd.DataFrame()
+for k in range(len(data_GMGC)):
+     
+    maxI=[]
+    modI=[]
+    lenI=[]
+    temp1_start=[]
+    temp2_start=[]
+    temp1_fin=[]
+    temp2_fin=[]
+    time_start=[]
+    time_fin=[]
+    time_drivefin=[]
+    temp1_drivefin=[]
+    temp2_drivefin=[]
+    sn=[]
+    
+    for i in range(1,len(data_GMGC[k])):
+       if data_GMGC[k][i]['data_status'].values[0]=='charge':
+           
+            maxI.append(max(data_GMGC[k][i]['总电流[A]'].values[:10]))
+            modI.append(stats.mode(data_GMGC[k][i]['总电流[A]'].values[:10])[0][0])
+            lenI.append(len(data_GMGC[k][i]['总电流[A]'].values))
+            temp1_start.append(data_GMGC[k][i]['单体温度1'].values[0])
+            temp2_start.append(data_GMGC[k][i]['单体温度2'].values[0])
+            temp1_fin.append(data_GMGC[k][i]['单体温度1'].values[-1])
+            temp2_fin.append(data_GMGC[k][i]['单体温度2'].values[-1])
+            time_start.append(data_GMGC[k][i]['时间戳'].values[0])
+            time_fin.append(data_GMGC[k][i]['时间戳'].values[-1])
+            time_drivefin.append(data_GMGC[k][i-1]['时间戳'].values[0])
+            temp1_drivefin.append(data_GMGC[k][i-1]['单体温度1'].values[0])
+            temp2_drivefin.append(data_GMGC[k][i-1]['单体温度2'].values[0])           
+            sn.append(data_GMGC[k][i]['sn'].values[0])
+    dic={"初始充电电流max":maxI,"初始充电电流mod":modI,"电流长度":lenI,"初始充电温度1":temp1_start,"初始充电温度2":temp2_start,
+        "结束充电温度1":temp1_fin,"结束充电温度2":temp2_fin,"初始充电时间":time_start,
+        "结束充电时间":time_fin,"行驶结束时间":time_drivefin,"行驶结束温度1":temp1_drivefin,
+        "行驶结束温度2":temp2_drivefin,"sn":sn}
+    df_analyse=pd.DataFrame(dic)
+    df_result=df_result.append(df_analyse)
+
+data_analyse=df_result[df_result['电流长度'].values>5]
+
+mean_temp1=[]
+mean_temp2=[]
+mean_temp3=[]
+time_diff_stand=[]
+time_diff_charge=[]
+
+for i in range(len(data_analyse)):
+    meantemp1=(data_analyse['初始充电温度1'].values[i]+data_analyse['初始充电温度2'].values[i])/2
+    mean_temp1.append(meantemp1)
+    meantemp2=(data_analyse['结束充电温度1'].values[i]+data_analyse['结束充电温度2'].values[i])/2
+    mean_temp2.append(meantemp2)
+    meantemp3=(data_analyse['行驶结束温度1'].values[i]+data_analyse['行驶结束温度2'].values[i])/2
+    mean_temp3.append(meantemp3)
+    td_charge=float(np.diff([data_analyse['初始充电时间'].values[i],data_analyse['结束充电时间'].values[i]])/np.timedelta64(1, 'm'))
+    time_diff_charge.append(td_charge)
+    td_stand=float(np.diff([data_analyse['行驶结束时间'].values[i],data_analyse['初始充电时间'].values[i]])/np.timedelta64(1, 'm'))
+    time_diff_stand.append(td_stand) 
+   
+data_analyse['初始充电温度']=mean_temp1
+data_analyse['结束充电温度']=mean_temp2
+data_analyse['行驶结束温度']=mean_temp3
+data_analyse['闲置时长']=time_diff_stand
+data_analyse['充电时长']=time_diff_charge
+
+diff_temp=[]
+for i in range(len(data_analyse)):
+    difftemp=data_analyse['结束充电温度'].values[i]-data_analyse['初始充电温度'].values[i]
+    diff_temp.append(difftemp)
+data_analyse['充电温差']=diff_temp
+data_select=data_analyse[data_analyse['充电时长'].values>5]
+

+ 111 - 0
LIB/MIDDLE/WinterCharging/V1_0_1/data_analyse11.csv

@@ -0,0 +1,111 @@
+,初始充电电流max,初始充电电流mod,电流长度,初始充电温度1,初始充电温度2,结束充电温度1,结束充电温度2,初始充电时间,结束充电时间,行驶结束时间,行驶结束温度1,行驶结束温度2,sn,初始充电温度,结束充电温度,行驶结束温度,闲置时长,充电时长,充电温差
+0,7.7,7.7,1025.0,6.0,7.0,11.0,11.0,2021-10-17 12:23:57,2021-10-17 15:14:28,2021-10-16 00:00:10,15.0,14.0,MGMCLN750N215H001,6.5,11.0,14.5,2183.7833333333333,170.51666666666668,4.5
+2,7.7,7.7,1031.0,7.0,7.0,10.0,9.0,2021-10-18 06:21:53,2021-10-18 09:13:32,2021-10-18 06:21:49,7.0,7.0,MGMCLN750N215H001,7.0,9.5,7.0,0.06666666666666667,171.65,2.5
+0,7.9,7.8,2387.0,13.0,12.0,18.0,16.0,2021-10-20 01:42:20,2021-10-20 08:19:28,2021-10-16 00:11:03,17.0,16.0,MGMCLN750N215H002,12.5,17.0,16.5,5851.283333333334,397.1333333333333,4.5
+4,7.9,7.8,927.0,13.0,12.0,14.0,13.0,2021-10-20 23:27:51,2021-10-21 02:01:50,2021-10-20 23:25:22,13.0,12.0,MGMCLN750N215H002,12.5,13.5,12.5,2.4833333333333334,153.98333333333332,1.0
+11,7.9,7.8,1485.0,19.0,18.0,18.0,17.0,2021-10-21 23:09:40,2021-10-22 03:16:54,2021-10-21 23:06:40,19.0,18.0,MGMCLN750N215H002,18.5,17.5,18.5,3.0,247.23333333333332,-1.0
+14,7.9,7.8,985.0,18.0,16.0,18.0,16.0,2021-10-22 20:20:29,2021-10-22 23:04:25,2021-10-22 15:56:00,21.0,19.0,MGMCLN750N215H002,17.0,17.0,20.0,264.48333333333335,163.93333333333334,0.0
+20,7.9,7.9,1871.0,17.0,15.0,17.0,16.0,2021-10-23 22:30:52,2021-10-24 03:42:24,2021-10-23 22:17:15,17.0,15.0,MGMCLN750N215H002,16.0,16.5,16.0,13.616666666666667,311.53333333333336,0.5
+27,7.9,7.8,1811.0,16.0,15.0,18.0,16.0,2021-10-24 23:53:12,2021-10-25 04:54:38,2021-10-24 23:49:00,16.0,15.0,MGMCLN750N215H002,15.5,17.0,15.5,4.2,301.43333333333334,1.5
+32,7.9,7.8,1487.0,17.0,16.0,19.0,17.0,2021-10-25 23:26:24,2021-10-26 03:33:50,2021-10-25 19:15:01,21.0,19.0,MGMCLN750N215H002,16.5,18.0,20.0,251.38333333333333,247.43333333333334,1.5
+35,7.9,7.8,1678.0,21.0,20.0,20.0,18.0,2021-10-26 23:03:45,2021-10-27 03:43:03,2021-10-26 22:57:59,22.0,20.0,MGMCLN750N215H002,20.5,19.0,21.0,5.766666666666667,279.3,-1.5
+36,7.9,7.8,664.0,20.0,19.0,21.0,19.0,2021-10-27 22:38:04,2021-10-28 00:28:29,2021-10-27 22:35:04,21.0,19.0,MGMCLN750N215H002,19.5,20.0,20.0,3.0,110.41666666666667,0.5
+38,7.9,7.8,938.0,19.0,18.0,19.0,17.0,2021-10-28 20:17:13,2021-10-28 22:53:07,2021-10-28 20:04:12,19.0,18.0,MGMCLN750N215H002,18.5,18.0,18.5,13.016666666666667,155.9,-0.5
+44,7.9,7.8,2193.0,22.0,20.0,20.0,19.0,2021-10-30 22:43:23,2021-10-31 04:53:57,2021-10-30 22:37:59,22.0,20.0,MGMCLN750N215H002,21.0,19.5,21.0,5.4,370.56666666666666,-1.5
+52,7.9,7.8,2031.0,19.0,17.0,19.0,17.0,2021-10-31 23:08:27,2021-11-01 04:46:45,2021-10-31 23:00:22,19.0,17.0,MGMCLN750N215H002,18.0,18.0,18.0,8.083333333333334,338.3,0.0
+55,7.9,7.8,986.0,13.0,12.0,15.0,14.0,2021-11-02 01:03:35,2021-11-02 03:47:29,2021-11-01 19:36:19,15.0,14.0,MGMCLN750N215H002,12.5,14.5,14.5,327.26666666666665,163.9,2.0
+58,7.9,7.8,1793.0,15.0,14.0,17.0,15.0,2021-11-02 23:07:37,2021-11-03 04:06:00,2021-11-02 22:26:51,16.0,14.0,MGMCLN750N215H002,14.5,16.0,15.0,40.766666666666666,298.3833333333333,1.5
+63,7.9,7.8,1731.0,15.0,13.0,17.0,15.0,2021-11-03 23:13:54,2021-11-04 04:01:44,2021-11-03 22:45:53,15.0,13.0,MGMCLN750N215H002,14.0,16.0,14.0,28.016666666666666,287.8333333333333,2.0
+64,7.9,7.8,1102.0,15.0,14.0,17.0,16.0,2021-11-04 20:56:38,2021-11-04 23:59:54,2021-11-04 19:37:36,16.0,15.0,MGMCLN750N215H002,14.5,16.5,15.5,79.03333333333333,183.26666666666668,2.0
+2,7.7,7.7,1244.0,11.0,11.0,12.0,11.0,2021-10-16 23:10:08,2021-10-17 02:44:19,2021-10-16 20:15:23,13.0,12.0,MGMCLN750N215H003,11.0,11.5,12.5,174.75,214.18333333333334,0.5
+6,7.7,7.7,929.0,16.0,15.0,18.0,18.0,2021-10-17 13:57:15,2021-10-17 16:31:49,2021-10-17 13:48:34,16.0,15.0,MGMCLN750N215H003,15.5,18.0,15.5,8.683333333333334,154.56666666666666,2.5
+8,7.8,7.7,1205.0,18.0,16.0,16.0,15.0,2021-10-17 21:18:40,2021-10-18 00:39:17,2021-10-17 21:01:49,18.0,17.0,MGMCLN750N215H003,17.0,15.5,17.5,16.85,200.61666666666667,-1.5
+14,7.6,7.6,258.0,18.0,17.0,19.0,18.0,2021-10-18 14:36:04,2021-10-18 15:18:48,2021-10-18 14:31:27,18.0,17.0,MGMCLN750N215H003,17.5,18.5,17.5,4.616666666666666,42.733333333333334,1.0
+15,7.7,7.6,1879.0,17.0,16.0,16.0,15.0,2021-10-18 20:54:24,2021-10-19 02:07:40,2021-10-18 20:37:44,17.0,16.0,MGMCLN750N215H003,16.5,15.5,16.5,16.666666666666668,313.26666666666665,-1.0
+17,7.6,7.6,534.0,15.0,14.0,16.0,15.0,2021-10-19 13:01:00,2021-10-19 14:29:51,2021-10-19 12:45:43,14.0,13.0,MGMCLN750N215H003,14.5,15.5,13.5,15.283333333333333,88.85,1.0
+18,7.7,7.6,1287.0,16.0,15.0,16.0,15.0,2021-10-19 19:15:44,2021-10-19 22:49:49,2021-10-19 19:12:27,16.0,15.0,MGMCLN750N215H003,15.5,15.5,15.5,3.283333333333333,214.08333333333334,0.0
+20,7.6,7.6,655.0,20.0,19.0,20.0,19.0,2021-10-21 17:04:58,2021-10-21 18:53:48,2021-10-21 16:54:43,20.0,19.0,MGMCLN750N215H003,19.5,19.5,19.5,10.25,108.83333333333333,0.0
+21,7.7,7.7,559.0,18.0,18.0,18.0,17.0,2021-10-21 21:44:48,2021-10-21 23:17:38,2021-10-21 18:53:54,20.0,19.0,MGMCLN750N215H003,18.0,17.5,19.5,170.9,92.83333333333333,-0.5
+22,7.7,7.6,557.0,22.0,20.0,22.0,21.0,2021-10-22 15:28:55,2021-10-22 17:01:21,2021-10-22 15:16:47,22.0,20.0,MGMCLN750N215H003,21.0,21.5,21.0,12.133333333333333,92.43333333333334,0.5
+24,7.7,7.7,1297.0,21.0,19.0,19.0,18.0,2021-10-22 19:33:35,2021-10-22 23:09:27,2021-10-22 19:25:42,21.0,19.0,MGMCLN750N215H003,20.0,18.5,20.0,7.883333333333334,215.86666666666667,-1.5
+26,7.7,7.6,543.0,18.0,17.0,20.0,19.0,2021-10-23 15:20:28,2021-10-23 16:50:38,2021-10-23 15:19:40,18.0,17.0,MGMCLN750N215H003,17.5,19.5,17.5,0.8,90.16666666666667,2.0
+28,7.8,7.7,1450.0,18.0,16.0,17.0,15.0,2021-10-23 22:16:56,2021-10-24 02:17:41,2021-10-23 21:50:57,18.0,17.0,MGMCLN750N215H003,17.0,16.0,17.5,25.983333333333334,240.75,-1.0
+29,7.7,7.7,1312.0,19.0,18.0,20.0,19.0,2021-10-25 18:40:47,2021-10-25 22:18:56,2021-10-25 18:06:53,19.0,18.0,MGMCLN750N215H003,18.5,19.5,18.5,33.9,218.15,1.0
+32,7.7,7.7,1729.0,19.0,18.0,20.0,19.0,2021-10-26 21:57:48,2021-10-27 02:45:37,2021-10-26 21:35:23,20.0,19.0,MGMCLN750N215H003,18.5,19.5,19.5,22.416666666666668,287.81666666666666,1.0
+37,2.3,2.3,1249.0,19.0,17.0,13.0,13.0,2021-10-27 21:17:01,2021-10-28 06:56:08,2021-10-27 21:12:24,19.0,18.0,MGMCLN750N215H003,18.0,13.0,18.5,4.616666666666666,579.1166666666667,-5.0
+39,7.7,7.6,1677.0,18.0,17.0,19.0,18.0,2021-10-29 21:36:30,2021-10-30 02:15:38,2021-10-29 21:28:18,18.0,17.0,MGMCLN750N215H003,17.5,18.5,17.5,8.2,279.1333333333333,1.0
+44,7.6,7.6,1657.0,12.0,11.0,15.0,14.0,2021-11-02 00:38:18,2021-11-02 05:13:56,2021-11-02 00:38:16,12.0,11.0,MGMCLN750N215H003,11.5,14.5,11.5,0.03333333333333333,275.6333333333333,3.0
+46,7.7,7.6,1199.0,15.0,14.0,16.0,15.0,2021-11-02 18:03:15,2021-11-02 21:24:25,2021-11-02 17:36:56,15.0,14.0,MGMCLN750N215H003,14.5,15.5,14.5,26.316666666666666,201.16666666666666,1.0
+47,7.7,7.6,1152.0,14.0,13.0,16.0,15.0,2021-11-04 20:48:38,2021-11-04 23:59:55,2021-11-04 20:39:03,15.0,14.0,MGMCLN750N215H003,13.5,15.5,14.5,9.583333333333334,191.28333333333333,2.0
+0,7.7,7.7,1418.0,15.0,13.0,18.0,17.0,2021-10-16 13:46:40,2021-10-16 17:42:11,2021-10-16 13:33:04,15.0,13.0,MGMCLN750N215H005,14.0,17.5,14.0,13.6,235.51666666666668,3.5
+1,7.7,7.6,600.0,13.0,13.0,13.0,13.0,2021-10-18 22:27:56,2021-10-19 00:07:42,2021-10-18 22:25:51,13.0,13.0,MGMCLN750N215H005,13.0,13.0,13.0,2.0833333333333335,99.76666666666667,0.0
+2,7.7,7.6,1071.0,14.0,14.0,16.0,15.0,2021-10-20 17:47:20,2021-10-20 20:45:19,2021-10-20 17:44:21,14.0,14.0,MGMCLN750N215H005,14.0,15.5,14.0,2.9833333333333334,177.98333333333332,1.5
+4,7.7,7.7,1151.0,20.0,18.0,23.0,22.0,2021-10-21 14:56:13,2021-10-21 18:07:45,2021-10-21 14:53:55,20.0,18.0,MGMCLN750N215H005,19.0,22.5,19.0,2.3,191.53333333333333,3.5
+6,7.7,7.6,1129.0,20.0,18.0,23.0,22.0,2021-10-22 15:20:47,2021-10-22 18:28:10,2021-10-22 15:14:32,19.0,18.0,MGMCLN750N215H005,19.0,22.5,18.5,6.25,187.38333333333333,3.5
+8,7.7,7.7,140.0,16.0,16.0,17.0,17.0,2021-10-23 08:11:02,2021-10-23 08:36:06,2021-10-23 01:48:19,16.0,15.0,MGMCLN750N215H005,16.0,17.0,15.5,382.71666666666664,25.066666666666666,1.0
+9,7.7,7.7,1569.0,21.0,20.0,22.0,21.0,2021-10-23 16:00:44,2021-10-23 20:22:06,2021-10-23 15:57:04,21.0,20.0,MGMCLN750N215H005,20.5,21.5,20.5,3.6666666666666665,261.3666666666667,1.0
+10,7.7,7.7,732.0,19.0,18.0,21.0,20.0,2021-10-24 15:34:23,2021-10-24 17:36:02,2021-10-24 15:33:38,19.0,18.0,MGMCLN750N215H005,18.5,20.5,18.5,0.75,121.65,2.0
+11,7.7,7.7,729.0,18.0,18.0,19.0,18.0,2021-10-24 20:28:29,2021-10-24 22:29:42,2021-10-24 17:36:12,21.0,20.0,MGMCLN750N215H005,18.0,18.5,20.5,172.28333333333333,121.21666666666667,0.5
+14,7.6,7.6,1472.0,20.0,19.0,23.0,22.0,2021-10-25 15:01:47,2021-10-25 19:06:48,2021-10-25 14:59:27,20.0,19.0,MGMCLN750N215H005,19.5,22.5,19.5,2.3333333333333335,245.01666666666668,3.0
+17,7.7,7.7,1494.0,22.0,22.0,25.0,24.0,2021-10-26 16:11:45,2021-10-26 20:20:21,2021-10-26 16:05:58,22.0,22.0,MGMCLN750N215H005,22.0,24.5,22.0,5.783333333333333,248.6,2.5
+24,7.7,7.6,1837.0,25.0,23.0,25.0,24.0,2021-10-27 16:38:42,2021-10-27 21:44:33,2021-10-27 16:33:06,24.0,23.0,MGMCLN750N215H005,24.0,24.5,23.5,5.6,305.85,0.5
+25,7.6,7.6,1577.0,19.0,19.0,22.0,21.0,2021-10-28 15:59:35,2021-10-28 20:21:56,2021-10-28 15:54:28,19.0,19.0,MGMCLN750N215H005,19.0,21.5,19.0,5.116666666666666,262.35,2.5
+26,7.7,7.6,1329.0,21.0,19.0,24.0,23.0,2021-10-29 13:45:42,2021-10-29 17:27:05,2021-10-29 12:59:34,17.0,16.0,MGMCLN750N215H005,20.0,23.5,16.5,46.13333333333333,221.38333333333333,3.5
+28,7.7,7.7,1039.0,18.0,18.0,22.0,21.0,2021-10-31 08:17:16,2021-10-31 11:10:17,2021-10-31 01:54:55,16.0,16.0,MGMCLN750N215H005,18.0,21.5,16.0,382.35,173.01666666666668,3.5
+29,7.7,7.7,1084.0,18.0,16.0,20.0,18.0,2021-11-01 01:21:51,2021-11-01 04:22:17,2021-11-01 00:50:35,16.0,16.0,MGMCLN750N215H005,17.0,19.0,16.0,31.266666666666666,180.43333333333334,2.0
+30,7.7,7.6,1260.0,17.0,16.0,20.0,19.0,2021-11-01 13:09:53,2021-11-01 16:39:31,2021-11-01 13:07:38,17.0,16.0,MGMCLN750N215H005,16.5,19.5,16.5,2.25,209.63333333333333,3.0
+32,7.7,7.6,1687.0,17.0,15.0,19.0,18.0,2021-11-02 15:28:42,2021-11-02 20:11:34,2021-11-02 15:25:36,17.0,15.0,MGMCLN750N215H005,16.0,18.5,16.0,3.1,282.8666666666667,2.5
+34,7.7,7.6,1085.0,19.0,18.0,20.0,19.0,2021-11-03 15:30:36,2021-11-03 18:31:18,2021-11-03 15:27:49,19.0,18.0,MGMCLN750N215H005,18.5,19.5,18.5,2.783333333333333,180.7,1.0
+35,7.7,7.6,1106.0,19.0,17.0,20.0,20.0,2021-11-04 14:53:35,2021-11-04 17:57:31,2021-11-04 14:32:19,17.0,16.0,MGMCLN750N215H005,18.0,20.0,16.5,21.266666666666666,183.93333333333334,2.0
+0,7.6,7.6,588.0,16.0,16.0,17.0,17.0,2021-10-25 21:45:22,2021-10-25 23:23:19,2021-10-16 00:04:01,19.0,19.0,MGMCLN750N215H006,16.0,17.0,19.0,14261.35,97.95,1.0
+5,7.6,7.6,584.0,20.0,20.0,20.0,19.0,2021-10-26 22:15:04,2021-10-26 23:52:04,2021-10-26 21:02:59,21.0,21.0,MGMCLN750N215H006,20.0,19.5,21.0,72.08333333333333,97.0,-0.5
+10,7.6,7.6,1191.0,18.0,17.0,20.0,19.0,2021-10-28 23:29:35,2021-10-29 03:45:06,2021-10-28 23:18:20,18.0,17.0,MGMCLN750N215H006,17.5,19.5,17.5,11.25,255.51666666666668,2.0
+11,7.6,7.6,1731.0,20.0,19.0,19.0,19.0,2021-10-29 19:57:12,2021-10-30 00:45:04,2021-10-29 19:54:55,20.0,19.0,MGMCLN750N215H006,19.5,19.0,19.5,2.283333333333333,287.8666666666667,-0.5
+18,7.6,7.6,1884.0,18.0,17.0,21.0,20.0,2021-10-31 05:15:47,2021-10-31 10:30:27,2021-10-31 05:12:11,19.0,17.0,MGMCLN750N215H006,17.5,20.5,18.0,3.6,314.6666666666667,3.0
+21,7.6,7.6,680.0,21.0,20.0,20.0,19.0,2021-10-31 15:17:08,2021-10-31 17:12:02,2021-10-31 15:14:08,21.0,21.0,MGMCLN750N215H006,20.5,19.5,21.0,3.0,114.9,-1.0
+23,7.6,7.6,1493.0,16.0,15.0,18.0,17.0,2021-11-01 02:37:48,2021-11-01 06:46:17,2021-11-01 02:23:09,16.0,15.0,MGMCLN750N215H006,15.5,17.5,15.5,14.65,248.48333333333332,2.0
+24,7.6,7.6,2108.0,14.0,13.0,19.0,18.0,2021-11-02 02:35:01,2021-11-02 08:26:04,2021-11-02 02:31:59,15.0,13.0,MGMCLN750N215H006,13.5,18.5,14.0,3.033333333333333,351.05,5.0
+33,0.8,0.0,2043.0,16.0,16.0,19.0,18.0,2021-11-03 14:16:12,2021-11-03 19:58:19,2021-11-03 14:13:51,16.0,16.0,MGMCLN750N215H006,16.0,18.5,16.0,2.35,342.1166666666667,2.5
+10,3.0,3.0,3778.0,14.0,13.0,12.0,11.0,2021-10-16 22:31:27,2021-10-17 09:11:46,2021-10-16 22:24:05,14.0,13.0,MGMCLN750N215H008,13.5,11.5,13.5,7.366666666666666,640.3166666666667,-2.0
+19,3.0,3.0,3840.0,16.0,15.0,14.0,13.0,2021-10-17 22:35:11,2021-10-18 09:14:47,2021-10-17 22:27:11,16.0,15.0,MGMCLN750N215H008,15.5,13.5,15.5,8.0,639.6,-2.0
+30,3.0,2.9,2941.0,18.0,17.0,13.0,12.0,2021-10-18 22:01:06,2021-10-19 06:10:51,2021-10-18 21:52:31,18.0,17.0,MGMCLN750N215H008,17.5,12.5,17.5,8.583333333333334,489.75,-5.0
+34,3.0,3.0,2904.0,16.0,14.0,12.0,11.0,2021-10-19 23:00:40,2021-10-20 07:04:08,2021-10-19 22:53:00,16.0,14.0,MGMCLN750N215H008,15.0,11.5,15.0,7.666666666666667,483.46666666666664,-3.5
+41,3.0,2.9,1378.0,16.0,15.0,15.0,14.0,2021-10-20 18:54:18,2021-10-20 22:43:48,2021-10-20 18:47:07,16.0,15.0,MGMCLN750N215H008,15.5,14.5,15.5,7.183333333333334,229.5,-1.0
+52,3.0,2.9,3342.0,20.0,18.0,16.0,15.0,2021-10-21 19:59:57,2021-10-22 05:16:25,2021-10-21 19:53:32,20.0,18.0,MGMCLN750N215H008,19.0,15.5,19.0,6.416666666666667,556.4666666666667,-3.5
+65,0.2,0.0,3903.0,17.0,16.0,16.0,15.0,2021-10-22 23:40:26,2021-10-23 10:31:33,2021-10-22 23:34:43,17.0,16.0,MGMCLN750N215H008,16.5,15.5,16.5,5.716666666666667,651.1166666666667,-1.0
+73,3.0,3.0,3821.0,18.0,16.0,15.0,14.0,2021-10-23 23:14:28,2021-10-24 09:50:22,2021-10-23 23:06:25,18.0,17.0,MGMCLN750N215H008,17.0,14.5,17.5,8.05,635.9,-2.5
+88,3.0,2.9,3843.0,17.0,16.0,16.0,15.0,2021-10-24 23:20:20,2021-10-25 09:59:54,2021-10-24 23:12:10,18.0,16.0,MGMCLN750N215H008,16.5,15.5,17.0,8.166666666666666,639.5666666666667,-1.0
+96,3.0,3.0,2845.0,19.0,18.0,18.0,17.0,2021-10-25 22:57:11,2021-10-26 06:50:58,2021-10-25 22:50:34,20.0,18.0,MGMCLN750N215H008,18.5,17.5,19.0,6.616666666666666,473.78333333333336,-1.0
+101,3.0,3.0,3291.0,22.0,20.0,18.0,17.0,2021-10-26 23:51:31,2021-10-27 09:00:23,2021-10-26 23:44:52,22.0,20.0,MGMCLN750N215H008,21.0,17.5,21.0,6.65,548.8666666666667,-3.5
+107,3.0,3.0,1101.0,20.0,19.0,17.0,16.0,2021-10-27 23:40:08,2021-10-28 08:55:20,2021-10-27 23:32:34,21.0,19.0,MGMCLN750N215H008,19.5,16.5,20.0,7.566666666666666,555.2,-3.0
+115,3.0,2.9,1980.0,21.0,20.0,18.0,18.0,2021-10-28 20:58:27,2021-10-29 03:24:45,2021-10-28 20:51:34,21.0,20.0,MGMCLN750N215H008,20.5,18.0,20.5,6.883333333333334,386.3,-2.5
+119,3.0,2.9,982.0,20.0,19.0,19.0,18.0,2021-10-29 18:37:30,2021-10-29 21:20:49,2021-10-29 13:22:23,19.0,18.0,MGMCLN750N215H008,19.5,18.5,18.5,315.1166666666667,163.31666666666666,-1.0
+129,1.1,0.0,3686.0,20.0,19.0,19.0,18.0,2021-10-31 00:10:20,2021-10-31 10:29:56,2021-10-31 00:06:34,20.0,19.0,MGMCLN750N215H008,19.5,18.5,19.5,3.7666666666666666,619.6,-1.0
+139,3.0,3.0,3917.0,17.0,16.0,15.0,14.0,2021-10-31 23:01:38,2021-11-01 09:54:02,2021-10-31 22:54:07,18.0,16.0,MGMCLN750N215H008,16.5,14.5,17.0,7.516666666666667,652.4,-2.0
+143,3.0,3.0,2095.0,17.0,16.0,16.0,15.0,2021-11-01 16:57:28,2021-11-01 22:46:11,2021-11-01 16:51:06,17.0,16.0,MGMCLN750N215H008,16.5,15.5,16.5,6.366666666666666,348.71666666666664,-1.0
+150,3.0,3.0,2918.0,15.0,13.0,15.0,14.0,2021-11-02 22:55:04,2021-11-03 07:00:55,2021-11-02 22:47:38,15.0,14.0,MGMCLN750N215H008,14.0,14.5,14.5,7.433333333333334,485.85,0.5
+159,8.0,7.9,1080.0,15.0,14.0,14.0,13.0,2021-11-03 22:32:40,2021-11-04 01:32:12,2021-11-03 21:20:47,16.0,15.0,MGMCLN750N215H008,14.5,13.5,15.5,71.88333333333334,179.53333333333333,-1.0
+161,8.0,7.9,1100.0,16.0,14.0,16.0,15.0,2021-11-04 20:56:46,2021-11-04 23:59:57,2021-11-04 20:37:33,17.0,14.0,MGMCLN750N215H008,15.0,15.5,15.5,19.216666666666665,183.18333333333334,0.5
+3,7.8,7.8,1618.0,11.0,10.0,13.0,12.0,2021-10-20 21:57:37,2021-10-21 02:27:02,2021-10-20 21:57:36,11.0,10.0,MGMCLN750N215H009,10.5,12.5,10.5,0.016666666666666666,269.4166666666667,2.0
+5,7.8,7.8,2114.0,17.0,16.0,17.0,15.0,2021-10-22 22:10:42,2021-10-23 04:03:21,2021-10-22 22:06:49,17.0,16.0,MGMCLN750N215H009,16.5,16.0,16.5,3.8833333333333333,352.65,-0.5
+7,7.8,7.8,2043.0,16.0,15.0,17.0,15.0,2021-10-23 22:05:55,2021-10-24 03:46:06,2021-10-23 22:02:08,16.0,15.0,MGMCLN750N215H009,15.5,16.0,15.5,3.783333333333333,340.18333333333334,0.5
+8,7.8,7.8,1866.0,16.0,16.0,18.0,16.0,2021-10-24 22:01:54,2021-10-25 03:12:45,2021-10-24 21:59:03,17.0,16.0,MGMCLN750N215H009,16.0,17.0,16.5,2.85,310.85,1.0
+12,7.8,7.7,1891.0,17.0,16.0,20.0,18.0,2021-10-25 23:44:37,2021-10-26 04:59:34,2021-10-25 23:40:17,17.0,16.0,MGMCLN750N215H009,16.5,19.0,16.5,4.333333333333333,314.95,2.5
+13,7.8,7.8,1924.0,20.0,19.0,21.0,18.0,2021-10-26 22:30:20,2021-10-27 03:50:39,2021-10-26 22:26:04,20.0,20.0,MGMCLN750N215H009,19.5,19.5,20.0,4.266666666666667,320.31666666666666,0.0
+14,7.8,7.8,875.0,19.0,18.0,22.0,20.0,2021-10-27 22:02:52,2021-10-28 00:28:32,2021-10-27 21:59:31,19.0,18.0,MGMCLN750N215H009,18.5,21.0,18.5,3.35,145.66666666666666,2.5
+15,7.8,7.8,1585.0,18.0,17.0,20.0,18.0,2021-10-28 22:07:55,2021-10-29 03:28:33,2021-10-28 22:04:17,18.0,17.0,MGMCLN750N215H009,17.5,19.0,17.5,3.6333333333333333,320.6333333333333,1.5
+17,7.8,7.8,1701.0,18.0,17.0,19.0,17.0,2021-10-29 22:15:40,2021-10-30 02:58:50,2021-10-29 22:12:37,18.0,17.0,MGMCLN750N215H009,17.5,18.0,17.5,3.05,283.1666666666667,0.5
+18,7.8,7.8,1796.0,19.0,18.0,22.0,19.0,2021-10-30 22:05:42,2021-10-31 03:10:56,2021-10-30 22:02:04,19.0,18.0,MGMCLN750N215H009,18.5,20.5,18.5,3.6333333333333333,305.23333333333335,2.0
+19,7.8,7.8,1649.0,17.0,16.0,18.0,17.0,2021-10-31 22:08:52,2021-11-01 02:43:22,2021-10-31 22:05:12,17.0,16.0,MGMCLN750N215H009,16.5,17.5,16.5,3.6666666666666665,274.5,1.0
+21,7.8,7.8,1867.0,14.0,14.0,18.0,16.0,2021-11-01 22:07:13,2021-11-02 03:18:05,2021-11-01 22:03:51,14.0,14.0,MGMCLN750N215H009,14.0,17.0,14.0,3.3666666666666667,310.8666666666667,3.0
+24,7.8,7.8,2178.0,15.0,13.0,19.0,17.0,2021-11-02 22:17:04,2021-11-03 04:19:45,2021-11-02 22:13:32,16.0,13.0,MGMCLN750N215H009,14.0,18.0,14.5,3.533333333333333,362.68333333333334,4.0
+27,7.8,7.8,2191.0,14.0,13.0,19.0,16.0,2021-11-03 22:20:27,2021-11-04 04:25:12,2021-11-03 22:13:18,14.0,13.0,MGMCLN750N215H009,13.5,17.5,13.5,7.15,364.75,4.0
+29,7.8,7.8,545.0,14.0,13.0,17.0,15.0,2021-11-04 22:29:26,2021-11-04 23:59:51,2021-11-04 22:25:51,14.0,13.0,MGMCLN750N215H009,13.5,16.0,13.5,3.5833333333333335,90.41666666666667,2.5
+0,7.7,7.6,2075.0,14.0,12.0,13.0,12.0,2021-10-17 23:27:24,2021-10-18 05:12:43,2021-10-17 23:23:06,14.0,12.0,MGMCLN750N215H010,13.0,12.5,13.0,4.3,345.31666666666666,-0.5
+7,7.6,7.6,2544.0,13.0,13.0,12.0,11.0,2021-10-18 21:42:37,2021-10-19 04:46:15,2021-10-18 14:04:02,22.0,20.0,MGMCLN750N215H010,13.0,11.5,21.0,458.5833333333333,423.6333333333333,-1.5
+8,7.6,7.6,1731.0,14.0,12.0,12.0,11.0,2021-10-19 23:27:33,2021-10-20 04:15:36,2021-10-19 23:04:44,14.0,13.0,MGMCLN750N215H010,13.0,11.5,13.5,22.816666666666666,288.05,-1.5
+15,7.7,0.0,2802.0,11.0,10.0,11.0,10.0,2021-10-20 22:13:01,2021-10-21 05:59:34,2021-10-20 14:29:13,23.0,21.0,MGMCLN750N215H010,10.5,10.5,22.0,463.8,466.55,0.0
+17,7.7,7.6,2175.0,21.0,19.0,17.0,16.0,2021-10-21 22:31:05,2021-10-22 04:33:16,2021-10-21 22:21:55,21.0,19.0,MGMCLN750N215H010,20.0,16.5,20.0,9.166666666666666,362.18333333333334,-3.5
+24,7.7,7.6,1881.0,20.0,19.0,17.0,17.0,2021-10-22 20:10:34,2021-10-23 01:24:15,2021-10-22 19:40:00,21.0,19.0,MGMCLN750N215H010,19.5,17.0,20.0,30.566666666666666,313.68333333333334,-2.5
+30,7.7,7.6,2564.0,14.0,14.0,13.0,12.0,2021-10-23 21:29:04,2021-10-24 04:36:05,2021-10-23 21:06:48,15.0,14.0,MGMCLN750N215H010,14.0,12.5,14.5,22.266666666666666,427.01666666666665,-1.5
+34,7.6,7.6,2631.0,20.0,18.0,15.0,14.0,2021-10-26 21:25:00,2021-10-27 04:43:14,2021-10-26 21:20:55,20.0,18.0,MGMCLN750N215H010,19.0,14.5,19.0,4.083333333333333,438.23333333333335,-4.5