zhuxi 3 years ago
parent
commit
6098aabc09
1 changed files with 277 additions and 0 deletions
  1. 277 0
      LIB/MIDDLE/odo/DailyMileageEstimation/mileage.py

+ 277 - 0
LIB/MIDDLE/odo/DailyMileageEstimation/mileage.py

@@ -0,0 +1,277 @@
+import pandas as pd
+import numpy as np
+from LIB.BACKEND.DataPreProcess import DataPreProcess
+import os
+import math
+import datetime
+import time
+
+def cal_mileage(sn,data_gps,data_bms):
+
+    
+    #将时间戳由 "%Y-%m-%d %H:%M:%S" 切换为 sec
+    def timeconvert(df_in,column_name):  
+        df=df_in.copy()
+        df.index=range(len(df))
+        time=df[column_name]
+        timeInSeries=[]
+        
+        time2=datetime.datetime.strptime(time[0],"%Y-%m-%d %H:%M:%S")
+        for k in range(len(time)):
+            time1=datetime.datetime.strptime(time[k],"%Y-%m-%d %H:%M:%S")    
+            t=(time1-time2)
+            timeInSeries.append(t.days*86400+t.seconds)
+        df.loc[:,'相对时间[s]']=pd.DataFrame(timeInSeries,columns=['相对时间[s]'])
+        return df
+
+    data_bms=timeconvert(data_bms,'时间戳')
+
+    #计算累积能量
+    def cal_accumKwh(df_in):
+        I=df_in['总电流[A]'].values
+        V=df_in['总电压[V]'].values
+        t=df_in['相对时间[s]'].values
+        accumAh=[0.0]
+        for k in range(1,len(I)):
+            accumAh_temp=(t[k]-t[k-1])*((I[k]+I[k-1])/(2*3600))*(V[k]+V[k-1])/2/1000
+            accumAh.append(accumAh[-1]+accumAh_temp)
+        df_in.loc[:,'累积能量[Kwh]']=accumAh
+        return(df_in)
+
+    data_bms=cal_accumKwh(data_bms)
+
+    #合并两张表格
+    df_bms=data_bms.copy()
+    df_gps=data_gps.copy()
+    df_bms.set_index(["时间戳"], inplace=True)
+    df_gps.set_index(["时间戳"], inplace=True)
+    df_temp = df_bms.append(df_gps)
+    df_temp=df_temp.sort_index(ascending=True)
+    df_temp.loc[:,'时间']=df_temp.index
+    df_temp.index=[k for k in range(len(df_temp))]
+    df_sheetCat=df_temp.copy()
+    df_sheetCat=timeconvert(df_sheetCat,'时间')
+    df_sheetCat=df_sheetCat.rename(columns={'时间':'时间戳'})
+    df_sheetCat=DataPreProcess.data_split_by_status(DataPreProcess,df_sheetCat, drive_interval_threshold=120, charge_interval_threshold=300, drive_stand_threshold=120, charge_stand_threshold=300)
+
+    #数据整理
+    df1=df_sheetCat.copy()
+    #如果前后data_status均不为none,但是本次为none,则将本次data_status设置为与上次相同。
+    data_status=df1['data_status'].values
+    for k in range(1,len(data_status)-1):
+        if data_status[k-1]!='none' and data_status[k+1]!='none':
+            df1.loc[k,'data_status']=data_status[k-1]
+
+    #如果前后两次电流值均不为nan,则将总电流[A]、总电压[V]、SOC[%]设置为与前次相同。
+    data_current=df1['总电流[A]'].values
+    for k in range(1,len(data_current)-1):
+        if not math.isnan(data_current[k-1]) and not math.isnan(data_current[k+1]) and math.isnan(data_current[k]):
+            df1.loc[k,'总电流[A]']=df1.loc[k-1,'总电流[A]']
+            df1.loc[k,'总电压[V]']=df1.loc[k-1,'总电压[V]']
+            df1.loc[k,'SOC[%]']=df1.loc[k-1,'SOC[%]']
+
+    #如果前后两次能量均不是NAN,但是本次为NAN,则将上次的能量指赋值给本次
+    AccumEnergy=df1['累积能量[Kwh]'].values
+    for k in range(1,len(AccumEnergy)-1):
+        if not math.isnan(AccumEnergy[k-1]) and not math.isnan(AccumEnergy[k+1]) and math.isnan(AccumEnergy[k]):
+            df1.loc[k,'累积能量[Kwh]']=AccumEnergy[k-1]
+
+    #删除一些无用列,获取用于计算的数据
+    df_input=df1[['时间戳','总电流[A]', '总电压[V]','SOC[%]','相对时间[s]', '累积能量[Kwh]','纬度', '经度','data_status']]
+    #筛选出有经纬度信息的数据
+    df_gpsOnly=df_input[df_input['纬度']>0]
+
+    #根据经纬度获取两点之间的距离
+    def cal_dis_meters(radius,latitude1, longitude1,latitude2, longitude2):  
+        radLat1 = (math.pi/180)*latitude1  
+        radLat2 = (math.pi/180)*latitude2  
+        radLng1 = (math.pi/180)*longitude1  
+        radLng2= (math.pi/180)*longitude2      
+        d=2*math.asin(math.sqrt(math.pow(math.sin((radLat1-radLat2)/2.0),2)+math.cos(radLat1)*math.cos(radLat2)*math.pow(math.sin((radLng1-radLng2)/2.0),2)))*radius
+        return d
+
+    #根据gps数据计算△距离1和△距离2
+    #△距离1:直接根据两次的经度和纬度计算得到的马氏距离
+    #△距离2:当两次上报经纬度的时间间隔<60sec时,如果车辆为行驶状态则使用两次的经纬度求得的马氏距离,
+    #如果车辆不为行驶状态,则为0.
+    index_list=df_gpsOnly.index
+    pos_list=df_gpsOnly[['纬度','经度']].values
+    time_list=df_input['相对时间[s]'].values
+    Energy_list=df_input['累积能量[Kwh]'].values
+    for k in range(1,len(pos_list)):
+        latitude1=pos_list[k-1][0]
+        longitude1=pos_list[k-1][1]
+        latitude2=pos_list[k][0]
+        longitude2=pos_list[k][1]
+        dlt_odo=cal_dis_meters(6378.137,latitude1, longitude1,latitude2, longitude2)
+        df_gpsOnly.loc[index_list[k],'△距离1']=dlt_odo    
+        if time_list[index_list[k]]-time_list[index_list[k-1]]<60:#两次上传GPS数据时间间隔小于60sec
+            if df_gpsOnly.loc[index_list[k],'data_status']=='drive' :   
+                df_gpsOnly.loc[index_list[k],'△距离2']=dlt_odo
+            elif df_gpsOnly.loc[index_list[k],'data_status']=='none' :
+                df_gpsOnly.loc[index_list[k],'△距离2']=dlt_odo
+            else:
+                df_gpsOnly.loc[index_list[k],'△距离2']=0
+
+    #如果某一段数据中有gps数据但是没有bms数据,里程按照gps数据计算,但是到有gps数据之后,发现累积能量变化不大于0,因此需要将这期间的里程均设置为0km            
+    df_gpsOnly_copy=df_gpsOnly.copy()
+    df_gpsOnly_copy.index=[i for i in range(len(df_gpsOnly))]
+    df_bmsOnly=df_gpsOnly_copy[df_gpsOnly_copy['总电压[V]']>0]
+    energy2=df_bmsOnly['累积能量[Kwh]'].values
+    df_bmsOnly_index=df_bmsOnly.index.values
+    for k in range(1,len(df_bmsOnly)):
+        if not (energy2[k]-energy2[k-1]>0):
+            for n in range(df_bmsOnly_index[k-1],df_bmsOnly_index[k]+1):
+                df_gpsOnly_copy.loc[n,'△距离2']=0
+
+    dis2=df_gpsOnly_copy['△距离2'].values
+    relatedTime=df_gpsOnly_copy['相对时间[s]'].values
+    nan_flag=0
+
+    for k in range(1,len(dis2)):
+        if math.isnan(dis2[k]) and (not math.isnan(dis2[k-1])): #本次△距离2为NAN但是上次不为NAN
+            nan_flag=1
+            ###平均能耗计算
+            st_time=relatedTime[k]-600  #10min之前的时刻点
+            df2=df_gpsOnly_copy[df_gpsOnly_copy['相对时间[s]']>=st_time]
+            df_temp2=df2[df2['相对时间[s]']<=relatedTime[k]]
+            df_temp2=df_temp2[['相对时间[s]','累积能量[Kwh]','△距离2']]
+            df_temp3=df_temp2.dropna(axis=0,how='any') 
+            if len(df_temp3)>5:
+                # st_time=relatedTime[k-1]-600  #10min之前的时刻点
+                # df2=df_gpsOnly_copy[df_gpsOnly_copy['相对时间[s]']>=st_time]
+                # df_temp2=df2[df2['相对时间[s]']<=relatedTime[k]]
+                
+                energy=df_temp3['累积能量[Kwh]'].values
+                dis_temp=df_temp3['△距离2'].values
+                # dis_temp_delet_nan=dis_temp[np.logical_not(np.isnan(dis_temp))]
+                df_gpsOnly_copy.loc[k,'△能量[Kwh]']=energy[-1]-energy[0]
+                df_gpsOnly_copy.loc[k,'累积距离[km]']=dis_temp[1:-1].sum()
+                if energy[-1]-energy[0]>0:
+                    df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=min(max(df_gpsOnly_copy.loc[k,'累积距离[km]']/df_gpsOnly_copy.loc[k,'△能量[Kwh]'],25),50)
+                else:
+                    if dis_temp[1:-1].sum()>0:
+                        df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=30
+                    else:
+                        df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=0
+            else:
+                df_temp2=df_gpsOnly_copy[df_gpsOnly_copy['相对时间[s]']<=relatedTime[k]]
+                df_energyPerKm=df_gpsOnly_copy[df_gpsOnly_copy['能耗[km/kwh]']>0]
+                df_energyPerKm.index=[i for i in range(len(df_energyPerKm))]
+                total_num=len(df_energyPerKm)
+                #统计最近10次的平均能耗,用于补充dis2前后都为nan时刻处的能耗及距离,
+                ##如果不足10次按照实际次数统计
+                if total_num>10:
+                    energycost_acc=0
+                    for i in range(10):
+                        energycost_acc=energycost_acc+df_energyPerKm.loc[total_num-i-1,'能耗[km/kwh]']
+                    avg_energyCost=min(max(energycost_acc/10,25),50)
+                    df_gpsOnly_copy.loc[k,'△能量[Kwh]']=1
+                    df_gpsOnly_copy.loc[k,'累积距离[km]']=avg_energyCost
+                    df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=avg_energyCost
+                elif total_num>0:
+                    avg_energyCost=min(max(df_energyPerKm['能耗[km/kwh]'].values.mean(),25),50)
+                    df_gpsOnly_copy.loc[k,'△能量[Kwh]']=1
+                    df_gpsOnly_copy.loc[k,'累积距离[km]']=avg_energyCost
+                    df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=avg_energyCost
+                else:
+                    df_gpsOnly_copy.loc[k,'△能量[Kwh]']=df_gpsOnly_copy.loc[k-1,'△能量[Kwh]'] 
+                    df_gpsOnly_copy.loc[k,'累积距离[km]']=df_gpsOnly_copy.loc[k-1,'累积距离[km]']
+                    df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=df_gpsOnly_copy.loc[k-1,'能耗[km/kwh]']
+                
+            
+            ####行驶里程估计
+            energy1=df_temp2['累积能量[Kwh]'].values
+            if energy1[-1]-energy1[-2]>0:
+                gps_dis=df_gpsOnly_copy.loc[k,'△距离1']
+                delta_t=df_gpsOnly_copy.loc[k,'相对时间[s]']-df_gpsOnly_copy.loc[k-1,'相对时间[s]']
+                vehspd=gps_dis*3600/delta_t
+                if vehspd>30:
+                    df_gpsOnly_copy.loc[k,'△距离3[km]']=(energy1[-1]-energy1[-2])*df_gpsOnly_copy.loc[k,'能耗[km/kwh]']
+                else:
+                    df_gpsOnly_copy.loc[k,'△距离3[km]']=max((energy1[-1]-energy1[-2])*df_gpsOnly_copy.loc[k,'能耗[km/kwh]'],gps_dis)
+            else:
+                df_gpsOnly_copy.loc[k,'△距离3[km]']=0
+
+            df_gpsOnly_copy.loc[k,'△距离2']=df_gpsOnly_copy.loc[k,'△距离3[km]']
+            
+        elif math.isnan(dis2[k]) and (math.isnan(dis2[k-1])) and nan_flag==1: #本次△距离为NAN上次也为NAN
+            df_energyPerKm=df_gpsOnly_copy[df_gpsOnly_copy['能耗[km/kwh]']>0]
+            df_energyPerKm.index=[i for i in range(len(df_energyPerKm))]
+            total_num=len(df_energyPerKm)
+            #统计最近10次的平均能耗,用于补充dis2前后都为nan时刻处的能耗及距离,
+            ##如果不足10次按照实际次数统计
+            if total_num>10:
+                energycost_acc=0
+                for i in range(10):
+                    energycost_acc=energycost_acc+df_energyPerKm.loc[total_num-i-1,'能耗[km/kwh]']
+                avg_energyCost=min(max(energycost_acc/10,25),50)
+                df_gpsOnly_copy.loc[k,'△能量[Kwh]']=1
+                df_gpsOnly_copy.loc[k,'累积距离[km]']=avg_energyCost
+                df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=avg_energyCost
+            elif total_num>0:
+                avg_energyCost=min(max(df_energyPerKm['能耗[km/kwh]'].values.mean(),25),50)
+                df_gpsOnly_copy.loc[k,'△能量[Kwh]']=1
+                df_gpsOnly_copy.loc[k,'累积距离[km]']=avg_energyCost
+                df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=avg_energyCost
+            else:
+                df_gpsOnly_copy.loc[k,'△能量[Kwh]']=df_gpsOnly_copy.loc[k-1,'△能量[Kwh]'] 
+                df_gpsOnly_copy.loc[k,'累积距离[km]']=df_gpsOnly_copy.loc[k-1,'累积距离[km]']
+                df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=df_gpsOnly_copy.loc[k-1,'能耗[km/kwh]']
+            
+            ##计算行驶里程
+            delta_energy=df_gpsOnly_copy.loc[k,'累积能量[Kwh]']-df_gpsOnly_copy.loc[k-1,'累积能量[Kwh]']
+            if delta_energy>0:
+                gps_dis=df_gpsOnly_copy.loc[k,'△距离1']
+                delta_t=df_gpsOnly_copy.loc[k,'相对时间[s]']-df_gpsOnly_copy.loc[k-1,'相对时间[s]']
+                vehspd=gps_dis*3600/delta_t
+                if vehspd>30:
+                    df_gpsOnly_copy.loc[k,'△距离3[km]']=delta_energy*df_gpsOnly_copy.loc[k,'累积距离[km]']/df_gpsOnly_copy.loc[k,'△能量[Kwh]']
+                else:
+                    df_gpsOnly_copy.loc[k,'△距离3[km]']=max(delta_energy*df_gpsOnly_copy.loc[k,'累积距离[km]']/df_gpsOnly_copy.loc[k,'△能量[Kwh]'],gps_dis)
+            else:
+                df_gpsOnly_copy.loc[k,'△距离3[km]']=0
+            
+            df_gpsOnly_copy.loc[k,'△距离2']=df_gpsOnly_copy.loc[k,'△距离3[km]']
+        else:
+            df_gpsOnly_copy.loc[k,'△能量[Kwh]']=1
+            df_gpsOnly_copy.loc[k,'累积距离[km]']=25
+            df_gpsOnly_copy.loc[k,'能耗[km/kwh]']=25
+            df_gpsOnly_copy.loc[k,'△距离3[km]']=df_gpsOnly_copy.loc[k,'△距离2']
+
+    ###############输出计算结果##################
+    ############################################
+    df_gpsOnly_copy.loc[0,'累积里程[km]']=0
+    df_gpsOnly_copy.loc[0,'日期']=str(df_gpsOnly_copy.loc[0,'时间戳'])[0:10]  
+
+    for k in range(1,len(df_gpsOnly_copy)):
+        df_dis_temp=df_gpsOnly_copy['△距离3[km]'].values[0:k+1]
+        df_dis_temp1=df_dis_temp[np.logical_not(np.isnan(df_dis_temp))]
+        if len(df_dis_temp1)>0:
+            df_gpsOnly_copy.loc[k,'累积里程[km]']=df_dis_temp1.sum()
+        else:
+            df_gpsOnly_copy.loc[k,'累积里程[km]']=df_gpsOnly_copy.loc[k-1,'累积里程[km]']
+        df_gpsOnly_copy.loc[k,'日期']=str(df_gpsOnly_copy.loc[k,'时间戳'])[0:10] 
+
+    datetime1=np.unique(df_gpsOnly_copy['日期'].values)
+    df_result=pd.DataFrame(index=datetime1)
+    list_result=[]
+    list_day_odo=[]
+
+    for k in range(len(datetime1)):
+        df_day=df_gpsOnly_copy[df_gpsOnly_copy['日期']==datetime1[k]]
+        odo_day=df_day['累积里程[km]'].values
+        df_result.loc[datetime1[k],'累积里程[km]']=odo_day[-1]-odo_day[0]
+        df_day['累积里程[km]']=odo_day-odo_day[0]
+        list_day_odo.extend(odo_day-odo_day[0])
+        list_result.append([datetime1[k],df_day])
+
+    df_gpsOnly_copy.loc[:,'每日累积里程[km]']=list_day_odo
+
+    #删除一些无用列,获取用于计算的数据
+    df_output=df_gpsOnly_copy[['时间戳','data_status','SOC[%]','每日累积里程[km]']]
+
+    #添加sn
+    df_output['sn'] = sn
+    return df_output
+