ProcessDfBms.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import pandas as pd
  2. import numpy as np
  3. from datetime import datetime
  4. from datetime import timedelta
  5. def get_bms_drive_timetable(df_bms,battery_mode):
  6. '''对df_bms进行处理,得到行车的时间表。'''
  7. #####################step1 先使用电流做充电状态的判断#############################################
  8. if battery_mode==0:#mode=0,电流为正代表放电
  9. condition_chrg=df_bms['bmspackcrnt']<0##根据电流,挑选充电状态
  10. df_bms.loc[condition_chrg,'bscsta']='chrg'
  11. condition_drive=df_bms['bmspackcrnt']>0.01##根据电流,挑选行驶状态
  12. df_bms.loc[condition_drive,'bscsta']='drive'
  13. df_bms.loc[~(condition_drive|condition_chrg),'bscsta']='idle'#静置状态
  14. else :#mode=1,电流为负代表放电
  15. condition_chrg=df_bms['bmspackcrnt']>0##根据电流,挑选充电状态
  16. df_bms.loc[condition_chrg,'bscsta']='chrg'
  17. condition_drive=df_bms['bmspackcrnt']<-0.01##根据电流,挑选行驶状态
  18. df_bms.loc[condition_drive,'bscsta']='drive'
  19. df_bms.loc[~(condition_drive|condition_chrg),'bscsta']='idle'#静置状态
  20. #####################step2 对drive进行debounce,进入时立即进入,退出时debounce,5分钟。##########
  21. index=0
  22. debounce_row=10#debounce判断持续10行
  23. debounce_time=300#debounce判断持续300秒
  24. #对上一步初步状态进行二次处理
  25. while index<(len(df_bms)-debounce_row):
  26. mode_0=df_bms.loc[index,'bscsta']
  27. mode_1=df_bms.loc[index+1,'bscsta']
  28. #如果发现了边界行,则进行debounce判断
  29. if (mode_0=='drive')&(mode_1!='drive'):#如果从drive变为idle
  30. accum_subtime=0#累计时间初始化
  31. for sub_index in range(debounce_row):#往下处理10行
  32. sub_time=df_bms.loc[index+sub_index,'deltatime']
  33. accum_subtime+=sub_time
  34. #如果累计时间不到300秒,则设置为drive
  35. if accum_subtime<debounce_time:
  36. df_bms.loc[index+sub_index,'bscsta']='drive'
  37. index=index+debounce_row#处理10行以后的数据
  38. #如果从idle变为drivemode,则将idle变为drive,包容前一行
  39. elif (mode_0!='drive')&(mode_1=='drive'):
  40. df_bms.loc[index,'bscsta']='drive'
  41. index=index+1
  42. else:
  43. index=index+1
  44. #######################step3 对drivemode的时间进行分段###########################################
  45. not_drive_flg=0#初始化
  46. #输出drivemode的时间段,包含开始时间、结束时间
  47. df_bms_drive_timetable_index=0
  48. df_bms_drive_timetable=pd.DataFrame([],columns={'drive_start_time','drive_end_time',
  49. 'gps_dist','predict_dist','drive_start_soc','drive_end_soc'})
  50. for index in range(len(df_bms)):
  51. temp_bscsta=df_bms.loc[index,'bscsta']
  52. if (temp_bscsta=='drive')&(not_drive_flg==0):
  53. drive_start_time=df_bms.loc[index,'time']
  54. not_drive_flg=1
  55. df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_start_time']=drive_start_time
  56. #startsoc
  57. drive_start_soc=df_bms.loc[index,'bmspacksoc']
  58. df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_start_soc']=drive_start_soc
  59. elif (temp_bscsta!='drive')&(not_drive_flg==1):
  60. drive_end_time=df_bms.loc[index,'time']
  61. not_drive_flg=0
  62. df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_end_time']=drive_end_time
  63. #endsoc
  64. drive_end_soc=df_bms.loc[index,'bmspacksoc']
  65. df_bms_drive_timetable.loc[df_bms_drive_timetable_index,'drive_end_soc']=drive_end_soc
  66. df_bms_drive_timetable_index+=1#index++
  67. #删除时间信息不齐全的行
  68. df_bms_drive_timetable=df_bms_drive_timetable.dropna(subset=['drive_end_time','drive_start_time'])
  69. return df_bms_drive_timetable
  70. def read_df_bms(path):
  71. '''从路径中读取df_bms,进行预处理'''
  72. df_bms=pd.read_csv(path, encoding='gbk')#编码方式gbk
  73. #筛选表头,重命名
  74. bms_columns=['时间戳','总电流[A]','总电压[V]','SOC[%]']
  75. df_bms=df_bms.loc[:,bms_columns].copy()
  76. df_bms.rename(columns = {"时间戳": "time", "总电流[A]": "bmspackcrnt",
  77. "总电压[V]": "bmspackvol", "SOC[%]": "bmspacksoc"},inplace=True)#表头替换
  78. #时间格式调整
  79. df_bms['time']=df_bms['time'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))#时间格式调整
  80. #进行预处理
  81. df_bms=df_add_deltatime(df_bms)#增加deltatime列
  82. return df_bms
  83. def preprocess_Df_Bms(df_bms):
  84. '''对获得的df_bms,进行预处理'''
  85. #筛选表头,重命名
  86. bms_columns=['时间戳','总电流[A]','总电压[V]','SOC[%]']
  87. df_bms=df_bms.loc[:,bms_columns].copy()
  88. df_bms.rename(columns = {"时间戳": "time", "总电流[A]": "bmspackcrnt",
  89. "总电压[V]": "bmspackvol", "SOC[%]": "bmspacksoc"},inplace=True)#表头替换
  90. #删除空行
  91. df_bms=df_bms.dropna(subset=['time'])
  92. #删除时间重复的行,保留第一次出现的行
  93. df_bms=df_bms.drop_duplicates(subset=['time'],keep='first')
  94. #时间格式调整
  95. df_bms['time']=df_bms['time'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))#时间格式调整
  96. #进行预处理
  97. df_bms=df_add_deltatime(df_bms)#增加deltatime列
  98. return df_bms
  99. def df_add_deltatime(df_in):
  100. '''Add a columns:deltatime,input df must have time column.'''
  101. for i in range(len(df_in)):
  102. #首行默认为0
  103. if i==0:
  104. df_in.loc[i,'deltatime']=0
  105. #从第二行开始,计算i行到i-1行,GPS距离之差
  106. else:
  107. time1=df_in.loc[i-1,'time']
  108. time2=df_in.loc[i,'time']
  109. deltatime=time_interval(time1,time2)#计算时间差,返回单位为秒。
  110. df_in.loc[i,'deltatime']=deltatime
  111. return df_in
  112. def time_interval(time1,time2):
  113. """
  114. Calculate the time interval between two times,
  115. return the seconds
  116. """
  117. deltatime=time2-time1
  118. return deltatime.seconds
  119. def cal_deltasoc(df_bms,start_time,end_time):
  120. '''输入开始时间和结束时间,返回deltasoc,此处将deltasoc*1既等效为unrecorded_odo.'''
  121. time_condition=(df_bms['time']>start_time)&(df_bms['time']<end_time)
  122. df_bms_sub=df_bms.loc[time_condition,:].copy()
  123. if len(df_bms_sub)>=2:
  124. df_bms_head=df_bms_sub.head(1).copy()#首行
  125. df_bms_startsoc=df_bms_head['bmspacksoc'].values[0]
  126. df_bms_tail=df_bms_sub.tail(1).copy()#尾行
  127. df_bms_endsoc=df_bms_tail['bmspacksoc'].values[0]
  128. delta_soc=df_bms_startsoc-df_bms_endsoc
  129. if delta_soc>0:
  130. #如果df_bms出现时间不连续,则先计算deltasoc,deltasoc每变化1,续驶里程增加1,
  131. unrecorded_odo=delta_soc*1
  132. #print('From '+str(start_time)+' to '+str(end_time)+' soc decrease: '+str(delta_soc))
  133. else:
  134. unrecorded_odo=0#如果deltasoc不大于0,说明在充电,或者静置不动
  135. #如果行数少于2,无法计算
  136. else:
  137. unrecorded_odo=0
  138. return unrecorded_odo