|
@@ -0,0 +1,321 @@
|
|
|
|
+import pandas as pd
|
|
|
|
+import numpy as np
|
|
|
|
+import os
|
|
|
|
+import math
|
|
|
|
+import datetime
|
|
|
|
+import time
|
|
|
|
+
|
|
|
|
+#将时间戳由 "%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(str(time[0]),"%Y-%m-%d %H:%M:%S")
|
|
|
|
+ for k in range(len(time)):
|
|
|
|
+ time1=datetime.datetime.strptime(str(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
|
|
|
|
+
|
|
|
|
+#计算累积能量
|
|
|
|
+def cal_accumKwh(df_in):
|
|
|
|
+ df_in1=df_in.copy()
|
|
|
|
+ df1=df_in1[['总电流[A]','总电压[V]','相对时间[s]']]
|
|
|
|
+ df1=df1.dropna(axis=0,how='any')
|
|
|
|
+ I=df1['总电流[A]'].values
|
|
|
|
+ V=df1['总电压[V]'].values
|
|
|
|
+ t=df1['相对时间[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)
|
|
|
|
+ df1.loc[:,'累积能量[Kwh]']=accumAh
|
|
|
|
+ df_out=pd.merge(df_in1,df1[['累积能量[Kwh]']],how='left',left_index=True, right_index=True)
|
|
|
|
+ return(df_out)
|
|
|
|
+
|
|
|
|
+#将时间格式化为整数
|
|
|
|
+def str_data_to_num(str_data):
|
|
|
|
+ # 格式时间成毫秒
|
|
|
|
+ strptime = time.strptime(str_data,"%Y-%m-%d %H:%M:%S")
|
|
|
|
+ # print("strptime",strptime)
|
|
|
|
+ mktime = int(time.mktime(strptime)*1000)
|
|
|
|
+ # print("mktime",mktime)
|
|
|
|
+ return mktime
|
|
|
|
+
|
|
|
|
+def df_date_To_int(df_in):
|
|
|
|
+ df=df_in.copy()
|
|
|
|
+ for k in range(len(df)):
|
|
|
|
+ df.loc[k,'绝对时间[ms]']=str_data_to_num(df['时间戳'][k])
|
|
|
|
+ return df
|
|
|
|
+
|
|
|
|
+#根据经纬度获取两点之间的距离
|
|
|
|
+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
|
|
|
|
+
|
|
|
|
+#第一部分距离计算
|
|
|
|
+def cal_distance1(part1,avg_cost):
|
|
|
|
+ part1.index=[i for i in range(len(part1))]
|
|
|
|
+ part1=part1.copy()
|
|
|
|
+ part1.loc[0,'△距离']=0
|
|
|
|
+ AccumEnergy1=part1['累积能量[Kwh]'].values
|
|
|
|
+ for k1 in range(1,len(part1)):
|
|
|
|
+ if (AccumEnergy1[k1]-AccumEnergy1[k1-1])>0:
|
|
|
|
+ part1.loc[k1,'△距离']=(AccumEnergy1[k1]-AccumEnergy1[k1-1])*avg_cost
|
|
|
|
+ part1.loc[k1,'方法']=4
|
|
|
|
+ else:
|
|
|
|
+ part1.loc[k1,'△距离']=0
|
|
|
|
+ part1.loc[k1,'方法']=5
|
|
|
|
+ return part1
|
|
|
|
+
|
|
|
|
+#第二部分计算
|
|
|
|
+def cal_distance2(part2,avg_cost):
|
|
|
|
+ part2_gps=part2[part2['纬度']>0]
|
|
|
|
+ part2_gps.index=[i for i in range(len(part2_gps))]
|
|
|
|
+ times_list=part2_gps['相对时间[s]'].values
|
|
|
|
+ lat=part2_gps['纬度'].values
|
|
|
|
+ lng=part2_gps['经度'].values
|
|
|
|
+ AccumEnergy2=part2_gps['累积能量[Kwh]'].values
|
|
|
|
+ part2_gps=part2_gps.copy()
|
|
|
|
+ part2_gps.loc[0,'△距离']=0
|
|
|
|
+ for k2 in range(1,len(part2_gps)):
|
|
|
|
+ delta_energy=AccumEnergy2[k2]-AccumEnergy2[k2-1]
|
|
|
|
+ delta_span=cal_dis_meters(6378.137,lat[k2], lng[k2],lat[k2-1], lng[k2-1])
|
|
|
|
+ v_spd=3600*delta_span/(times_list[k2]-times_list[k2-1])
|
|
|
|
+ if times_list[k2]-times_list[k2-1]<60:
|
|
|
|
+ if v_spd>70 :
|
|
|
|
+ part2_gps.loc[k2,'△距离']=delta_energy*avg_cost
|
|
|
|
+ part2_gps.loc[k2,'方法']=1_1
|
|
|
|
+ else:
|
|
|
|
+ part2_gps.loc[k2,'△距离']=delta_span
|
|
|
|
+ part2_gps.loc[k2,'方法']=1_2
|
|
|
|
+ else:
|
|
|
|
+ if delta_energy<=0:
|
|
|
|
+ part2_gps.loc[k2,'△距离']=0
|
|
|
|
+ part2_gps.loc[k2,'方法']=2
|
|
|
|
+ else:
|
|
|
|
+ if v_spd>70:
|
|
|
|
+ part2_gps.loc[k2,'△距离']=delta_energy*avg_cost
|
|
|
|
+ part2_gps.loc[k2,'方法']=3_1
|
|
|
|
+ else:
|
|
|
|
+ part2_gps.loc[k2,'△距离']=max(delta_span,delta_energy*avg_cost)
|
|
|
|
+ part2_gps.loc[k2,'方法']=3_2
|
|
|
|
+ return part2_gps
|
|
|
|
+
|
|
|
|
+#第三部分距离计算
|
|
|
|
+def cal_distance3(part3,avg_cost):
|
|
|
|
+ part3.index=[i for i in range(len(part3))]
|
|
|
|
+ part3=part3.copy()
|
|
|
|
+ part3.loc[0,'△距离']=0
|
|
|
|
+ AccumEnergy3=part3['累积能量[Kwh]'].values
|
|
|
|
+ for k3 in range(1,len(part3)):
|
|
|
|
+ if (AccumEnergy3[k3]-AccumEnergy3[k3-1])>0:
|
|
|
|
+ part3.loc[k3,'△距离']=(AccumEnergy3[k3]-AccumEnergy3[k3-1])*avg_cost
|
|
|
|
+ part3.loc[k3,'方法']=4
|
|
|
|
+ else:
|
|
|
|
+ part3.loc[k3,'△距离']=0
|
|
|
|
+ part3.loc[k3,'方法']=5
|
|
|
|
+ return part3
|
|
|
|
+
|
|
|
|
+def real_odo(df_in,avg_cost):
|
|
|
|
+ # df_handle=df_in.copy()
|
|
|
|
+ df=timeconvert(df_in,"时间戳")#计算相对时间
|
|
|
|
+ df=cal_accumKwh(df)#计算累积能量
|
|
|
|
+ positive_lat_index=df[df['纬度']>0].index
|
|
|
|
+ if len(positive_lat_index)>2:
|
|
|
|
+ first_index=positive_lat_index[0]
|
|
|
|
+ end_index=positive_lat_index[-1]
|
|
|
|
+ #将数据分割为有第一个GPS数据之前(part1)、
|
|
|
|
+ #有最后一个GPS数据之后(part3)以及
|
|
|
|
+ #有第一个GPS数据和最后一个GPS数据中间的数据(part3)
|
|
|
|
+ part1=df[0:first_index+1]
|
|
|
|
+ part2=df[first_index:end_index+1]
|
|
|
|
+ part3=df[end_index:-1]
|
|
|
|
+ part1=cal_distance1(part1,avg_cost)
|
|
|
|
+ part2_gps=cal_distance2(part2,avg_cost)
|
|
|
|
+ part3=cal_distance3(part3,avg_cost)
|
|
|
|
+ df_out=pd.concat([part1,part2_gps[1:],part3[1:]])
|
|
|
|
+ else:
|
|
|
|
+ part1=df
|
|
|
|
+ part2=df[0:0]
|
|
|
|
+ part3=df[0:0]
|
|
|
|
+ part1=cal_distance1(part1,avg_cost)
|
|
|
|
+ df_out=part1.copy()
|
|
|
|
+
|
|
|
|
+ #计算累积里程
|
|
|
|
+ df_out.loc[0,'累积里程[km]']=0
|
|
|
|
+ df_out.index=[i for i in range(len(df_out))]
|
|
|
|
+
|
|
|
|
+ for k in range(1,len(df_out)):
|
|
|
|
+ df_out.loc[k,'累积里程[km]']=df_out.loc[k-1,'累积里程[km]']+df_out.loc[k,'△距离']
|
|
|
|
+ return(df_out)
|
|
|
|
+
|
|
|
|
+def calcul_mileage(sn,data_bms,data_gps):
|
|
|
|
+
|
|
|
|
+ #合并两张表格
|
|
|
|
+ df_bms=data_bms.copy()
|
|
|
|
+ df_gps=data_gps.copy()
|
|
|
|
+ #删除纬度小于10的点
|
|
|
|
+ for k in range(1,len(df_gps)):
|
|
|
|
+ if df_gps.loc[k,'纬度']<10:
|
|
|
|
+ df_gps=df_gps.drop(k)
|
|
|
|
+ df_bms.set_index(["时间戳"], inplace=True)
|
|
|
|
+ df_gps.set_index(["时间戳"], inplace=True)
|
|
|
|
+ merge_df1=pd.merge(df_bms, df_gps,how='outer', left_index=True, right_index=True)
|
|
|
|
+ merge_df1.loc[:,'时间戳']=merge_df1.index
|
|
|
|
+ merge_df1.index=[i for i in range(len(merge_df1))]
|
|
|
|
+
|
|
|
|
+ #参数定义
|
|
|
|
+ cost_min=34 #最小能耗km/kwh
|
|
|
|
+ cost_max=45 #最高能耗km/kwh
|
|
|
|
+
|
|
|
|
+ df_input=merge_df1[['时间戳','总电流[A]', '总电压[V]','SOC[%]','充电状态','纬度', '经度']]
|
|
|
|
+ #电流电压数据修复
|
|
|
|
+ df_input=timeconvert(df_input,"时间戳")#计算相对时间
|
|
|
|
+ related_times=df_input['相对时间[s]'].values
|
|
|
|
+ lat_list=df_input['纬度'].values
|
|
|
|
+ lng_list=df_input['经度'].values
|
|
|
|
+ #Vlt_list=df_input['总电压[V]'].values
|
|
|
|
+ for k in range(1,len(df_input)):
|
|
|
|
+ if math.isnan(df_input.loc[k,'总电流[A]']):
|
|
|
|
+ if related_times[k]-related_times[k-1]<5:
|
|
|
|
+ df_input.loc[k,'总电流[A]']=df_input.loc[k-1,'总电流[A]']
|
|
|
|
+ df_input.loc[k,'总电压[V]']=df_input.loc[k-1,'总电压[V]']
|
|
|
|
+ df_input.loc[k,'修复']=1
|
|
|
|
+ elif lat_list[k-1]>0:
|
|
|
|
+ delta_odo=cal_dis_meters(6378.137,lat_list[k], lng_list[k],lat_list[k-1], lng_list[k-1])
|
|
|
|
+ df_input.loc[k,'总电流[A]']=1000*3600*(delta_odo/cost_min)/70/(related_times[k]-related_times[k-1])
|
|
|
|
+ df_input.loc[k,'总电压[V]']=70
|
|
|
|
+ df_input.loc[k,'修复']=2
|
|
|
|
+ elif related_times[k]-related_times[k-1]<30:
|
|
|
|
+ df_input.loc[k,'总电流[A]']=df_input.loc[k-1,'总电流[A]']
|
|
|
|
+ df_input.loc[k,'总电压[V]']=df_input.loc[k-1,'总电压[V]']
|
|
|
|
+ df_input.loc[k,'修复']=3
|
|
|
|
+ else:
|
|
|
|
+ df_input=df_input.drop(k)
|
|
|
|
+
|
|
|
|
+ df_input.index=[i for i in range(len(df_input))]
|
|
|
|
+ df_input['日期']=[df_input.loc[i,'时间戳'][0:10] for i in range(len(df_input))]
|
|
|
|
+ date_list=np.unique(df_input['日期'].values)
|
|
|
|
+
|
|
|
|
+ #list_result=[]
|
|
|
|
+ input_res=pd.DataFrame()
|
|
|
|
+ res = pd.DataFrame()
|
|
|
|
+ df_input_copy=df_input.copy()
|
|
|
|
+ for date_str in date_list:
|
|
|
|
+ df_input_copy=df_input[df_input['日期']==date_str]
|
|
|
|
+ data_len=len(df_input_copy)
|
|
|
|
+ time_list=df_input_copy['时间戳'].values
|
|
|
|
+ #初始化参数
|
|
|
|
+ start_time=datetime.datetime.strptime(time_list[0], "%Y-%m-%d %H:%M:%S")
|
|
|
|
+ last_time=time_list[0]
|
|
|
|
+ #reset_time=start_time
|
|
|
|
+ start_index=0
|
|
|
|
+ end_index=1
|
|
|
|
+ cal_count=0
|
|
|
|
+ #df_deltaData_last=df_input_copy[0:0]
|
|
|
|
+ #初始化输出
|
|
|
|
+ df_result=pd.DataFrame()
|
|
|
|
+
|
|
|
|
+ df_result.loc[0,'时间']=start_time
|
|
|
|
+ df_result.loc[0,'时间']=str(df_result.loc[0,'时间'])
|
|
|
|
+ df_result.loc[0,'时间'] =df_result.loc[0,'时间'].rpartition(':')[0]
|
|
|
|
+
|
|
|
|
+ df_result.loc[0,'累积里程[km]']=0
|
|
|
|
+ df_result.loc[0,'能耗[km/kwh]']=cost_min
|
|
|
|
+ #process_store=[]
|
|
|
|
+ avg_cost=34
|
|
|
|
+ cross_odo=0
|
|
|
|
+ for k in range(1,data_len):
|
|
|
|
+
|
|
|
|
+ target_Time=start_time+datetime.timedelta(minutes=5)
|
|
|
|
+ timenow=datetime.datetime.strptime(time_list[k], "%Y-%m-%d %H:%M:%S")
|
|
|
|
+ if target_Time>=timenow:
|
|
|
|
+ delta_time=(target_Time-timenow).seconds
|
|
|
|
+ cal_flag=0
|
|
|
|
+ if delta_time<60:
|
|
|
|
+ end_index=k
|
|
|
|
+ cal_flag=1
|
|
|
|
+ else:
|
|
|
|
+ end_index=k
|
|
|
|
+ cal_flag=1
|
|
|
|
+
|
|
|
|
+ if cal_flag==1:
|
|
|
|
+ cal_count=cal_count+1
|
|
|
|
+
|
|
|
|
+ df_deltaData=df_input_copy[max(start_index-100,0):end_index+1]
|
|
|
|
+ avg_cost=max(cost_min,df_result.loc[cal_count-1,'能耗[km/kwh]'])
|
|
|
|
+ #avg_cost=cost_min
|
|
|
|
+ df_span=real_odo(df_deltaData,avg_cost)
|
|
|
|
+ st_str=df_span['时间戳'].values[0]
|
|
|
|
+ st_time=datetime.datetime.strptime(st_str, "%Y-%m-%d %H:%M:%S")
|
|
|
|
+ last_time_s=datetime.datetime.strptime(last_time, "%Y-%m-%d %H:%M:%S")
|
|
|
|
+ if last_time_s>=st_time:
|
|
|
|
+ last_time=last_time
|
|
|
|
+ cross_odo=cross_odo
|
|
|
|
+ else:
|
|
|
|
+ last_time=start_time
|
|
|
|
+ cross_odo=0
|
|
|
|
+ delta_odo=df_span['累积里程[km]'].values[-1]-df_span[df_span['时间戳']==str(last_time)]['累积里程[km]'].values[0]
|
|
|
|
+ delta_energy=df_span['累积能量[Kwh]'].values[-1]-df_span[df_span['时间戳']==str(last_time)]['累积能量[Kwh]'].values[0]
|
|
|
|
+ df_result.loc[cal_count,'时间']=timenow
|
|
|
|
+ df_result.loc[cal_count,'时间']=str(df_result.loc[cal_count,'时间'])
|
|
|
|
+ df_result.loc[cal_count,'时间'] = df_result.loc[cal_count,'时间'].rpartition(':')[0]
|
|
|
|
+
|
|
|
|
+ df_result.loc[cal_count,'累积里程[km]']=df_result.loc[cal_count-1,'累积里程[km]']+delta_odo-cross_odo
|
|
|
|
+ if delta_energy>0:
|
|
|
|
+ df_result.loc[cal_count,'能耗[km/kwh]']=min(max(delta_odo/delta_energy,cost_min),cost_max)
|
|
|
|
+ else:
|
|
|
|
+ df_result.loc[cal_count,'能耗[km/kwh]']=cost_min
|
|
|
|
+
|
|
|
|
+ # df_span[df_span['纬度']>0][-1:]
|
|
|
|
+ if len(df_span[df_span['纬度']>0])>0:
|
|
|
|
+ last_gps=df_span[df_span['纬度']>0][-1:]
|
|
|
|
+ idx=last_gps.index.values[0]
|
|
|
|
+ last_time=df_span.loc[idx,'时间戳']
|
|
|
|
+ cross_odo=df_span['累积里程[km]'].values[-1]-df_span.loc[idx,'累积里程[km]']
|
|
|
|
+ else:
|
|
|
|
+ last_time=df_span['时间戳'].values[-1]
|
|
|
|
+ cross_odo=0
|
|
|
|
+
|
|
|
|
+ start_index=end_index
|
|
|
|
+ start_time=timenow
|
|
|
|
+ cal_flag=0
|
|
|
|
+
|
|
|
|
+ res=res.append(df_result)
|
|
|
|
+ input_res=input_res.append(df_input_copy)
|
|
|
|
+
|
|
|
|
+ l= len(input_res['时间戳'])
|
|
|
|
+ for k in range(l):
|
|
|
|
+ input_res.loc[k,'时间戳'] =input_res.loc[k,'时间戳'].rpartition(':')[0]
|
|
|
|
+
|
|
|
|
+ res.index=[i for i in range(len(res))]
|
|
|
|
+ res['日期']=[res.loc[i,'时间'][0:10] for i in range(len(res))]
|
|
|
|
+
|
|
|
|
+ merge_res=pd.DataFrame()
|
|
|
|
+ for date_str in date_list:
|
|
|
|
+ input_res_copy=input_res[input_res['日期']==date_str]
|
|
|
|
+ input_res_copy=input_res_copy.drop_duplicates('时间戳')
|
|
|
|
+ res_copy=res[res['日期']==date_str]
|
|
|
|
+ df_merge=pd.DataFrame()
|
|
|
|
+ df_merge=pd.merge(input_res_copy,res_copy,left_on='时间戳',right_on='时间',how='right')
|
|
|
|
+ merge_res=merge_res.append(df_merge)
|
|
|
|
+
|
|
|
|
+ merge_res['sn']=sn
|
|
|
|
+ merge_res=merge_res[['时间戳','sn','总电流[A]','总电压[V]','SOC[%]','充电状态','纬度','经度','能耗[km/kwh]','累积里程[km]']]
|
|
|
|
+ merge_res=merge_res.rename(columns={'累积里程[km]':'每日累积里程[km]'})
|
|
|
|
+
|
|
|
|
+ return merge_res
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|