|
@@ -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
|
|
|
+
|