import pandas as pd import numpy as np from datetime import datetime from datetime import timedelta def get_bms_drive_timetable(df_bms,battery_mode): '''对df_bms进行处理,得到行车的时间表。''' #####################step1 先使用电流做充电状态的判断############################################# if battery_mode==0:#mode=0,电流为正代表放电 condition_chrg=df_bms['bmspackcrnt']<0##根据电流,挑选充电状态 df_bms.loc[condition_chrg,'bscsta']='chrg' condition_drive=df_bms['bmspackcrnt']>0.01##根据电流,挑选行驶状态 df_bms.loc[condition_drive,'bscsta']='drive' df_bms.loc[~(condition_drive|condition_chrg),'bscsta']='idle'#静置状态 else :#mode=1,电流为负代表放电 condition_chrg=df_bms['bmspackcrnt']>0##根据电流,挑选充电状态 df_bms.loc[condition_chrg,'bscsta']='chrg' condition_drive=df_bms['bmspackcrnt']<-0.01##根据电流,挑选行驶状态 df_bms.loc[condition_drive,'bscsta']='drive' df_bms.loc[~(condition_drive|condition_chrg),'bscsta']='idle'#静置状态 #####################step2 对drive进行debounce,进入时立即进入,退出时debounce,5分钟。########## index=0 debounce_row=10#debounce判断持续10行 debounce_time=300#debounce判断持续300秒 #对上一步初步状态进行二次处理 while index<(len(df_bms)-debounce_row): mode_0=df_bms.loc[index,'bscsta'] mode_1=df_bms.loc[index+1,'bscsta'] #如果发现了边界行,则进行debounce判断 if (mode_0=='drive')&(mode_1!='drive'):#如果从drive变为idle accum_subtime=0#累计时间初始化 for sub_index in range(debounce_row):#往下处理10行 sub_time=df_bms.loc[index+sub_index,'deltatime'] accum_subtime+=sub_time #如果累计时间不到300秒,则设置为drive if accum_subtime<debounce_time: df_bms.loc[index+sub_index,'bscsta']='drive' index=index+debounce_row#处理10行以后的数据 #如果从idle变为drivemode,则将idle变为drive,包容前一行 elif (mode_0!='drive')&(mode_1=='drive'): df_bms.loc[index,'bscsta']='drive' index=index+1 else: index=index+1 #######################step3 对drivemode的时间进行分段########################################### not_drive_flg=0#初始化 #输出drivemode的时间段,包含开始时间、结束时间 df_bms_drive_timetable_index=0 df_bms_drive_timetable=pd.DataFrame([],columns={'drive_start_time','drive_end_time', 'gps_dist','predict_dist','drive_start_soc','drive_end_soc'}) for index in range(len(df_bms)): temp_bscsta=df_bms.loc[index,'bscsta'] if (temp_bscsta=='drive')&(not_drive_flg==0): drive_start_time=df_bms.loc[index,'time'] not_drive_flg=1 df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_start_time']=drive_start_time #startsoc drive_start_soc=df_bms.loc[index,'bmspacksoc'] df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_start_soc']=drive_start_soc elif (temp_bscsta!='drive')&(not_drive_flg==1): drive_end_time=df_bms.loc[index,'time'] not_drive_flg=0 df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_end_time']=drive_end_time #endsoc drive_end_soc=df_bms.loc[index,'bmspacksoc'] df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_end_soc']=drive_end_soc df_bms_drive_timetable_index+=1#index++ #删除时间信息不齐全的行 df_bms_drive_timetable=df_bms_drive_timetable.dropna(subset=['drive_end_time','drive_start_time']) return df_bms_drive_timetable def read_df_bms(path): '''从路径中读取df_bms,进行预处理''' df_bms=pd.read_csv(path, encoding='gbk')#编码方式gbk #筛选表头,重命名 bms_columns=['时间戳','总电流[A]','总电压[V]','SOC[%]'] df_bms=df_bms.loc[:,bms_columns].copy() df_bms.rename(columns = {"时间戳": "time", "总电流[A]": "bmspackcrnt", "总电压[V]": "bmspackvol", "SOC[%]": "bmspacksoc"},inplace=True)#表头替换 #时间格式调整 df_bms['time']=df_bms['time'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))#时间格式调整 #进行预处理 df_bms=df_add_deltatime(df_bms)#增加deltatime列 return df_bms def preprocess_Df_Bms(df_bms): '''对获得的df_bms,进行预处理''' #筛选表头,重命名 bms_columns=['时间戳','总电流[A]','总电压[V]','SOC[%]'] df_bms=df_bms.loc[:,bms_columns].copy() df_bms.rename(columns = {"时间戳": "time", "总电流[A]": "bmspackcrnt", "总电压[V]": "bmspackvol", "SOC[%]": "bmspacksoc"},inplace=True)#表头替换 #删除空行 df_bms=df_bms.dropna(subset=['time']) #删除时间重复的行,保留第一次出现的行 df_bms=df_bms.drop_duplicates(subset=['time'],keep='first') #时间格式调整 df_bms['time']=df_bms['time'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))#时间格式调整 #进行预处理 df_bms=df_add_deltatime(df_bms)#增加deltatime列 return df_bms def df_add_deltatime(df_in): '''Add a columns:deltatime,input df must have time column.''' for i in range(len(df_in)): #首行默认为0 if i==0: df_in.loc[i,'deltatime']=0 #从第二行开始,计算i行到i-1行,GPS距离之差 else: time1=df_in.loc[i-1,'time'] time2=df_in.loc[i,'time'] deltatime=time_interval(time1,time2)#计算时间差,返回单位为秒。 df_in.loc[i,'deltatime']=deltatime return df_in def time_interval(time1,time2): """ Calculate the time interval between two times, return the seconds """ deltatime=time2-time1 return deltatime.seconds def cal_deltasoc(df_bms,start_time,end_time): '''输入开始时间和结束时间,返回deltasoc,此处将deltasoc*1既等效为unrecorded_odo.''' time_condition=(df_bms['time']>start_time)&(df_bms['time']<end_time) df_bms_sub=df_bms.loc[time_condition,:].copy() if len(df_bms_sub)>=2: df_bms_head=df_bms_sub.head(1).copy()#首行 df_bms_startsoc=df_bms_head['bmspacksoc'].values[0] df_bms_tail=df_bms_sub.tail(1).copy()#尾行 df_bms_endsoc=df_bms_tail['bmspacksoc'].values[0] delta_soc=df_bms_startsoc-df_bms_endsoc if delta_soc>0: #如果df_bms出现时间不连续,则先计算deltasoc,deltasoc每变化1,续驶里程增加1, unrecorded_odo=delta_soc*1 #print('From '+str(start_time)+' to '+str(end_time)+' soc decrease: '+str(delta_soc)) else: unrecorded_odo=0#如果deltasoc不大于0,说明在充电,或者静置不动 #如果行数少于2,无法计算 else: unrecorded_odo=0 return unrecorded_odo