function.py 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. ##################################################################
  4. #
  5. # Copyright (c) 2023 CICV, Inc. All Rights Reserved
  6. #
  7. ##################################################################
  8. """
  9. @Authors: zhanghaiwen(zhanghaiwen@china-icv.cn), yangzihao(yangzihao@china-icv.cn)
  10. @Data: 2023/08/03
  11. @Last Modified: 2023/08/03
  12. @Summary: Function metrics
  13. """
  14. import sys
  15. sys.path.append('../common')
  16. sys.path.append('../modules')
  17. sys.path.append('../results')
  18. import math
  19. import numpy as np
  20. import pandas as pd
  21. import scipy.signal as sg
  22. from score_weight import cal_score_with_priority, cal_weight_from_80
  23. from common import score_grade, string_concatenate, replace_key_with_value, score_over_100
  24. class Function(object):
  25. """
  26. Class for achieving function metrics for autonomous driving.
  27. Attributes:
  28. df: Vehicle driving data, stored in dataframe format.
  29. """
  30. def __init__(self, data_processed, custom_data, scoreModel):
  31. self.eval_data = pd.DataFrame()
  32. self.data_processed = data_processed
  33. self.scoreModel = scoreModel
  34. self.df = data_processed.object_df
  35. self.ego_df = data_processed.ego_data
  36. self.obj_id_list = data_processed.obj_id_list
  37. self.df_roadmark = data_processed.road_mark_df
  38. self.df_roadpos = data_processed.road_pos_df
  39. self.df_drivectrl = data_processed.driver_ctrl_df
  40. self.unfunc_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  41. self.unfunc_follow_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  42. self.unfunc_lane_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  43. self.unfunc_custom_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  44. self.custom_markline_list = []
  45. # config infos for calculating score
  46. self.config = data_processed.config
  47. function_config = self.config.config['function']
  48. self.function_config = function_config
  49. # common data
  50. self.bulitin_metric_list = self.config.builtinMetricList
  51. # dimension data
  52. self.weight_custom = function_config['weightCustom']
  53. self.metric_list = function_config['metric']
  54. self.type_list = function_config['type']
  55. self.type_name_dict = function_config['typeName']
  56. self.name_dict = function_config['name']
  57. self.unit_dict = function_config['unit']
  58. # custom metric data
  59. self.customMetricParam = function_config['customMetricParam']
  60. self.custom_metric_list = list(self.customMetricParam.keys())
  61. self.custom_data = custom_data
  62. self.custom_param_dict = {}
  63. # score data
  64. self.weight = function_config['weightDimension']
  65. self.weight_type_dict = function_config['typeWeight']
  66. self.weight_type_list = function_config['typeWeightList']
  67. self.weight_dict = function_config['weight']
  68. self.weight_list = function_config['weightList']
  69. self.priority_dict = function_config['priority']
  70. self.priority_list = function_config['priorityList']
  71. self.kind_dict = function_config['kind']
  72. self.optimal_dict = function_config['optimal']
  73. self.multiple_dict = function_config['multiple']
  74. self.kind_list = function_config['kindList']
  75. self.optimal_list = function_config['optimalList']
  76. self.multiple_list = function_config['multipleList']
  77. # self.unit_dict = function_config['unit']
  78. self.metric_dict = function_config['typeMetricDict']
  79. if "functionACC" in self.metric_dict.keys():
  80. self.acc_metric_list = self.metric_dict['functionACC']
  81. if "functionLKA" in self.metric_dict.keys():
  82. self.lka_metric_list = self.metric_dict['functionLKA']
  83. # self.acc_metric_list = ['followSpeedDeviation', 'followDistanceDeviation', 'followStopDistance',
  84. # 'followResponseTime']
  85. # self.lka_metric_list = ['laneDistance', 'centerDistanceExpectation', 'centerDistanceStandardDeviation',
  86. # 'centerDistanceMax', 'centerDistanceMin', 'centerDistanceFrequency',
  87. # 'centerDistanceRange']
  88. # custom metric
  89. self.flag_type_dict = {}
  90. # lists of drving control info
  91. self.time_list = data_processed.driver_ctrl_data['time_list']
  92. self.frame_list = data_processed.driver_ctrl_data['frame_list']
  93. self.time_list_follow = []
  94. self.frame_list_follow = []
  95. self.dist_list = []
  96. self.v_deviation_list = []
  97. self.v_relative_list = []
  98. self.dist_deviation_list = []
  99. self.stop_distance_list = []
  100. self.follow_stop_time_start_list = [] # 起停跟车响应时长
  101. self.dist_list_full_time = list()
  102. self.dist_deviation_list_full_time = list()
  103. self.line_dist = []
  104. self.center_dist = []
  105. self.center_dist_with_nan = []
  106. self.center_time_list = []
  107. self.center_frame_list = []
  108. self.ICA_FLAG = False
  109. self.follow_stop_count = 0
  110. self.result = {}
  111. def _following(self, df):
  112. """
  113. 稳定跟车行驶:
  114. 1.稳态控制速度偏差:筛选出跟车行驶数据后,
  115. 2.稳态控制距离偏差
  116. ACC stastus
  117. 0x7: Stand-wait State
  118. 0x6: Stand-active State
  119. 0x5: Passive State
  120. 0x4: Standby State
  121. 0x3: Shut-off State
  122. 0x2: Override State
  123. 0x1: Active State
  124. 0x0: Off
  125. # 速度变化不能以0到非0为参考,要改为从0到0.05的变化,有一个阈值滤波,避免前车车辆抖动误差影响传感器
  126. 弯道行驶: 最小跟随弯道半径
  127. """
  128. # df = self.df[self.df['ACC_status'] == "Active"].copy() # 跟车状态下
  129. # df = self.df[self.df['ACC_status'] == 1].copy() # 跟车状态下
  130. col_list = ['simTime', 'simFrame', 'playerId', 'v', 'posX', 'posY'] # target_id
  131. df = df[col_list].copy()
  132. ego_df = df[df['playerId'] == 1][['simTime', 'simFrame', 'v', 'posX', 'posY']]
  133. # 筛选目标车(同一车道内,距离最近的前车)
  134. # obj_df = df[df['playerId'] == df['target_id']]
  135. target_id = 2
  136. obj_df = df[df['playerId'] == target_id][['simTime', 'simFrame', 'v', 'posX', 'posY']] # 目标车
  137. obj_df = obj_df.rename(columns={'v': 'v_obj', 'posX': 'posX_obj', 'posY': 'posY_obj'})
  138. df_merge = pd.merge(ego_df, obj_df, on=['simTime', 'simFrame'], how='left')
  139. df_merge['v_relative'] = df_merge['v'] - df_merge['v_obj']
  140. df_merge['dist'] = df_merge.apply(
  141. lambda row: self.dist(row['posX'], row['posY'], row['posX_obj'], row['posY_obj']), axis=1)
  142. self.dist_list = df_merge['dist'].values.tolist()
  143. df_merge['time_gap'] = df_merge['dist'] / df_merge['v']
  144. SAFE_TIME_GAP = 3
  145. df_merge['dist_deviation'] = df_merge['time_gap'].apply(
  146. lambda x: 0 if (x >= SAFE_TIME_GAP) else (SAFE_TIME_GAP - x))
  147. df_stop = df_merge[(df_merge['v'] == 0) & (df_merge['v_obj'] == 0)]
  148. stop_distance_list = df_stop['dist'].values.tolist()
  149. self.stop_distance_list = stop_distance_list
  150. t_list = df_stop['simTime'].values.tolist()
  151. stop_group = []
  152. sub_group = []
  153. CONTINUOUS_TIME_PERIOD = 1
  154. CONTINUOUS_FRAME_PERIOD = 13
  155. for i in range(len(t_list)):
  156. if not sub_group or t_list[i] - t_list[i - 1] <= CONTINUOUS_TIME_PERIOD:
  157. sub_group.append(t_list[i])
  158. else:
  159. stop_group.append(sub_group)
  160. sub_group = [t_list[i]]
  161. stop_group.append(sub_group)
  162. stop_group = [g for g in stop_group if len(g) >= CONTINUOUS_FRAME_PERIOD]
  163. self.follow_stop_count = len(stop_group)
  164. # solution 1: 跟车状态下,算法输出预设跟车速度
  165. # df['velocity_deviation'] = abs(df['v'] - df['set_velocity'])
  166. # max_velocity_deviation = df['velocity_deviation'].max()
  167. # solution 2: 跟车状态下,跟车设定速度为目标车速度
  168. # velocity_deviation = []
  169. # distance_deviation = []
  170. # stop_distance = []
  171. #
  172. # for f, data in df.groupby('simFrame'):
  173. # ego_data = data.iloc[0].copy()
  174. # # df.loc[len(df)] = ego_data
  175. #
  176. # if len(data) < 2:
  177. # continue
  178. # v1 = ego_data['v']
  179. # x1 = ego_data['posX']
  180. # y1 = ego_data['posY']
  181. #
  182. # for i in range(1, len(data)):
  183. # obj_data = data.iloc[i].copy()
  184. #
  185. # v2 = obj_data['v']
  186. # x2 = obj_data['posX']
  187. # y2 = obj_data['posY']
  188. #
  189. # v_delta = abs(v1 - v2)
  190. # velocity_deviation.append(v_delta)
  191. #
  192. # dist = self.dist(x1, y1, x2, y2)
  193. # distance_deviation.append(dist)
  194. #
  195. # if v2 == 0 and v1 == 0:
  196. # stop_distance.append(dist)
  197. # df.loc[len(df)] = obj_data
  198. # self.df = df
  199. df_merge.replace([np.inf, -np.inf], np.nan, inplace=True) # 异常值处理
  200. self.time_list_follow = df_merge['simTime'].values.tolist()
  201. self.frame_list_follow = df_merge['simFrame'].values.tolist()
  202. self.v_relative_list = df_merge['v_relative'].values.tolist()
  203. self.v_deviation_list = abs(df_merge['v_relative']).values.tolist()
  204. self.dist_deviation_list = df_merge['dist_deviation'].values.tolist()
  205. tmp_df = self.ego_df[['simTime', 'simFrame']].copy()
  206. v_rel_df = df_merge[['simTime', 'v_relative']].copy()
  207. df_merged1 = pd.merge(tmp_df, v_rel_df, on='simTime', how='left')
  208. self.v_relative_list_full_time = df_merged1['v_relative'].values.tolist()
  209. dist_deviation_df = df_merge[['simTime', 'dist_deviation']].copy()
  210. df_merged1 = pd.merge(tmp_df, dist_deviation_df, on='simTime', how='left')
  211. self.dist_deviation_list_full_time = df_merged1['dist_deviation'].values.tolist()
  212. dist_df = df_merge[['simTime', 'dist']].copy()
  213. df_merged1 = pd.merge(tmp_df, dist_df, on='simTime', how='left')
  214. self.dist_list_full_time = df_merged1['dist'].values.tolist()
  215. max_velocity_deviation = abs(df_merge['v_relative']).max()
  216. distance_deviation = df_merge['dist_deviation'].max()
  217. min_stop_distance = min(self.stop_distance_list) if self.stop_distance_list else 9999
  218. self.result['followSpeedDeviation'] = max_velocity_deviation
  219. self.result['followDistanceDeviation'] = distance_deviation
  220. self.result['followStopDistance'] = min_stop_distance
  221. def _stop_and_go(self, df):
  222. """
  223. 停走功能:
  224. 1.跟停距离3-4m,
  225. 2.启动跟车响应时间<=1.2s
  226. 3.停车跟车响应时间<=1.2s
  227. decisionType_target
  228. 0 无障碍物巡航
  229. 1 停车减速让行
  230. 2 跟车
  231. 3 绕行
  232. 4 到达终点?
  233. """
  234. # df = self.df[self.df['ACC_status'].isin(["Active", "Stand-active", "Stand-wait"])].copy() # 跟车状态下
  235. # df = self.df[self.df['ACC_status'] == 1].copy() # 跟车状态下
  236. STOP_SPEED_THRESHOLD = 0.05
  237. df['v'] = df['v'].apply(lambda x: 0 if x <= STOP_SPEED_THRESHOLD else 1) # 区分速度为0或非0
  238. target_id = 2
  239. df_ego = df[df['playerId'] == 1].copy()
  240. df_obj = df[df['playerId'] == target_id].copy() # 目标车
  241. df_obj_time = df_obj['simTime'].values.tolist()
  242. df_ego = df_ego[df_ego['simTime'].isin(df_obj_time)].copy()
  243. df_ego = df_ego.drop_duplicates(["simTime", "simFrame"])
  244. df_obj = df_obj.drop_duplicates(["simTime", "simFrame"])
  245. df_ego['v_diff'] = df_ego['v'].diff()
  246. df_ego['v_start_flag'] = df_ego['v_diff'].apply(lambda x: 1 if x == 1 else 0) # 起步即为1
  247. df_ego['v_stop_flag'] = df_ego['v_diff'].apply(lambda x: 1 if x == -1 else 0) # 停车即为-1
  248. df_obj['v_diff'] = df_obj['v'].diff()
  249. obj_v_start_flag = df_obj['v_diff'].apply(lambda x: 1 if x == 1 else 0).values # 起步即为1
  250. obj_v_stop_flag = df_obj['v_diff'].apply(lambda x: 1 if x == -1 else 0).values # 停车即为1
  251. df_ego['obj_v_start_flag'] = obj_v_start_flag
  252. df_ego['obj_v_stop_flag'] = obj_v_stop_flag
  253. df_ego['flag_start'] = df_ego['obj_v_start_flag'] - df_ego['v_start_flag'] # 目标车起步即为1,自车起步即为-1
  254. df_ego['flag_stop'] = df_ego['obj_v_stop_flag'] - df_ego['v_stop_flag'] # 目标车停车即为1,自车停车即为-1
  255. flag_start_list = df_ego['flag_start'].values
  256. flag_stop_list = df_ego['flag_stop'].values
  257. time_list = df_ego['simTime'].values
  258. time_start_list = []
  259. time_stop_list = []
  260. for i, flag in enumerate(flag_start_list):
  261. if flag:
  262. t1 = time_list[i]
  263. if flag == -1:
  264. t2 = time_list[i]
  265. time_start_list.append(t2 - t1) # t2-t1即为自车起步响应时间
  266. for i, flag in enumerate(flag_stop_list):
  267. if flag:
  268. t1 = time_list[i]
  269. if flag == -1:
  270. t2 = time_list[i]
  271. time_stop_list.append(t2 - t1) # t2-t1即为自车停车响应时间
  272. time_start_list = [i for i in time_start_list if i != 0]
  273. self.result['followResponseTime'] = max(time_start_list) if time_start_list else 0
  274. self.follow_stop_time_start_list = time_start_list
  275. # self.result['跟车停止响应最长时间'] = max(time_stop_list)
  276. def dist(self, x1, y1, x2, y2):
  277. dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
  278. return dis
  279. def _line_dist_merge(self):
  280. # line_dist_df = self.df_roadmark[self.df_roadmark['id'] == 0 & self.df_roadmark['id'] == 2].copy()
  281. # line_dist_group = line_dist_df.groupby("simFrame").apply(lambda t: abs(t['lateralDist']).min()).values.tolist()
  282. # line_dist_df['line_dist'] = line_dist_group
  283. # line_dist_df = line_dist_df[['simFrame', 'line_dist']]
  284. # line_dist_df.columns = ['simFrame', 'line_dist']
  285. # line_dist_df = line_dist_df.drop_duplicates()
  286. line_dist_df = self.df_roadmark[(self.df_roadmark['id'] == 0) | (self.df_roadmark['id'] == 2)].copy()
  287. # df = line_dist_df[line_dist_df['id'] == 2][['simTime', 'simFrame']].copy()
  288. # df['line_dist'] = line_dist_df.groupby('simFrame').apply(lambda t: abs(t['lateralDist']).min()).values.tolist()
  289. if line_dist_df.empty:
  290. self.ego_df['line_dist'] = pd.Series(dtype=float)
  291. else:
  292. df = line_dist_df.groupby('simFrame').apply(lambda t: abs(t['lateralDist']).min()).reset_index()
  293. # df = df.rename(columns={'lateralDist': 'line_dist'})
  294. df.columns = ["simFrame", "line_dist"]
  295. self.ego_df = pd.merge(self.ego_df, df, on='simFrame', how='left')
  296. def _lane_transverse_distance(self, df):
  297. """
  298. 0x7:Reserved
  299. 0x6: Reserved
  300. 0x5: Reserved
  301. 0x4: Error
  302. 0x3: Active
  303. 0x2: Standby
  304. 0x1: Passive
  305. 0x0: Off
  306. """
  307. # 车道内偏移行驶时,与近侧车道线的横向距离
  308. # data_group = lane_df.groupby("simFrame").apply(lambda t: abs(t['lateralDist']).min())
  309. # data_group = self.df_roadmark.groupby("simFrame").apply(lambda t: abs(t['lateralDist']).min())
  310. # df = data_group.to_frame(name='line_dist')
  311. # df['simFrame'] = data_group.index.tolist()
  312. # df = self.df_roadmark[self.df_roadmark['id'] == 0][['simTime', 'simFrame']].copy()
  313. # df['line_dist'] = self.df_roadmark.groupby('simFrame').apply(
  314. # lambda t: abs(t['lateralDist']).min()).values.tolist()
  315. # self.ego_df = pd.merge(self.ego_df, df, on=['simTime', 'simFrame'], how='left')
  316. # self._line_dist_merge()
  317. # # df = self.df[self.df['LKA_status'] == 3]
  318. # df = self.ego_df[self.ego_df['LKA_status'] == "Active"]
  319. self.line_dist = df['line_dist'].to_list()
  320. self.line_dist = [x for x in self.line_dist if not np.isnan(x)]
  321. self.result['laneDistance'] = min(self.line_dist) if self.line_dist else self.optimal_dict['laneDistance']
  322. def _lateral_dist_of_center_line(self, df_laneoffset):
  323. # df_laneoffset = self.df[(self.df['LKA_status'] == "Active") & (self.df['playerId'] == 1)]
  324. self.center_dist_with_nan = df_laneoffset['laneOffset'].to_list()
  325. self.center_time_list = df_laneoffset['simTime'].to_list()
  326. self.center_frame_list = df_laneoffset['simFrame'].to_list()
  327. # self.center_dist_df = self.df_roadpos[self.df_roadpos["playerId"] == 1]
  328. # self.center_dist = self.center_dist_df["laneOffset"]
  329. # self.center_time_list = self.center_dist_df['simTime'].to_list()
  330. # self.center_frame_list = self.center_dist_df['simFrame'].to_list()
  331. self.center_dist = [x for x in self.center_dist_with_nan if not np.isnan(x)]
  332. if not self.center_dist:
  333. self.result['centerDistanceExpectation'] = 0
  334. self.result['centerDistanceStandardDeviation'] = 0
  335. # self.result['centerDistanceMax'] = abs(extreme_max_value).max()
  336. # self.result['centerDistanceMin'] = abs(extreme_min_value).min()
  337. self.result['centerDistanceMax'] = 0
  338. self.result['centerDistanceMin'] = 0
  339. self.result['centerDistanceFrequency'] = 0
  340. self.result['centerDistanceRange'] = 0
  341. else:
  342. center_dist = [abs(x) for x in self.center_dist]
  343. # 车道中心线横向距离分布期望与标准差
  344. E_lane_center_dist = np.mean(center_dist)
  345. D_lane_center_dist = np.std(center_dist)
  346. # 车道中心线横向距离分布极值
  347. center_dist = np.array(center_dist)
  348. extrmax_index = sg.argrelmax(center_dist)[0]
  349. extrmin_index = sg.argrelmin(center_dist)[0]
  350. extreme_max_value = center_dist[extrmax_index]
  351. extreme_min_value = center_dist[extrmin_index]
  352. # 横向相对位置震荡频率
  353. # 极值即函数局部的最大值或最小值,周期表示两个极大值之间的时间长度或者两个极小值之间的时间长度
  354. length1 = len(extrmax_index) # 极大值列表长度
  355. length2 = len(extrmin_index) # 极小值列表长度
  356. # 极值下标之间的时间间隔列表乘以每两个下标之间的时间间隔
  357. FREQUENCY = 100
  358. time_diff = 1.0 / FREQUENCY
  359. period1 = time_diff * (extrmax_index[1:length1] - extrmax_index[0:length1 - 1])
  360. period2 = time_diff * (extrmin_index[1:length2] - extrmin_index[0:length2 - 1])
  361. try:
  362. period = (sum(period1) + sum(period2)) / (length1 + length2) # 所有时间间隔(即周期)的均值作为最后的周期
  363. except ZeroDivisionError:
  364. period = 0
  365. frequency = 1 / period if period else 0
  366. # length = min(len(extreme_max_value), len(extreme_min_value))
  367. # period = np.mean(extrmax_index[0:length] - extrmin_index[0:length])
  368. # frequency = 1 / period
  369. # 横向相对位置震荡极差
  370. length = min(len(extreme_max_value), len(extreme_min_value))
  371. extr_diff = extreme_max_value[0:length] - extreme_min_value[0:length]
  372. self.result['centerDistanceExpectation'] = E_lane_center_dist
  373. self.result['centerDistanceStandardDeviation'] = D_lane_center_dist
  374. # self.result['centerDistanceMax'] = abs(extreme_max_value).max()
  375. # self.result['centerDistanceMin'] = abs(extreme_min_value).min()
  376. self.result['centerDistanceMax'] = center_dist.max()
  377. self.result['centerDistanceMin'] = center_dist.min()
  378. self.result['centerDistanceFrequency'] = abs(frequency)
  379. self.result['centerDistanceRange'] = abs(extr_diff).max() if list(extr_diff) else 0
  380. def _continous_judge(self, frame_list):
  381. CONTINUOUS_FRAME_PERIOD = 3
  382. if not frame_list:
  383. return 0
  384. cnt = 1
  385. for i in range(1, len(frame_list)):
  386. if frame_list[i] - frame_list[i - 1] <= CONTINUOUS_FRAME_PERIOD:
  387. continue
  388. cnt += 1
  389. return cnt
  390. def _lane_departure_warning(self, ldw_df):
  391. """
  392. 工作车速范围:55/60-200/250 km/h
  393. 最小可用车道宽度:2.6m
  394. 误报警:距离安全,但是预警
  395. 漏报警:距离危险,但是没报警
  396. 灵敏度差:线外40cm
  397. 灵敏度零级:压线
  398. 灵敏度一级:线内20cm(20%)
  399. 灵敏度二级:线内40cm(40%)
  400. 灵敏度三级:线内60cm(60%)
  401. 偏离车速1.0m/s:线内60cm报警
  402. 偏离车速0.5m/s:线内40cm报警
  403. """
  404. # 自车, 车道线宽度>2.6m,转向灯没开
  405. # ego_df = self.df[self.df['playerId'] == 1].copy()
  406. # ego_df['line_dist'] = self.line_dist
  407. # lane_dist_df = self.df_roadmark[self.df_roadmark['id'] == 0 & self.df_roadmark['id'] == 2].copy()
  408. # lane_dist_group = lane_dist_df.groupby("simFrame").apply(
  409. # lambda t: abs(t['lateralDist']).min()).values.tolist()
  410. # lane_dist_df['line_dist'] = lane_dist_group
  411. # lane_dist_df = lane_dist_df[['simFrame', 'line_dist']]
  412. # lane_dist_df.columns = ['simFrame', 'line_dist']
  413. # # lane_dist_df = lane_dist_df[['simTime', 'simFrame', 'line_dist']]
  414. # # lane_dist_df.columns = ['simTime', 'simFrame', 'line_dist']
  415. # lane_dist_df = lane_dist_df.drop_duplicates()
  416. # ldw_status_df = self.df[self.df['playerId'] == 1].copy()[['simTime', 'simFrame', 'LDW_status']].drop_duplicates()
  417. # ldw_status_df = self.ego_df[['simTime', 'simFrame', 'LDW_status', 'line_dist']].copy().drop_duplicates()
  418. # ldw_df = pd.merge_asof(ldw_status_df, lane_dist_df, on='simFrame', direction='nearest')
  419. # ldw_df = self.ego_df[['simTime', 'simFrame', 'LDW_status', 'line_dist']].copy()
  420. # calculate max DLC
  421. warning_dist_max = ldw_df[ldw_df['LDW_status'] == "Active"]['line_dist'].max()
  422. # warning_dist_max = ldw_df[ldw_df['LDW_status'] == 3]['line_dist'].max()
  423. self.result['预警时距离车道线最大距离'] = warning_dist_max
  424. # count miss warning
  425. miss_warning_df = ldw_df[(ldw_df['line_dist'] <= 0.4) & (ldw_df['LDW_status'] != "Active")]
  426. miss_warning_frame_list = miss_warning_df['simFrame'].values.tolist()
  427. miss_warning_count = self._continous_judge(miss_warning_frame_list)
  428. self.result['车道偏离漏预警次数'] = miss_warning_count
  429. # count false warning
  430. false_warning_df = ldw_df[(ldw_df['line_dist'] >= 0.4) & (ldw_df['LDW_status'] == "Active")]
  431. false_warning_frame_list = false_warning_df['simFrame'].values.tolist()
  432. false_warning_count = self._continous_judge(false_warning_frame_list)
  433. self.result['车道偏离误预警次数'] = false_warning_count
  434. def _autonomous_emergency_brake(self):
  435. """
  436. 刹得准、刹得稳
  437. 碰撞预警 + 紧急制动
  438. <=4s 预警>1s,制动<3s
  439. 触发目标类型
  440. 目标类型准确度
  441. 目标为车辆的速度降:
  442. 弱势目标的速度降:
  443. 触发时TTC<4s
  444. 一级制动减速度:4m/s^2
  445. 二级制动减速度:10m/s^2
  446. 刹停行驶距离:10-20m
  447. 刹停时前车距离:0.8-1.5m
  448. 误触发次数:频率 n/10万km
  449. 漏触发:
  450. 能绕开就没必要刹停:开始刹车时距离远近
  451. Returns:
  452. """
  453. # ego_df = self.df[self.df['playerId'] == 1]
  454. df = self.ego_df[self.ego_df['Aeb_status'] == 'Active']
  455. # df = self.ego_df[self.ego_df['Aeb_status'] == 0]
  456. # calculate brakeDecelerate
  457. df['lon_accel'] = df['accelX'] * np.cos(df['posH']) + df['accelY'] * np.sin(df['posH'])
  458. decelerate_max = df['lon_accel'].min()
  459. # calculate brake stop travelDist
  460. df_dist = df[df['lon_accel'] < 0]
  461. frame_list = df_dist['simFrame'].to_list()
  462. travelDist_list = df_dist['travelDist'].to_list()
  463. travelDist_group = []
  464. start = 0
  465. for i in range(1, len(frame_list)):
  466. if frame_list[i] - frame_list[i - 1] > 5:
  467. end = i - 1
  468. # travelDist_group.append(travelDist_list[start:end])
  469. travelDist_group.append(travelDist_list[end] - travelDist_list[start])
  470. start = i
  471. end = -1
  472. travelDist_group.append(travelDist_list[end] - travelDist_list[start])
  473. brake_distance_max = max(travelDist_group) if travelDist_group else np.inf
  474. self.result['brakeDecelerate'] = abs(round(decelerate_max, 4))
  475. self.result['brakeDistance'] = round(brake_distance_max, 4)
  476. def _integrated_cruise_assist(self, df):
  477. df_LCC = df[df['ICA_status'].isin(['LLC_follow_vehicle', 'LLC_follow_line'])].copy()
  478. self.LCC_line_dist = df_LCC['line_dist'].to_list()
  479. self.result['LCClaneDistance'] = min(self.LCC_line_dist) if self.LCC_line_dist else self.optimal_dict[
  480. 'LCClaneDistance']
  481. self.LCC_center_dist = df_LCC['laneOffset'].to_list()
  482. self.LCC_center_time_list = df_LCC['simTime'].to_list()
  483. self.LCC_center_frame_list = df_LCC['simFrame'].to_list()
  484. if not self.LCC_center_dist:
  485. self.result['LCCcenterDistanceExpectation'] = 0
  486. self.result['LCCcenterDistanceStandardDeviation'] = 0
  487. # self.result['centerDistanceMax'] = abs(extreme_max_value).max()
  488. # self.result['centerDistanceMin'] = abs(extreme_min_value).min()
  489. self.result['LCCcenterDistanceMax'] = 0
  490. self.result['LCCcenterDistanceMin'] = 0
  491. self.result['LCCcenterDistanceFrequency'] = 0
  492. self.result['LCCcenterDistanceRange'] = 0
  493. else:
  494. center_dist = [abs(x) for x in self.LCC_center_dist]
  495. # 车道中心线横向距离分布期望与标准差
  496. E_lane_center_dist = np.mean(center_dist)
  497. D_lane_center_dist = np.std(center_dist)
  498. # 车道中心线横向距离分布极值
  499. center_dist = np.array(center_dist)
  500. extrmax_index = sg.argrelmax(center_dist)[0]
  501. extrmin_index = sg.argrelmin(center_dist)[0]
  502. extreme_max_value = center_dist[extrmax_index]
  503. extreme_min_value = center_dist[extrmin_index]
  504. # 横向相对位置震荡频率
  505. # 极值即函数局部的最大值或最小值,周期表示两个极大值之间的时间长度或者两个极小值之间的时间长度
  506. length1 = len(extrmax_index) # 极大值列表长度
  507. length2 = len(extrmin_index) # 极小值列表长度
  508. # 极值下标之间的时间间隔列表乘以每两个下标之间的时间间隔
  509. FREQUENCY = 100
  510. time_diff = 1.0 / FREQUENCY
  511. period1 = time_diff * (extrmax_index[1:length1] - extrmax_index[0:length1 - 1])
  512. period2 = time_diff * (extrmin_index[1:length2] - extrmin_index[0:length2 - 1])
  513. try:
  514. period = (sum(period1) + sum(period2)) / (length1 + length2) # 所有时间间隔(即周期)的均值作为最后的周期
  515. except ZeroDivisionError:
  516. period = 0
  517. frequency = 1 / period if period else 0
  518. # length = min(len(extreme_max_value), len(extreme_min_value))
  519. # period = np.mean(extrmax_index[0:length] - extrmin_index[0:length])
  520. # frequency = 1 / period
  521. # 横向相对位置震荡极差
  522. length = min(len(extreme_max_value), len(extreme_min_value))
  523. extr_diff = extreme_max_value[0:length] - extreme_min_value[0:length]
  524. self.result['LCCcenterDistanceExpectation'] = E_lane_center_dist
  525. self.result['LCCcenterDistanceStandardDeviation'] = D_lane_center_dist
  526. # self.result['centerDistanceMax'] = abs(extreme_max_value).max()
  527. # self.result['centerDistanceMin'] = abs(extreme_min_value).min()
  528. self.result['LCCcenterDistanceMax'] = center_dist.max()
  529. self.result['LCCcenterDistanceMin'] = center_dist.min()
  530. self.result['LCCcenterDistanceFrequency'] = abs(frequency)
  531. self.result['LCCcenterDistanceRange'] = abs(extr_diff).max() if list(extr_diff) else 0
  532. df_LC = df[df['ICA_status'] == 'Only_Longitudinal_Control'].copy()
  533. v_max = df_LC['v'].max()
  534. v_min = df_LC['v'].min()
  535. self.result['OLC_v_deviation'] = v_max - v_min
  536. def _function_statistic(self):
  537. """
  538. """
  539. ACC_optimal_list = []
  540. if "functionACC" in self.type_list:
  541. if len(self.obj_id_list) > 1:
  542. df_follow = self.df[self.df['ACC_status'] == "Active"].copy() # 跟车状态下
  543. self._following(df_follow)
  544. df_stop_and_go = self.df[
  545. self.df['ACC_status'].isin(["Active", "Stand-active", "Stand-wait"])].copy() # 跟车状态下
  546. self._stop_and_go(df_stop_and_go)
  547. if df_follow.empty and df_stop_and_go.empty:
  548. self.flag_type_dict['functionACC'] = False
  549. else:
  550. ACC_optimal_list = [value for key, value in self.optimal_dict.items() if key in self.acc_metric_list]
  551. if "functionLKA" in self.type_list:
  552. self._line_dist_merge()
  553. # df_line_dist = self.df[self.df['LKA_status'] == 3]
  554. df_lka = self.ego_df[self.ego_df['LKA_status'] == "Active"]
  555. self._lane_transverse_distance(df_lka)
  556. self._lateral_dist_of_center_line(df_lka)
  557. if df_lka.empty:
  558. self.flag_type_dict['functionLKA'] = False
  559. # if "functionLDW" in self.type_list:
  560. # df_ldw = self.ego_df[['simTime', 'simFrame', 'LDW_status', 'line_dist']].copy()
  561. # self._lane_departure_warning(df_ldw)
  562. # if "functionAEB" in self.type_list:
  563. # self._autonomous_emergency_brake()
  564. # if self.df['ICA_status'].nunique() != 1:
  565. # self.ICA_FLAG = True
  566. # # if "functionICA" in self.type_list:
  567. # # self._integrated_cruise_assist(self.ego_df)
  568. # # ACC
  569. # if len(self.obj_id_list) > 1:
  570. # df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy() # 数字3,对应Active
  571. # self._following(df_follow)
  572. #
  573. # df_stop_and_go = self.df[
  574. # self.df['ACC_status'].isin(["Shut_off", "Stand-active", "Stand-wait"])].copy() # 跟车状态下
  575. # self._stop_and_go(df_stop_and_go)
  576. #
  577. # else:
  578. # ACC_optimal_list = [value for key, value in self.optimal_dict.items() if key in self.acc_metric_list]
  579. #
  580. # # LKA
  581. # self._line_dist_merge()
  582. # # df_line_dist = self.df[self.df['LKA_status'] == 3]
  583. # df_lka = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"]
  584. # self._lane_transverse_distance(df_lka)
  585. # self._lateral_dist_of_center_line(df_lka)
  586. arr_func = [value for key, value in self.result.items() if key in self.metric_list]
  587. # arr_func = list(self.result.values())
  588. if "functionACC" in self.type_list and len(self.obj_id_list) == 1:
  589. arr_func = ACC_optimal_list + arr_func
  590. return arr_func
  591. def custom_metric_param_parser(self, param_list):
  592. """
  593. param_dict = {
  594. "paramA" [
  595. {
  596. "kind": "-1",
  597. "optimal": "1",
  598. "multiple": ["0.5","5"],
  599. "spare1": null,
  600. "spare2": null
  601. }
  602. ]
  603. }
  604. """
  605. kind_list = []
  606. optimal_list = []
  607. multiple_list = []
  608. spare_list = []
  609. # spare1_list = []
  610. # spare2_list = []
  611. for i in range(len(param_list)):
  612. kind_list.append(int(param_list[i]['kind']))
  613. optimal_list.append(float(param_list[i]['optimal']))
  614. multiple_list.append([float(x) for x in param_list[i]['multiple']])
  615. spare_list.append([item["param"] for item in param_list[i]["spare"]])
  616. # spare1_list.append(param_list[i]['spare1'])
  617. # spare2_list.append(param_list[i]['spare2'])
  618. result = {
  619. "kind": kind_list,
  620. "optimal": optimal_list,
  621. "multiple": multiple_list,
  622. "spare": spare_list,
  623. # "spare1": spare1_list,
  624. # "spare2": spare2_list
  625. }
  626. return result
  627. def custom_metric_score(self, metric, value, param_list):
  628. """
  629. """
  630. param = self.custom_metric_param_parser(param_list)
  631. self.custom_param_dict[metric] = param
  632. score_model = self.scoreModel(param['kind'], param['optimal'], param['multiple'], np.array([value]))
  633. score_sub = score_model.cal_score()
  634. score = sum(score_sub) / len(score_sub)
  635. return score
  636. def func_score(self):
  637. score_metric_dict = {}
  638. score_type_dict = {}
  639. arr_func = self._function_statistic()
  640. print("\n[功能性表现及得分情况]")
  641. print("功能性各指标值:", [round(num, 2) for num in arr_func])
  642. if arr_func:
  643. arr_func = np.array([arr_func])
  644. score_model = self.scoreModel(self.kind_list, self.optimal_list, self.multiple_list, arr_func)
  645. score_sub = score_model.cal_score()
  646. score_sub = list(map(lambda x: 80 if np.isnan(x) else x, score_sub))
  647. score_metric = [round(num, 2) for num in score_sub]
  648. metric_list = [x for x in self.metric_list if x in self.config.builtinMetricList]
  649. score_metric_dict = {key: value for key, value in zip(metric_list, score_metric)}
  650. for metric in self.custom_metric_list:
  651. value = self.custom_data[metric]['value']
  652. param_list = self.customMetricParam[metric]
  653. score = self.custom_metric_score(metric, value, param_list)
  654. score_metric_dict[metric] = round(score, 2)
  655. score_metric_dict = {key: score_metric_dict[key] for key in self.metric_list}
  656. score_metric = list(score_metric_dict.values())
  657. if self.weight_custom: # 自定义权重
  658. score_metric_with_weight_dict = {key: score_metric_dict[key] * self.weight_dict[key] for key in
  659. self.weight_dict}
  660. for type in self.type_list:
  661. type_score = sum(
  662. value for key, value in score_metric_with_weight_dict.items() if key in self.metric_dict[type])
  663. score_type_dict[type] = round(type_score, 2) if type_score < 100 else 100
  664. score_type_with_weight_dict = {key: score_type_dict[key] * self.weight_type_dict[key] for key in
  665. score_type_dict}
  666. score_function = sum(score_type_with_weight_dict.values())
  667. else: # 客观赋权
  668. self.weight_list = cal_weight_from_80(score_metric)
  669. self.weight_dict = {key: value for key, value in zip(self.metric_list, self.weight_list)}
  670. score_function = cal_score_with_priority(score_metric, self.weight_list, self.priority_list)
  671. for type in self.type_list:
  672. type_weight = sum(value for key, value in self.weight_dict.items() if key in self.metric_dict[type])
  673. for key, value in self.weight_dict.items():
  674. if key in self.metric_dict[type]:
  675. # self.weight_dict[key] = round(value / type_weight, 4)
  676. self.weight_dict[key] = value / type_weight
  677. type_score_metric = [value for key, value in score_metric_dict.items() if key in self.metric_dict[type]]
  678. type_weight_list = [value for key, value in self.weight_dict.items() if key in self.metric_dict[type]]
  679. type_priority_list = [value for key, value in self.priority_dict.items() if
  680. key in self.metric_dict[type]]
  681. type_score = cal_score_with_priority(type_score_metric, type_weight_list, type_priority_list)
  682. score_type_dict[type] = round(type_score, 2) if type_score < 100 else 100
  683. for key in self.weight_dict:
  684. self.weight_dict[key] = round(self.weight_dict[key], 4)
  685. score_type = list(score_type_dict.values())
  686. self.weight_type_list = cal_weight_from_80(score_type)
  687. self.weight_type_dict = {key: value for key, value in zip(self.type_list, self.weight_type_list)}
  688. score_function = round(score_function, 2)
  689. print(f"功能性得分为:{score_function:.2f}分。")
  690. print(f"功能性各类型得分为:{score_type_dict}分。")
  691. print(f"功能性各指标得分为:{score_metric_dict}。")
  692. return score_function, score_type_dict, score_metric_dict
  693. def continuous_group(self, df):
  694. time_list = df['simTime'].values.tolist()
  695. frame_list = df['simFrame'].values.tolist()
  696. group_time = []
  697. group_frame = []
  698. sub_group_time = []
  699. sub_group_frame = []
  700. for i in range(len(frame_list)):
  701. if not sub_group_time or frame_list[i] - frame_list[i - 1] <= 1:
  702. sub_group_time.append(time_list[i])
  703. sub_group_frame.append(frame_list[i])
  704. else:
  705. group_time.append(sub_group_time)
  706. group_frame.append(sub_group_frame)
  707. sub_group_time = [time_list[i]]
  708. sub_group_frame = [frame_list[i]]
  709. group_time.append(sub_group_time)
  710. group_frame.append(sub_group_frame)
  711. group_time = [g for g in group_time if len(g) >= 2]
  712. group_frame = [g for g in group_frame if len(g) >= 2]
  713. # 输出图表值
  714. time = [[g[0], g[-1]] for g in group_time]
  715. frame = [[g[0], g[-1]] for g in group_frame]
  716. unfunc_time_df = pd.DataFrame(time, columns=['start_time', 'end_time'])
  717. unfunc_frame_df = pd.DataFrame(frame, columns=['start_frame', 'end_frame'])
  718. unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
  719. return unfunc_df
  720. def unfunctional_follow_v_deviation_df_statistic(self):
  721. unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
  722. 'v_deviation': self.v_deviation_list})
  723. unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
  724. v_df = unfunc_df[unfunc_df['v_deviation'] > self.optimal_dict['followSpeedDeviation']]
  725. v_df = v_df[['simTime', 'simFrame', 'v_deviation']]
  726. v_follow_df = self.continuous_group(v_df)
  727. # v_follow_df['type'] = 'follow'
  728. # v_follow_df['type'] = 'ACC'
  729. v_follow_df['type'] = f"{self.type_name_dict['functionACC']}"
  730. self.unfunc_follow_df = pd.concat([self.unfunc_follow_df, v_follow_df], ignore_index=True)
  731. def unfunctional_follow_dist_deviation_df_statistic(self):
  732. unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
  733. 'dist_deviation': self.dist_deviation_list})
  734. unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
  735. dist_df = unfunc_df[unfunc_df['dist_deviation'] > self.optimal_dict['followDistanceDeviation']] # 阈值由1改为了3
  736. dist_df = dist_df[['simTime', 'simFrame', 'dist_deviation']]
  737. dist_follow_df = self.continuous_group(dist_df)
  738. # v_follow_df['type'] = 'follow'
  739. # dist_follow_df['type'] = 'ACC'
  740. dist_follow_df['type'] = f"{self.type_name_dict['functionACC']}"
  741. self.unfunc_follow_df = pd.concat([self.unfunc_follow_df, dist_follow_df], ignore_index=True)
  742. def unfunctional_lane_df_statistic(self):
  743. unfunc_df = pd.DataFrame(
  744. {'simTime': self.center_time_list, 'simFrame': self.center_frame_list,
  745. 'center_dist': self.center_dist_with_nan})
  746. unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
  747. unfunc_df = unfunc_df.dropna(subset=['center_dist'])
  748. lane_df = unfunc_df[abs(unfunc_df['center_dist']) > self.optimal_dict['centerDistanceMax']]
  749. lane_df = lane_df[['simTime', 'simFrame', 'center_dist']]
  750. dist_lane_df = self.continuous_group(lane_df)
  751. # dist_lane_df['type'] = 'lane'
  752. # dist_lane_df['type'] = 'LKA'
  753. dist_lane_df['type'] = f"{self.type_name_dict['functionLKA']}"
  754. self.unfunc_lane_df = pd.concat([self.unfunc_lane_df, dist_lane_df], ignore_index=True)
  755. # def zip_time_pairs(self, zip_list, upper_limit=9999):
  756. # zip_time_pairs = zip(self.time_list, zip_list)
  757. # zip_vs_time = [[x, upper_limit if y > upper_limit else y] for x, y in zip_time_pairs if not math.isnan(y)]
  758. # return zip_vs_time
  759. def zip_time_pairs(self, zip_list):
  760. zip_time_pairs = zip(self.time_list, zip_list)
  761. zip_vs_time = [[x, "" if math.isnan(y) else y] for x, y in zip_time_pairs]
  762. return zip_vs_time
  763. def _get_weight_distribution(self, dimension):
  764. # get weight distribution
  765. weight_distribution = {}
  766. weight_distribution["name"] = self.config.dimension_name[dimension]
  767. for type in self.type_list:
  768. type_weight_indexes_dict = {key: f"{self.name_dict[key]}({value * 100:.2f}%)" for key, value in
  769. self.weight_dict.items() if
  770. key in self.metric_dict[type]}
  771. weight_distribution_type = {
  772. "weight": f"{self.type_name_dict[type]}({self.weight_type_dict[type] * 100:.2f}%)",
  773. "indexes": type_weight_indexes_dict
  774. }
  775. weight_distribution[type] = weight_distribution_type
  776. return weight_distribution
  777. def report_statistic(self):
  778. # report_dict = {
  779. # "name": "功能性",
  780. # "weight": f"{self.weight * 100:.2f}%",
  781. # "weightDistribution": weight_distribution,
  782. # "score": score_function,
  783. # "level": grade_function,
  784. # 'score_type': score_type,
  785. # 'score_metric': score_metric,
  786. # 'followStopCount': self.follow_stop_count,
  787. # "description1": func_description1,
  788. # "description2": func_description2,
  789. #
  790. # "functionACC": acc_dict,
  791. # "functionLKA": lka_dict,
  792. #
  793. # "speData": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time],
  794. # "accData": [lat_acc_vs_time, lon_acc_vs_time],
  795. #
  796. # }
  797. brakePedal_list = self.data_processed.driver_ctrl_data['brakePedal_list']
  798. throttlePedal_list = self.data_processed.driver_ctrl_data['throttlePedal_list']
  799. steeringWheel_list = self.data_processed.driver_ctrl_data['steeringWheel_list']
  800. # common parameter calculate
  801. brake_vs_time = self.zip_time_pairs(brakePedal_list)
  802. throttle_vs_time = self.zip_time_pairs(throttlePedal_list)
  803. steering_vs_time = self.zip_time_pairs(steeringWheel_list)
  804. report_dict = {
  805. "name": self.config.dimension_name["function"],
  806. "weight": f"{self.weight * 100:.2f}%",
  807. 'followStopCount': self.follow_stop_count,
  808. }
  809. # upper_limit = 40
  810. times_upper = 2
  811. # len_time = len(self.time_list)
  812. duration = self.time_list[-1]
  813. # score_function, score_type, score_metric = self.func_score()
  814. score_function, score_type_dict, score_metric_dict = self.func_score()
  815. # get weight distribution
  816. report_dict["weightDistribution"] = self._get_weight_distribution("function")
  817. score_function = int(score_function) if int(score_function) == score_function else round(
  818. score_function, 2)
  819. # score_type = [int(n) if int(n) == n else n for key, n in score_type_dict.items()]
  820. # score_metric = [int(n) if int(n) == n else n for key, n in score_metric_dict.items()]
  821. grade_function = score_grade(score_function)
  822. report_dict["score"] = score_function
  823. report_dict["level"] = grade_function
  824. # report_dict["score_type"] = score_type
  825. # report_dict["score_metric"] = score_metric
  826. # speed data
  827. ego_speed_list = self.ego_df['v'].values.tolist()
  828. ego_speed_vs_time = self.zip_time_pairs(ego_speed_list)
  829. obj_speed_vs_time = []
  830. rel_speed_vs_time = []
  831. # report_dict["speData"] = [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  832. # accData
  833. lat_acc_list = self.ego_df['lat_acc'].values.tolist()
  834. lat_acc_vs_time = self.zip_time_pairs(lat_acc_list)
  835. lon_acc_list = self.ego_df['lon_acc'].values.tolist()
  836. lon_acc_vs_time = self.zip_time_pairs(lon_acc_list)
  837. # acc data
  838. # lat_acc_list = self.ego_df['lat_acc'].values.tolist()
  839. # lat_acc_vs_time = self.zip_time_pairs(lat_acc_list)
  840. # lon_acc_list = self.ego_df['lon_acc'].values.tolist()
  841. # lon_acc_vs_time = self.zip_time_pairs(lon_acc_list)
  842. # report_dict["accData"] = [lat_acc_vs_time, lon_acc_vs_time]
  843. # statistic type report infos
  844. unfunc_metric_list = []
  845. func_over_optimal = []
  846. # function description
  847. func_type_list = []
  848. unfunc_type_list = []
  849. type_details_dict = {}
  850. for type in self.type_list:
  851. if type == "functionACC":
  852. builtin_graph_dict = {}
  853. custom_graph_dict = {}
  854. if len(self.obj_id_list) == 1:
  855. follow_description1 = "无目标车数据可计算;"
  856. follow_description2 = ""
  857. follow_description3 = "无目标车数据可计算;"
  858. follow_description4 = "无目标车数据可计算;"
  859. acc_dict_indexes = {}
  860. for metric in self.metric_dict[type]:
  861. acc_dict_indexes[metric] = {
  862. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  863. "name": f"{self.name_dict[metric]}",
  864. "score": 80,
  865. "avg": "-",
  866. "max": "-",
  867. "min": "-",
  868. }
  869. if self.kind_dict[metric] == -1:
  870. acc_dict_indexes[metric]["range"] = f"[0, {self.optimal_dict[metric]}]"
  871. elif self.kind_dict[metric] == 1:
  872. acc_dict_indexes[metric]["range"] = f"[{self.optimal_dict[metric]}, inf)"
  873. elif self.kind_dict[metric] == 0:
  874. acc_dict_indexes[metric][
  875. "range"] = f"[{self.optimal_dict[metric] * self.multiple_dict[metric][0]}, {self.optimal_dict[metric] * self.multiple_dict[metric][1]}]"
  876. acc_dict = {
  877. "name": f"{self.type_name_dict[type]}",
  878. "score": 80,
  879. "level": "良好",
  880. "description1": follow_description1,
  881. "description2": follow_description2,
  882. "description3": follow_description3,
  883. "description4": follow_description4,
  884. "noObjectCar": True,
  885. "indexes": acc_dict_indexes,
  886. "builtin": {},
  887. "custom": {}
  888. }
  889. # follow cruise description
  890. func_follow_metric_list = []
  891. unfunc_follow_metric_list = []
  892. str_follow_over_optimal = ''
  893. distance_vs_time = self.zip_time_pairs(self.dist_list_full_time)
  894. else:
  895. acc_dict = {
  896. "name": f"{self.type_name_dict[type]}",
  897. "noObjectCar": False,
  898. }
  899. # follow dict
  900. score_follow = score_type_dict[type]
  901. grade_follow = score_grade(score_follow)
  902. acc_dict["score"] = score_follow
  903. acc_dict["level"] = grade_follow
  904. unfunc_type_list.append(type) if score_type_dict[type] < 80 else func_type_list.append(type)
  905. # follow cruise description
  906. func_follow_metric_list = []
  907. unfunc_follow_metric_list = []
  908. for metric in self.metric_dict[type]:
  909. unfunc_follow_metric_list.append(metric) if score_metric_dict[
  910. metric] < 80 else func_follow_metric_list.append(
  911. metric)
  912. str_follow_over_optimal = ''
  913. if not unfunc_follow_metric_list:
  914. str_func_follow_metric = string_concatenate(func_follow_metric_list)
  915. follow_description1 = f"{str_func_follow_metric}指标均表现良好"
  916. else:
  917. for metric in unfunc_follow_metric_list:
  918. if metric in self.bulitin_metric_list:
  919. value = self.result[metric]
  920. if self.kind_dict[metric] == -1:
  921. metric_over_optimal = ((value - self.optimal_dict[metric]) / self.optimal_dict[
  922. metric]) * 100
  923. elif self.kind_dict[metric] == 1:
  924. metric_over_optimal = ((self.optimal_dict[metric] - value) / self.optimal_dict[
  925. metric]) * 100
  926. elif self.kind_dict[metric] == 0:
  927. metric_over_optimal = (abs(self.optimal_dict[metric] - value) / self.optimal_dict[
  928. metric]) * 100
  929. else:
  930. value = self.custom_data[metric]["value"][0]
  931. if self.custom_param_dict[metric]['kind'][0] == -1:
  932. metric_over_optimal = ((value - self.custom_param_dict[metric]['optimal'][0]) /
  933. self.custom_param_dict[metric]['optimal'][0]) * 100
  934. elif self.custom_param_dict[metric]['kind'][0] == 1:
  935. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] - value) /
  936. self.custom_param_dict[metric]['optimal'][0]) * 100
  937. elif self.custom_param_dict[metric]['kind'][0] == 0:
  938. metric_over_optimal = (abs(self.custom_param_dict[metric]['optimal'][0] - value) /
  939. self.custom_param_dict[metric]['optimal'][0]) * 100
  940. # str_follow_over_optimal += f"{metric}为{value:.2f},超过合理范围{metric_over_optimal:.2f}%;"
  941. str_follow_over_optimal += f"{metric}为{value:.2f}{self.unit_dict[metric]},超过合理范围{metric_over_optimal:.2f}%;"
  942. str_follow_over_optimal = str_follow_over_optimal[:-1] if str_follow_over_optimal else ""
  943. str_func_follow_metric = string_concatenate(func_follow_metric_list)
  944. str_unfunc_follow_metric = string_concatenate(unfunc_follow_metric_list)
  945. if not func_follow_metric_list:
  946. follow_description1 = f"{str_unfunc_follow_metric}指标表现不佳。{str_follow_over_optimal}"
  947. else:
  948. follow_description1 = f"{str_func_follow_metric}指标表现良好,{str_unfunc_follow_metric}指标表现不佳。{str_follow_over_optimal}"
  949. # for follow_description2
  950. follow_duration = (len(self.time_list_follow) - 2) * 0.04 if self.time_list_follow else 0
  951. follow_description2 = f"自车在行驶时有{follow_duration:.2f}s处于跟车状态,"
  952. follow_description3 = ""
  953. if "followResponseTime" in self.metric_list:
  954. # for follow_description3
  955. cnt3_1 = len(self.follow_stop_time_start_list)
  956. tmp3_list = [x for x in self.follow_stop_time_start_list if
  957. x > self.optimal_dict['followResponseTime']]
  958. cnt3_2 = len(tmp3_list)
  959. percent3 = 0 if cnt3_1 == 0 else round(cnt3_2 / cnt3_1 * 100, 2)
  960. follow_description3 = f"起停跟车响应时间有{cnt3_2}次超出合理范围,占比为{percent3}%;"
  961. follow_description4 = ""
  962. if "followDistanceDeviation" in self.metric_list:
  963. # for follow_description4
  964. cnt4_1 = len(self.stop_distance_list)
  965. tmp4_list = [x for x in self.stop_distance_list if
  966. x < self.optimal_dict['followDistanceDeviation']]
  967. cnt4_2 = len(tmp4_list)
  968. percent4 = 0 if cnt4_1 == 0 else round(cnt4_2 / cnt4_1 * 100, 2)
  969. follow_description4 = f"在本次测试中,跟车状态下目标车共发生了{cnt4_1}次停车,有{cnt4_2}次超出合理范围,占比为{percent4}%;"
  970. # distance_list = obj_df['dist'].values.tolist()
  971. # distance_deviation_vs_time = self.zip_time_pairs(self.dist_deviation_list_full_time)
  972. #
  973. # acc_dict["description1"] = replace_key_with_value(follow_description1, self.name_dict)
  974. # acc_dict["description2"] = replace_key_with_value(follow_description2, self.name_dict)
  975. # acc_dict["description3"] = replace_key_with_value(follow_description3, self.name_dict)
  976. # acc_dict["description4"] = replace_key_with_value(follow_description4, self.name_dict)
  977. # common parameter calculate
  978. obj_df = self.df[self.df['playerId'] == 2]
  979. obj_speed_list = obj_df['v'].values.tolist()
  980. obj_speed_vs_time = self.zip_time_pairs(obj_speed_list)
  981. rel_speed_vs_time = self.zip_time_pairs(self.v_relative_list_full_time)
  982. distance_vs_time = self.zip_time_pairs(self.dist_list_full_time)
  983. # acc_dict["speData"] = [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  984. # acc_dict["disData"] = distance_vs_time
  985. unfunc_follow_df = self.unfunc_follow_df.copy()
  986. unfunc_follow_df['type'] = "origin"
  987. unfunc_follow_slices = unfunc_follow_df.to_dict('records')
  988. # acc_dict["speMarkLine"] = unfunc_follow_slices
  989. # acc_dict["disMarkLine"] = unfunc_follow_slices
  990. distance_deviation_vs_time = self.zip_time_pairs(self.dist_deviation_list_full_time)
  991. # function ACC data
  992. acc_dict_indexes = {}
  993. for metric in self.metric_dict[type]:
  994. if metric == "followSpeedDeviation":
  995. self.unfunctional_follow_v_deviation_df_statistic()
  996. unfunc_v_df = self.unfunc_follow_df.copy()
  997. unfunc_v_df.loc[unfunc_v_df['type'] != 'ACC', 'type'] = "origin"
  998. # unfunc_v_df.loc[unfunc_v_df['type'] == 'time', 'type'] = "time"
  999. unfunc_v_slices = unfunc_v_df.to_dict('records')
  1000. df1 = self.unfunc_follow_df[self.unfunc_follow_df['type'] == 'ACC']
  1001. df1['v_time'] = df1['end_time'] - df1['start_time']
  1002. devi_v_time = df1['v_time'].sum()
  1003. follow_duration = (len(self.time_list_follow) - 2) * 0.04 if self.time_list_follow else 0
  1004. percent2_1 = devi_v_time / follow_duration * 100 if follow_duration else 0
  1005. if devi_v_time != 0:
  1006. follow_description2 += f"跟车状态下自车和目标车的速度差共有{devi_v_time:.2f}s超出合理范围,占比为{percent2_1:.2f}%;"
  1007. else:
  1008. follow_description2 += "跟车状态下自车和目标车的速度差均在合理范围内;"
  1009. v_deviation_list = [x for x in self.v_deviation_list if not np.isnan(x)]
  1010. acc_dict_indexes["followSpeedDeviation"] = {
  1011. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1012. "name": f"{self.name_dict[metric]}",
  1013. "score": score_metric_dict[
  1014. "followSpeedDeviation"],
  1015. "avg": f'{np.mean(v_deviation_list):.2f}' if v_deviation_list else 0,
  1016. "max": f'{max(v_deviation_list):.2f}' if v_deviation_list else 0,
  1017. "min": f'{min(v_deviation_list):.2f}' if v_deviation_list else 0,
  1018. # "range": f"[0, {self.optimal_dict['followSpeedDeviation']}]"
  1019. "range": f"[-{self.optimal_dict['followSpeedDeviation']}, {self.optimal_dict['followSpeedDeviation']}]"
  1020. }
  1021. fsd_data = {
  1022. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1023. "name": f"{self.name_dict[metric]}",
  1024. "data": rel_speed_vs_time,
  1025. "range": f"[-{self.optimal_dict['followSpeedDeviation']}, {self.optimal_dict['followSpeedDeviation']}]",
  1026. # "range": f"[0, {self.optimal_dict['followSpeedDeviation']}]",
  1027. # "markLine": unfunc_v_slices,
  1028. # "markLine2": [-1 * self.optimal_dict['followSpeedDeviation'],
  1029. # self.optimal_dict['followSpeedDeviation']],
  1030. }
  1031. builtin_graph_dict["followSpeedDeviation"] = fsd_data
  1032. if metric == "followDistanceDeviation":
  1033. self.unfunctional_follow_dist_deviation_df_statistic()
  1034. unfunc_dist_df = self.unfunc_follow_df.copy()
  1035. unfunc_dist_df.loc[unfunc_dist_df['type'] != 'ACC', 'type'] = "origin"
  1036. # unfunc_dist_df.loc[unfunc_dist_df['type'] == 'distance', 'type'] = "distance"
  1037. unfunc_dist_slices = unfunc_dist_df.to_dict('records')
  1038. df2 = self.unfunc_follow_df[self.unfunc_follow_df['type'] == 'ACC']
  1039. df2['dist_time'] = df2['end_time'] - df2['start_time']
  1040. devi_dist_time = df2['dist_time'].sum()
  1041. follow_duration = (len(self.time_list_follow) - 2) * 0.04 if self.time_list_follow else 0
  1042. percent2_2 = devi_dist_time / follow_duration * 100 if follow_duration else 0
  1043. if devi_dist_time != 0:
  1044. follow_description2 += f"跟车状态下自车和目标车的距离差共有{devi_dist_time:.2f}s超出合理范围,占比为{percent2_2:.2f}%;"
  1045. else:
  1046. follow_description2 += "跟车状态下自车和目标车的距离差均在合理范围内;"
  1047. dist_deviation_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
  1048. acc_dict_indexes["followDistanceDeviation"] = {
  1049. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1050. "name": f"{self.name_dict[metric]}",
  1051. "score": score_metric_dict[
  1052. "followDistanceDeviation"],
  1053. "avg": f'{np.mean(dist_deviation_list):.2f}' if dist_deviation_list else 0,
  1054. "max": f'{max(dist_deviation_list):.2f}' if dist_deviation_list else 0,
  1055. "min": f'{min(dist_deviation_list):.2f}' if dist_deviation_list else 0,
  1056. "range": f"[0, {self.optimal_dict['followDistanceDeviation']}]"
  1057. }
  1058. fdd_data = {
  1059. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1060. "name": f"{self.name_dict[metric]}",
  1061. "data": distance_deviation_vs_time,
  1062. "range": f"[0, {self.optimal_dict['followDistanceDeviation']}]",
  1063. # "markLine": unfunc_dist_slices,
  1064. # "markLine2": [self.optimal_dict['followDistanceDeviation']],
  1065. }
  1066. builtin_graph_dict["followDistanceDeviation"] = fdd_data
  1067. if metric == "followStopDistance":
  1068. acc_dict_indexes["followStopDistance"] = {
  1069. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1070. "name": f"{self.name_dict[metric]}",
  1071. "score": score_metric_dict[
  1072. "followStopDistance"],
  1073. "avg": f'{np.mean(self.stop_distance_list):.2f}' if self.stop_distance_list else 0,
  1074. "max": f'{max(self.stop_distance_list):.2f}' if self.stop_distance_list else 0,
  1075. "min": f'{min(self.stop_distance_list):.2f}' if self.stop_distance_list else 0,
  1076. "range": f"[{self.optimal_dict['followStopDistance']}, inf)"
  1077. }
  1078. # sdd_data = {
  1079. # # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1080. # "name": f"{self.name_dict[metric]}",
  1081. # "data": self.stop_distance_list,
  1082. # "range": f"[{self.optimal_dict['followStopDistance']}, inf)",
  1083. # # "ref": [self.optimal_dict['followStopDistance'] - 1,
  1084. # # self.optimal_dict['followStopDistance']],
  1085. # }
  1086. # builtin_graph_dict["followStopDistance"] = sdd_data
  1087. if metric == "followResponseTime":
  1088. acc_dict_indexes["followResponseTime"] = {
  1089. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1090. "name": f"{self.name_dict[metric]}",
  1091. "score": score_metric_dict["followResponseTime"],
  1092. "avg": f'{np.mean(self.follow_stop_time_start_list):.2f}' if self.follow_stop_time_start_list else 0,
  1093. "max": f'{max(self.follow_stop_time_start_list):.2f}' if self.follow_stop_time_start_list else 0,
  1094. "min": f'{min(self.follow_stop_time_start_list):.2f}' if self.follow_stop_time_start_list else 0,
  1095. "range": f"[0, {self.optimal_dict['followResponseTime']}]"
  1096. }
  1097. # rt_data = {
  1098. # # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1099. # "name": f"{self.name_dict[metric]}",
  1100. # "data": self.follow_stop_time_start_list,
  1101. # # "range": f"[0, {self.optimal_dict['followResponseTime']})"
  1102. # }
  1103. # builtin_graph_dict["followResponseTime"] = rt_data
  1104. if metric not in self.bulitin_metric_list:
  1105. acc_dict_indexes[metric] = {
  1106. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1107. "name": f"{self.name_dict[metric]}",
  1108. "score": score_metric_dict[metric],
  1109. "avg": self.custom_data[metric]['tableData']['avg'],
  1110. "max": self.custom_data[metric]['tableData']['max'],
  1111. "min": self.custom_data[metric]['tableData']['min'],
  1112. }
  1113. if self.custom_param_dict[metric]['kind'][0] == -1:
  1114. acc_dict_indexes[metric][
  1115. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1116. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1117. acc_dict_indexes[metric][
  1118. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1119. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1120. acc_dict_indexes[metric][
  1121. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0] * self.custom_param_dict[metric]['multiple'][0][0]}, {self.custom_param_dict[metric]['optimal'][0] * self.custom_param_dict[metric]['multiple'][0][1]}]"
  1122. custom_graph_dict[metric] = self.custom_data[metric]["reportData"]
  1123. self.custom_markline_list.extend(self.custom_data[metric]["reportData"]['markLine'])
  1124. acc_dict["indexes"] = acc_dict_indexes
  1125. acc_dict["builtin"] = builtin_graph_dict
  1126. acc_dict["custom"] = custom_graph_dict
  1127. acc_dict["description1"] = replace_key_with_value(follow_description1, self.name_dict)
  1128. acc_dict["description2"] = replace_key_with_value(follow_description2, self.name_dict)
  1129. acc_dict["description3"] = replace_key_with_value(follow_description3, self.name_dict)
  1130. acc_dict["description4"] = replace_key_with_value(follow_description4, self.name_dict)
  1131. type_details_dict[type] = acc_dict
  1132. unfunc_metric_list += unfunc_follow_metric_list
  1133. func_over_optimal.append(str_follow_over_optimal)
  1134. elif type == "functionLKA":
  1135. lka_dict = {
  1136. "name": f"{self.type_name_dict[type]}",
  1137. }
  1138. builtin_graph_dict = {}
  1139. custom_graph_dict = {}
  1140. # get score and grade
  1141. score_lane = score_type_dict["functionLKA"]
  1142. grade_lane = score_grade(score_lane)
  1143. lka_dict['score'] = score_lane
  1144. lka_dict['level'] = grade_lane
  1145. # unfunc_type_list.append('车道保持') if score_type_dict["functionLKA"] < 80 else func_type_list.append(
  1146. # '车道保持')
  1147. unfunc_type_list.append(type) if score_type_dict[type] < 80 else func_type_list.append(type)
  1148. # lane keep description
  1149. func_lane_metric_list = []
  1150. unfunc_lane_metric_list = []
  1151. for metric in self.metric_dict[type]:
  1152. unfunc_lane_metric_list.append(metric) if score_metric_dict[
  1153. metric] < 80 else func_lane_metric_list.append(
  1154. metric)
  1155. lka_dict_indexes = {}
  1156. for metric in self.metric_dict[type]:
  1157. if metric == "laneDistance":
  1158. lka_dict_indexes["laneDistance"] = {
  1159. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1160. "name": f"{self.name_dict[metric]}",
  1161. "score": score_metric_dict["laneDistance"],
  1162. "avg": f'{np.mean(self.line_dist):.2f}' if self.line_dist else "-",
  1163. "max": f'{max(self.line_dist):.2f}' if self.line_dist else "-",
  1164. "min": f'{min(self.line_dist):.2f}' if self.line_dist else "-",
  1165. "range": f"[{self.optimal_dict['laneDistance']}, 1.875]"
  1166. }
  1167. if metric == "centerDistanceExpectation":
  1168. lka_dict_indexes["centerDistanceExpectation"] = {
  1169. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1170. "name": f"{self.name_dict[metric]}",
  1171. "score": score_metric_dict['centerDistanceExpectation'],
  1172. "avg": f'{self.result["centerDistanceExpectation"]:.2f}' if self.center_dist else "-",
  1173. "max": "-",
  1174. "min": "-",
  1175. "range": f"[0, {self.optimal_dict['centerDistanceExpectation']}]"
  1176. }
  1177. if metric == "centerDistanceStandardDeviation":
  1178. lka_dict_indexes["centerDistanceStandardDeviation"] = {
  1179. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1180. "name": f"{self.name_dict[metric]}",
  1181. "score": score_metric_dict['centerDistanceStandardDeviation'],
  1182. "avg": f'{self.result["centerDistanceStandardDeviation"]:.2f}' if self.center_dist else "-",
  1183. "max": "-",
  1184. "min": "-",
  1185. "range": f"[0, {self.optimal_dict['centerDistanceStandardDeviation']}]"
  1186. }
  1187. if metric == "centerDistanceMax":
  1188. lka_dict_indexes["centerDistanceMax"] = {
  1189. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1190. "name": f"{self.name_dict[metric]}",
  1191. "score": score_metric_dict['centerDistanceMax'],
  1192. "avg": "-",
  1193. "max": f'{self.result["centerDistanceMax"]:.2f}' if self.center_dist else "-",
  1194. "min": "-",
  1195. "range": f"[0, {self.optimal_dict['centerDistanceMax']}]"
  1196. }
  1197. if metric == "centerDistanceMin":
  1198. lka_dict_indexes["centerDistanceMin"] = {
  1199. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1200. "name": f"{self.name_dict[metric]}",
  1201. "score": score_metric_dict['centerDistanceMin'],
  1202. "avg": "-",
  1203. "max": "-",
  1204. "min": f'{self.result["centerDistanceMin"]:.2f}' if self.center_dist else "-",
  1205. "range": f"[0, {self.optimal_dict['centerDistanceMin']}]"
  1206. }
  1207. if metric == "centerDistanceFrequency":
  1208. lka_dict_indexes["centerDistanceFrequency"] = {
  1209. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1210. "name": f"{self.name_dict[metric]}",
  1211. "score": score_metric_dict['centerDistanceFrequency'],
  1212. "avg": f'{self.result["centerDistanceFrequency"]:.2f}' if self.center_dist else "-",
  1213. "max": "-",
  1214. "min": "-",
  1215. "range": f"[0, {self.optimal_dict['centerDistanceFrequency']}]"
  1216. }
  1217. if metric == "centerDistanceRange":
  1218. lka_dict_indexes["centerDistanceRange"] = {
  1219. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1220. "name": f"{self.name_dict[metric]}",
  1221. "score": score_metric_dict['centerDistanceRange'],
  1222. "avg": f'{self.result["centerDistanceRange"]:.2f}' if self.center_dist else "-",
  1223. "max": "-",
  1224. "min": "-",
  1225. "range": f"[0, {self.optimal_dict['centerDistanceRange']}]"
  1226. }
  1227. if metric not in self.bulitin_metric_list:
  1228. lka_dict_indexes[metric] = {
  1229. # "name": self.custom_data[metric]['name'],
  1230. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1231. "name": f"{self.name_dict[metric]}",
  1232. "score": score_metric_dict[metric],
  1233. "avg": self.custom_data[metric]['tableData']['avg'],
  1234. "max": self.custom_data[metric]['tableData']['max'],
  1235. "min": self.custom_data[metric]['tableData']['min'],
  1236. }
  1237. if self.custom_param_dict[metric]['kind'][0] == -1:
  1238. lka_dict_indexes[metric]["range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1239. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1240. lka_dict_indexes[metric][
  1241. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1242. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1243. lka_dict_indexes[metric][
  1244. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0] * self.custom_param_dict[metric]['multiple'][0][0]}, {self.custom_param_dict[metric]['optimal'][0] * self.custom_param_dict[metric]['multiple'][0][1]}]"
  1245. custom_graph_dict[metric] = self.custom_data[metric]["reportData"]
  1246. self.custom_markline_list.extend(self.custom_data[metric]["reportData"]['markLine'])
  1247. lka_dict["indexes"] = lka_dict_indexes
  1248. str_lane_over_optimal = ''
  1249. if not unfunc_lane_metric_list:
  1250. str_func_lane_metric = string_concatenate(func_lane_metric_list)
  1251. lane_description1 = f"{str_func_lane_metric}指标均表现良好"
  1252. else:
  1253. for metric in unfunc_lane_metric_list:
  1254. if metric in self.bulitin_metric_list:
  1255. value = self.result[metric]
  1256. if self.kind_dict[metric] == -1:
  1257. metric_over_optimal = ((value - self.optimal_dict[metric]) / self.optimal_dict[
  1258. metric]) * 100
  1259. elif self.kind_dict[metric] == 1:
  1260. metric_over_optimal = ((self.optimal_dict[metric] - value) / self.optimal_dict[
  1261. metric]) * 100
  1262. elif self.kind_dict[metric] == 0:
  1263. metric_over_optimal = (abs(self.optimal_dict[metric] - value) / self.optimal_dict[
  1264. metric]) * 100
  1265. else:
  1266. value = self.custom_data[metric]["value"][0]
  1267. if self.custom_param_dict[metric]['kind'][0] == -1:
  1268. metric_over_optimal = ((value - self.custom_param_dict[metric]['optimal'][0]) /
  1269. self.custom_param_dict[metric]['optimal'][0]) * 100
  1270. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1271. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] - value) /
  1272. self.custom_param_dict[metric]['optimal'][0]) * 100
  1273. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1274. metric_over_optimal = (abs(self.custom_param_dict[metric]['optimal'][0] - value) /
  1275. self.custom_param_dict[metric]['optimal'][0]) * 100
  1276. str_lane_over_optimal += f"{metric}为{value:.2f}{self.unit_dict[metric]},超过合理范围{metric_over_optimal:.2f}%;"
  1277. str_lane_over_optimal = str_lane_over_optimal[:-1] if str_lane_over_optimal else ""
  1278. str_func_lane_metric = string_concatenate(func_lane_metric_list)
  1279. str_unfunc_lane_metric = string_concatenate(unfunc_lane_metric_list)
  1280. if not func_lane_metric_list:
  1281. lane_description1 = f"{str_unfunc_lane_metric}指标表现不佳。{str_lane_over_optimal}"
  1282. else:
  1283. lane_description1 = f"{str_func_lane_metric}指标表现良好,{str_unfunc_lane_metric}指标表现不佳。{str_lane_over_optimal}"
  1284. lane_description2 = ""
  1285. center_distance_vs_time = []
  1286. if "centerDistanceMax" in self.metric_list:
  1287. cnt2_1 = len(self.center_dist)
  1288. tmp2_list = [x for x in self.center_dist if x > self.optimal_dict['centerDistanceMax']]
  1289. cnt2_2 = len(tmp2_list)
  1290. percent2 = 0 if cnt2_1 == 0 else (cnt2_2 / cnt2_1 * 100)
  1291. dist_time = percent2 * duration / 100
  1292. if dist_time != 0:
  1293. lane_description2 = f"距离有{dist_time:.2f}秒超出合理范围,占比为{percent2:.2f}%"
  1294. else:
  1295. lane_description2 = f"距离均在合理范围内,算法车道保持表现良好"
  1296. # lane keep data for graph
  1297. # center_distance_vs_time = self.zip_time_pairs(self.center_dist)
  1298. center_distance_vs_time = self.zip_time_pairs(self.center_dist_with_nan)
  1299. self.unfunctional_lane_df_statistic()
  1300. #
  1301. # lka_dict["description1"] = replace_key_with_value(lane_description1, self.name_dict)
  1302. # lka_dict["description2"] = lane_description2
  1303. unfunc_lane_df = self.unfunc_lane_df.copy()
  1304. unfunc_lane_df['type'] = "origin"
  1305. unfunc_lane_slices = unfunc_lane_df.to_dict('records')
  1306. unfunc_lane_dist_df = self.unfunc_lane_df.copy()
  1307. unfunc_lane_dist_df.loc[unfunc_lane_dist_df['type'] != 'LKA', 'type'] = "origin"
  1308. unfunc_lane_dist_slices = unfunc_lane_dist_df.to_dict('records')
  1309. lka_data = {
  1310. "name": "车辆中心线横向距离(m)",
  1311. "data": center_distance_vs_time,
  1312. # "markLine": unfunc_lane_dist_slices
  1313. }
  1314. if 'centerDistanceMax' in self.optimal_dict:
  1315. lka_range = f"[0, {self.optimal_dict['centerDistanceMax']}]"
  1316. elif 'centerDistanceMin' in self.optimal_dict:
  1317. lka_range = f"[0, {self.optimal_dict['centerDistanceMin']}]"
  1318. else:
  1319. lka_range = f"[0, 0.5]"
  1320. lka_data["range"] = lka_range
  1321. builtin_graph_dict["centerDistance"] = lka_data
  1322. lka_dict["builtin"] = builtin_graph_dict
  1323. lka_dict["custom"] = custom_graph_dict
  1324. lka_dict["description1"] = replace_key_with_value(lane_description1, self.name_dict)
  1325. lka_dict["description2"] = lane_description2
  1326. # lka_dict["centerDisData"] = center_distance_vs_time
  1327. # lka_dict["centerDisMarkLine"] = unfunc_lane_dist_slices
  1328. type_details_dict[type] = lka_dict
  1329. unfunc_metric_list += unfunc_lane_metric_list
  1330. func_over_optimal.append(str_lane_over_optimal)
  1331. else:
  1332. type_dict = {
  1333. "name": f"{self.type_name_dict[type]}",
  1334. }
  1335. builtin_graph_dict = {}
  1336. custom_graph_dict = {}
  1337. # get score and grade
  1338. score_custom_type = score_type_dict[type]
  1339. grade_custom_type = score_grade(score_custom_type)
  1340. type_dict["score"] = score_custom_type
  1341. type_dict["level"] = grade_custom_type
  1342. # custom type description
  1343. good_custom_metric_list = []
  1344. bad_custom_metric_list = []
  1345. unfunc_type_list.append(type) if score_type_dict[type] < 80 else func_type_list.append(type)
  1346. type_dict_indexes = {}
  1347. for metric in self.metric_dict[type]:
  1348. bad_custom_metric_list.append(metric) if score_metric_dict[
  1349. metric] < 80 else good_custom_metric_list.append(
  1350. metric)
  1351. type_dict_indexes[metric] = {
  1352. # "name": self.custom_data[metric]['name'],
  1353. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1354. "name": f"{self.name_dict[metric]}",
  1355. "score": score_metric_dict[metric],
  1356. "avg": self.custom_data[metric]['tableData']['avg'],
  1357. "max": self.custom_data[metric]['tableData']['max'],
  1358. "min": self.custom_data[metric]['tableData']['min'],
  1359. }
  1360. if self.custom_param_dict[metric]['kind'][0] == -1:
  1361. type_dict_indexes[metric]["range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1362. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1363. type_dict_indexes[metric]["range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1364. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1365. type_dict_indexes[metric][
  1366. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0] * self.custom_param_dict[metric]['multiple'][0][0]}, {self.custom_param_dict[metric]['optimal'][0] * self.custom_param_dict[metric]['multiple'][0][1]}]"
  1367. custom_graph_dict[metric] = self.custom_data[metric]['reportData']
  1368. self.custom_markline_list.extend(self.custom_data[metric]["reportData"]['markLine'])
  1369. type_dict["indexes"] = type_dict_indexes
  1370. str_type_over_optimal = ""
  1371. if not bad_custom_metric_list:
  1372. str_good_custom_metric = string_concatenate(good_custom_metric_list)
  1373. type_description = f"{str_good_custom_metric}指标均表现良好"
  1374. else:
  1375. for metric in bad_custom_metric_list:
  1376. value = self.custom_data[metric]["value"][0]
  1377. if self.custom_param_dict[metric]['kind'][0] == -1:
  1378. metric_over_optimal = ((value - self.custom_param_dict[metric]['optimal'][0]) /
  1379. self.custom_param_dict[metric]['optimal'][0]) * 100
  1380. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1381. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] - value) /
  1382. self.custom_param_dict[metric]['optimal'][0]) * 100
  1383. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1384. if self.custom_param_dict[metric]['optimal'][0]==0:
  1385. division_num = 0.00001
  1386. metric_over_optimal = (abs(self.custom_param_dict[metric]['optimal'][0] - value) /
  1387. division_num) * 100
  1388. else:
  1389. metric_over_optimal = (abs(self.custom_param_dict[metric]['optimal'][0] - value) /
  1390. self.custom_param_dict[metric]['optimal'][0]) * 100
  1391. str_type_over_optimal += f"{metric}为{value:.2f}{self.unit_dict[metric]},超过合理范围{metric_over_optimal:.2f}%;"
  1392. str_type_over_optimal = str_type_over_optimal[:-1]
  1393. str_good_custom_metric = string_concatenate(good_custom_metric_list)
  1394. str_bad_custom_metric = string_concatenate(bad_custom_metric_list)
  1395. if not good_custom_metric_list:
  1396. type_description = f"{str_bad_custom_metric}指标表现不佳。{str_type_over_optimal}"
  1397. else:
  1398. type_description = f"{str_good_custom_metric}指标表现良好,{str_bad_custom_metric}指标表现不佳。{str_type_over_optimal}"
  1399. type_dict["builtin"] = builtin_graph_dict
  1400. type_dict["custom"] = custom_graph_dict
  1401. type_dict["description"] = replace_key_with_value(type_description, self.name_dict)
  1402. type_details_dict[type] = type_dict
  1403. unfunc_metric_list += bad_custom_metric_list
  1404. func_over_optimal.append(str_type_over_optimal)
  1405. report_dict["details"] = type_details_dict
  1406. # report_dict["speData"] = [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  1407. func_over_optimal = [s for s in func_over_optimal if s]
  1408. str_func_over_optimal = ';'.join(func_over_optimal)
  1409. if grade_function == '优秀':
  1410. str_func_type = string_concatenate(func_type_list)
  1411. func_description1 = f'算法在{str_func_type}功能上表现优秀;'
  1412. elif grade_function == '良好':
  1413. str_func_type = string_concatenate(func_type_list)
  1414. func_description1 = f'算法在{str_func_type}功能上总体表现良好,满足设计指标要求;'
  1415. elif grade_function == '一般':
  1416. str_unfunc_type = string_concatenate(unfunc_type_list)
  1417. str_unfunc_metric = string_concatenate(unfunc_metric_list)
  1418. str_unfunc_metric = replace_key_with_value(str_unfunc_metric, self.type_name_dict)
  1419. func_description1 = f'算法在{str_unfunc_type}功能上表现一般、需要在{str_unfunc_metric}指标上进一步优化。其中,{str_func_over_optimal};'
  1420. elif grade_function == '较差':
  1421. str_unfunc_type = string_concatenate(unfunc_type_list)
  1422. func_description1 = f'算法在{str_unfunc_type}功能上表现较差,需要提高算法的功能性表现。其中,{str_func_over_optimal};'
  1423. if not unfunc_type_list:
  1424. func_description2 = '功能性在各个功能上的表现俱佳。'
  1425. else:
  1426. str_unfunc_type = string_concatenate(unfunc_type_list)
  1427. func_description2 = f"算法在{str_unfunc_type}功能上需要重点优化。"
  1428. # report_dict["description1"] = replace_key_with_value(func_description1, self.name_dict)
  1429. report_dict["description1"] = replace_key_with_value(replace_key_with_value(func_description1, self.name_dict),
  1430. self.type_name_dict)
  1431. report_dict["description2"] = replace_key_with_value(func_description2, self.type_name_dict)
  1432. report_dict['commonData'] = {
  1433. "per": {
  1434. "name": "脚刹/油门踏板开度(百分比)",
  1435. "legend": ["刹车踏板开度", "油门踏板开度"],
  1436. "data": [brake_vs_time, throttle_vs_time]
  1437. },
  1438. "ang": {
  1439. "name": "方向盘转角(角度°)",
  1440. "data": steering_vs_time
  1441. },
  1442. "spe": {
  1443. "name": "速度(km/h)",
  1444. "legend": ["自车速度", "目标车速度", "自车与目标车相对速度"],
  1445. "data": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  1446. },
  1447. "acc": {
  1448. "name": "加速度(m/s²)",
  1449. "legend": ["横向加速度", "纵向加速度"],
  1450. "data": [lat_acc_vs_time, lon_acc_vs_time]
  1451. },
  1452. # "dis": {
  1453. # "name": "前车距离(m)",
  1454. # "data": distance_vs_time
  1455. # }
  1456. }
  1457. if "functionACC" in self.type_list:
  1458. report_dict['commonData']["dis"] = {
  1459. "name": "前车距离(m)",
  1460. "data": distance_vs_time
  1461. }
  1462. self.unfunc_df = pd.concat([self.unfunc_df, self.unfunc_follow_df, self.unfunc_lane_df], ignore_index=True)
  1463. unfunc_df = self.unfunc_df.copy()
  1464. unfunc_slices = unfunc_df.to_dict('records')
  1465. unfunc_slices.extend(self.custom_markline_list)
  1466. report_dict["commonMarkLine"] = unfunc_slices
  1467. # report_dict = {
  1468. # "name": "功能性",
  1469. # "weight": f"{self.weight * 100:.2f}%",
  1470. # "weightDistribution": weight_distribution,
  1471. # "score": score_function,
  1472. # "level": grade_function,
  1473. # 'followStopCount': self.follow_stop_count,
  1474. # "description1": func_description1,
  1475. # "description2": func_description2,
  1476. #
  1477. # "functionACC": acc_dict,
  1478. # "functionLKA": lka_dict,
  1479. #
  1480. # "speData": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time],
  1481. # "accData": [lat_acc_vs_time, lon_acc_vs_time],
  1482. #
  1483. # }
  1484. self.eval_data = self.ego_df.copy()
  1485. return report_dict
  1486. def get_eval_data(self):
  1487. if 'line_dist' in self.eval_data.columns:
  1488. df = self.eval_data[['simTime', 'simFrame', 'playerId', 'lat_acc_roc', 'lon_acc_roc', 'line_dist']].copy()
  1489. else:
  1490. df = self.eval_data[['simTime', 'simFrame', 'playerId', 'lat_acc_roc', 'lon_acc_roc']].copy()
  1491. self.df['line_dist'] = pd.Series(dtype=float)
  1492. return df