safe.py 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116
  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), xieguijin(xieguijin@china-icv.cn), yangzihao(yangzihao@china-icv.cn)
  10. @Data: 2023/07/25
  11. @Last Modified: 2023/07/26
  12. @Summary: safe 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. from collections import defaultdict
  22. import scipy.integrate as spi
  23. from score_weight import cal_score_with_priority, cal_weight_from_80
  24. from common import score_grade, string_concatenate, replace_key_with_value, score_over_100
  25. class Safe(object):
  26. """
  27. Class for achieving safe metrics for autonomous driving.
  28. Attributes:
  29. df: Vehicle driving data, stored in dataframe format.
  30. df_drivectrl: Vehcile driving control data, including brakepedal, throttle pedal and steerignwheel.
  31. Methods:
  32. _safe_param_cal_new: Calculate parameters for evaluateion.
  33. _cal_v_ego_projection: Calculate ego car velocity project over distance.
  34. _cal_v_projection: Calculate relative velocity project over distance.
  35. _cal_a_projection: Calculate relative acceleration project over distance.
  36. _calculate_derivative: Calculate derivative.
  37. _cal_relative_angular_v: Calculate relative angular velocity.
  38. _death_pr: Calculate death probability.
  39. _cal_collisionRisk_level: Calculate collisionRisk level.
  40. dist: Calculate distance of two cars.
  41. """
  42. def __init__(self, data_processed, custom_data, scoreModel):
  43. self.eval_data = pd.DataFrame()
  44. self.data_processed = data_processed
  45. self.scoreModel = scoreModel
  46. self.df = data_processed.object_df.copy()
  47. self.ego_df = data_processed.ego_data
  48. self.laneinfo_df = data_processed.lane_info_df
  49. self.obj_id_list = data_processed.obj_id_list
  50. # config infos for calculating score
  51. self.config = data_processed.config
  52. safe_config = self.config.config['safe']
  53. self.safe_config = safe_config
  54. # common data
  55. self.bulitin_metric_list = self.config.builtinMetricList
  56. # dimension data
  57. self.weight_custom = safe_config['weightCustom']
  58. self.metric_list = safe_config['metric']
  59. self.type_list = safe_config['type']
  60. self.type_name_dict = safe_config['typeName']
  61. self.name_dict = safe_config['name']
  62. self.unit_dict = safe_config['unit']
  63. # custom metric data
  64. self.customMetricParam = safe_config['customMetricParam']
  65. self.custom_metric_list = list(self.customMetricParam.keys())
  66. self.custom_data = custom_data
  67. self.custom_param_dict = {}
  68. # score data
  69. self.weight = safe_config['weightDimension']
  70. self.weight_type_dict = safe_config['typeWeight']
  71. self.weight_type_list = safe_config['typeWeightList']
  72. self.weight_dict = safe_config['weight']
  73. self.weight_list = safe_config['weightList']
  74. self.priority_dict = safe_config['priority']
  75. self.priority_list = safe_config['priorityList']
  76. self.kind_dict = safe_config['kind']
  77. self.kind1_dict = self.kind_dict[0]
  78. self.optimal_dict = safe_config['optimal']
  79. self.optimal1_dict = self.optimal_dict[0]
  80. self.multiple_dict = safe_config['multiple']
  81. self.kind_list = safe_config['kindList']
  82. self.optimal_list = safe_config['optimalList']
  83. self.multiple_list = safe_config['multipleList']
  84. self.metric_dict = safe_config['typeMetricDict']
  85. # self.time_metric_list = self.metric_dict['safeTime']
  86. # self.distance_metric_list = self.metric_dict['safeDistance']
  87. # lists of drving control info
  88. self.time_list = data_processed.driver_ctrl_data['time_list']
  89. self.frame_list = self.ego_df['simFrame'].values.tolist()
  90. self.collisionRisk = 0
  91. self.empty_flag = True
  92. # no car following scene
  93. if len(self.obj_id_list) > 1:
  94. self.unsafe_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  95. self.unsafe_time_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  96. self.unsafe_dist_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  97. # self.unsafe_acce_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  98. self.unsafe_acce_drac_df = pd.DataFrame(
  99. columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  100. self.unsafe_acce_xtn_df = pd.DataFrame(
  101. columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  102. self.unsafe_prob_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  103. self.most_dangerous = {}
  104. self.pass_percent = {}
  105. self._safe_param_cal_new()
  106. def _safe_param_cal_new(self):
  107. """
  108. """
  109. Tc = 0.3
  110. rho = 0.3 # 驾驶员制动反应时间
  111. ego_accel_max = 6 # 自车油门最大加速度
  112. obj_decel_max = 8 # 前车刹车最大减速度
  113. ego_decel_min = 1 # 自车刹车最小减速度 ug
  114. ego_decel_lon_max = 8
  115. ego_decel_lat_max = 1
  116. # 构建双层字典数据结构
  117. obj_dict = defaultdict(dict)
  118. obj_data_dict = self.df.to_dict('records')
  119. for item in obj_data_dict:
  120. obj_dict[item['simFrame']][item['playerId']] = item
  121. df_list = []
  122. EGO_PLAYER_ID = 1
  123. # self.empty_flag = True
  124. for frame_num in self.frame_list:
  125. ego_data = obj_dict[frame_num][EGO_PLAYER_ID]
  126. v1 = ego_data['v'] / 3.6 # km/h to m/s
  127. x1 = ego_data['posX']
  128. y1 = ego_data['posY']
  129. h1 = ego_data['posH']
  130. len1 = ego_data['dimX']
  131. width1 = ego_data['dimY']
  132. o_x1 = ego_data['offX']
  133. v_x1 = ego_data['speedX'] / 3.6 # km/h to m/s
  134. v_y1 = ego_data['speedY'] / 3.6 # km/h to m/s
  135. a_x1 = ego_data['accelX']
  136. a_y1 = ego_data['accelY']
  137. # a1 = ego_data['accel']
  138. for playerId in self.obj_id_list:
  139. if playerId == EGO_PLAYER_ID:
  140. continue
  141. try:
  142. obj_data = obj_dict[frame_num][playerId]
  143. lane_width = self.laneinfo_df[self.laneinfo_df['simFrame'].isin([frame_num])]['width'].values/2
  144. except KeyError:
  145. continue
  146. x2 = obj_data['posX']
  147. y2 = obj_data['posY']
  148. dist = self.dist(x1, y1, x2, y2)
  149. obj_data['dist'] = dist
  150. v_x2 = obj_data['speedX'] / 3.6 # km/h to m/s
  151. v_y2 = obj_data['speedY'] / 3.6 # km/h to m/s
  152. v2 = obj_data['v'] / 3.6 # km/h to m/s
  153. # h2 = obj_data['posH']
  154. len2 = obj_data['dimX']
  155. width2 = obj_data['dimY']
  156. o_x2 = obj_data['offX']
  157. a_x2 = obj_data['accelX']
  158. a_y2 = obj_data['accelY']
  159. # a2 = obj_data['accel']
  160. dx, dy = x2 - x1, y2 - y1
  161. # 定义矢量A和x轴正向向量x
  162. A = np.array([dx, dy])
  163. x = np.array([1, 0])
  164. # 计算点积和向量长度
  165. dot_product = np.dot(A, x)
  166. vector_length_A = np.linalg.norm(A)
  167. vector_length_x = np.linalg.norm(x)
  168. # 计算夹角的余弦值
  169. cos_theta = dot_product / (vector_length_A * vector_length_x)
  170. # 将余弦值转换为角度值(弧度制)
  171. beta = np.arccos(cos_theta) # 如何通过theta正负确定方向
  172. lon_d = dist * math.cos(beta - h1)
  173. lat_d = abs(dist * math.sin(beta - h1)) # 需要增加左正右负的判断,但beta取值为[0,pi)
  174. obj_dict[frame_num][playerId]['lon_d'] = lon_d
  175. obj_dict[frame_num][playerId]['lat_d'] = lat_d
  176. if lon_d > 100 or lon_d < -5 or lat_d > 4:
  177. continue
  178. self.empty_flag = False
  179. vx, vy = v_x1 - v_x2, v_y1 - v_y2
  180. ax, ay = a_x2 - a_x1, a_y2 - a_y1
  181. v_ego_p = self._cal_v_ego_projection(dx, dy, v_x1, v_y1)
  182. v_obj_p = self._cal_v_ego_projection(dx, dy, v_x2, v_y2)
  183. vrel_projection_in_dist = self._cal_v_projection(dx, dy, vx, vy)
  184. arel_projection_in_dist = self._cal_a_projection(dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1,
  185. v_x2, v_y2)
  186. obj_dict[frame_num][playerId]['vrel_projection_in_dist'] = vrel_projection_in_dist
  187. obj_dict[frame_num][playerId]['arel_projection_in_dist'] = arel_projection_in_dist
  188. obj_dict[frame_num][playerId]['v_ego_projection_in_dist'] = v_ego_p
  189. obj_dict[frame_num][playerId]['v_obj_projection_in_dist'] = v_obj_p
  190. obj_type = obj_data['type']
  191. if abs(dist*cos_theta) <= lane_width[0]:
  192. TTC = self._cal_TTC(dist, vrel_projection_in_dist)
  193. else:
  194. TTC = 10000
  195. MTTC = self._cal_MTTC(TTC, vrel_projection_in_dist, arel_projection_in_dist)
  196. THW = self._cal_THW(dist, v_ego_p)
  197. # 单车道时可用
  198. LonSD = self._cal_longitudinal_safe_dist(v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min,
  199. obj_decel_max)
  200. lat_dist = 0.5
  201. v_right = v1
  202. v_left = v2
  203. a_right_lat_brake_min = 1
  204. a_left_lat_brake_min = 1
  205. a_lat_max = 5
  206. LatSD = self._cal_lateral_safe_dist(lat_dist, v_right, v_left, rho, a_right_lat_brake_min,
  207. a_left_lat_brake_min,
  208. a_lat_max)
  209. DRAC = self._cal_DRAC(dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2)
  210. lon_a1 = a_x1 * math.cos(h1) + a_y1 * math.sin(h1)
  211. lon_a2 = a_x2 * math.cos(h1) + a_y2 * math.sin(h1)
  212. lon_a = abs(lon_a1 - lon_a2)
  213. lon_d = dist * abs(math.cos(beta - h1))
  214. lon_v = v_x1 * math.cos(h1) + v_y1 * math.sin(h1)
  215. BTN = self._cal_BTN_new(lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max)
  216. lat_a1 = a_x1 * math.sin(h1) * -1 + a_y1 * math.cos(h1)
  217. lat_a2 = a_x2 * math.sin(h1) * -1 + a_y2 * math.cos(h1)
  218. lat_a = abs(lat_a1 - lat_a2)
  219. lat_d = dist * abs(math.sin(beta - h1))
  220. lat_v = v_x1 * math.sin(h1) * -1 + v_y1 * math.cos(h1)
  221. STN = self._cal_STN_new(TTC, lat_a1, lat_a, lat_d, lat_v, ego_decel_lat_max, width1, width2)
  222. obj_dict[frame_num][playerId]['lat_v_rel'] = v_x1 - v_x2
  223. obj_dict[frame_num][playerId]['lon_v_rel'] = v_y1 - v_y2
  224. # BTN = self.cal_BTN(a_y1, ay, dy, vy, max_ay)
  225. # STN = self.cal_STN(TTC, a_x1, ax, dx, vx, max_ax, len1, len2)
  226. TTC = None if (not TTC or TTC < 0) else TTC
  227. MTTC = None if (not MTTC or MTTC < 0) else MTTC
  228. THW = None if (not THW or THW < 0) else THW
  229. DRAC = 10 if DRAC >= 10 else DRAC
  230. if not TTC or TTC > 4000: # threshold = 4258.41
  231. collisionSeverity = 0
  232. pr_death = 0
  233. collisionRisk = 0
  234. else:
  235. result, error = spi.quad(self._normal_distribution, 0, TTC - Tc)
  236. collisionSeverity = 1 - result
  237. pr_death = self._death_pr(obj_type, vrel_projection_in_dist)
  238. collisionRisk = 0.4 * pr_death + 0.6 * collisionSeverity
  239. obj_dict[frame_num][playerId]['TTC'] = TTC
  240. obj_dict[frame_num][playerId]['MTTC'] = MTTC
  241. obj_dict[frame_num][playerId]['THW'] = THW
  242. obj_dict[frame_num][playerId]['LonSD'] = LonSD
  243. obj_dict[frame_num][playerId]['LatSD'] = LatSD
  244. obj_dict[frame_num][playerId]['DRAC'] = DRAC
  245. obj_dict[frame_num][playerId]['BTN'] = abs(BTN)
  246. obj_dict[frame_num][playerId]['STN'] = abs(STN)
  247. obj_dict[frame_num][playerId]['collisionSeverity'] = collisionSeverity * 100
  248. obj_dict[frame_num][playerId]['pr_death'] = pr_death * 100
  249. obj_dict[frame_num][playerId]['collisionRisk'] = collisionRisk * 100
  250. df_fnum = pd.DataFrame(obj_dict[frame_num].values())
  251. df_list.append(df_fnum)
  252. df_safe = pd.concat(df_list)
  253. col_list = ['simTime', 'simFrame', 'playerId', 'v', 'accel', 'lon_acc', 'lat_acc', 'dist', 'lon_d', 'lat_d',
  254. 'lat_v_rel', 'lon_v_rel', 'v_ego_projection_in_dist',
  255. 'v_obj_projection_in_dist', 'vrel_projection_in_dist', 'arel_projection_in_dist',
  256. 'TTC', 'MTTC', 'THW', 'LonSD', 'LatSD', 'DRAC', 'BTN', 'STN', 'collisionSeverity', 'pr_death',
  257. 'collisionRisk']
  258. if not self.empty_flag:
  259. df_safe = df_safe[col_list].reset_index(drop=True)
  260. # df_safe.reset_index(drop=True)
  261. self.eval_data = df_safe.copy()
  262. self.df = df_safe
  263. self.df['flag'] = 0
  264. if not self.empty_flag:
  265. for metric in self.metric_list:
  266. if metric in self.bulitin_metric_list:
  267. self.df['tmp'] = self.df[metric].apply(lambda x: 1 if x < self.optimal1_dict[metric] else 0)
  268. self.df['flag'] = self.df['flag'] + self.df['tmp']
  269. self.df['unsafe_flag'] = self.df['flag'].apply(lambda x: 1 if x > 0 else 0)
  270. def _cal_v_ego_projection(self, dx, dy, v_x1, v_y1):
  271. # 计算 AB 连线的向量 AB
  272. # dx = x2 - x1
  273. # dy = y2 - y1
  274. # 计算 AB 连线的模长 |AB|
  275. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  276. # 计算 AB 连线的单位向量 U_AB
  277. U_ABx = dx / AB_mod
  278. U_ABy = dy / AB_mod
  279. # 计算 A 在 AB 连线上的速度 V1_on_AB
  280. V1_on_AB = v_x1 * U_ABx + v_y1 * U_ABy
  281. return V1_on_AB
  282. def _cal_v_projection(self, dx, dy, vx, vy):
  283. # 计算 AB 连线的向量 AB
  284. # dx = x2 - x1
  285. # dy = y2 - y1
  286. # 计算 AB 连线的模长 |AB|
  287. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  288. # 计算 AB 连线的单位向量 U_AB
  289. U_ABx = dx / AB_mod
  290. U_ABy = dy / AB_mod
  291. # 计算 A 相对于 B 的速度 V_relative
  292. # vx = vx1 - vx2
  293. # vy = vy1 - vy2
  294. # 计算 A 相对于 B 在 AB 连线上的速度 V_on_AB
  295. V_on_AB = vx * U_ABx + vy * U_ABy
  296. return V_on_AB
  297. def _cal_a_projection(self, dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1, v_x2, v_y2):
  298. # 计算 AB 连线的向量 AB
  299. # dx = x2 - x1
  300. # dy = y2 - y1
  301. # 计算 θ
  302. V_mod = math.sqrt(vx ** 2 + vy ** 2)
  303. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  304. if V_mod == 0 or AB_mod == 0:
  305. return 0
  306. cos_theta = (vx * dx + vy * dy) / (V_mod * AB_mod)
  307. theta = math.acos(cos_theta)
  308. # 计算 AB 连线的模长 |AB|
  309. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  310. # 计算 AB 连线的单位向量 U_AB
  311. U_ABx = dx / AB_mod
  312. U_ABy = dy / AB_mod
  313. # 计算 A 相对于 B 的加速度 a_relative
  314. # ax = ax1 - ax2
  315. # ay = ay1 - ay2
  316. # 计算 A 相对于 B 在 AB 连线上的加速度 a_on_AB
  317. a_on_AB = ax * U_ABx + ay * U_ABy
  318. VA = np.array([v_x1, v_y1])
  319. VB = np.array([v_x2, v_y2])
  320. D_A = np.array([x1, y1])
  321. D_B = np.array([x2, y2])
  322. V_r = VA - VB
  323. V = np.linalg.norm(V_r)
  324. w = self._cal_relative_angular_v(theta, D_A, D_B, VA, VB)
  325. a_on_AB_back = self._calculate_derivative(a_on_AB, w, V, theta)
  326. return a_on_AB_back
  327. # 计算相对加速度
  328. def _calculate_derivative(self, a, w, V, theta):
  329. # 计算(V×cos(θ))'的值
  330. # derivative = a * math.cos(theta) - w * V * math.sin(theta)theta
  331. derivative = a - w * V * math.sin(theta)
  332. return derivative
  333. def _cal_relative_angular_v(self, theta, A, B, VA, VB):
  334. dx = A[0] - B[0]
  335. dy = A[1] - B[1]
  336. dvx = VA[0] - VB[0]
  337. dvy = VA[1] - VB[1]
  338. # (dx * dvy - dy * dvx)
  339. angular_velocity = math.sqrt(dvx ** 2 + dvy ** 2) * math.sin(theta) / math.sqrt(dx ** 2 + dy ** 2)
  340. return angular_velocity
  341. def _death_pr(self, obj_type, v_relative):
  342. if obj_type == 5:
  343. p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
  344. else:
  345. p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
  346. return p_death
  347. def _cal_collisionRisk_level(self, obj_type, v_relative, collisionSeverity):
  348. if obj_type == 5:
  349. p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
  350. else:
  351. p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
  352. collisionRisk = 0.4 * p_death + 0.6 * collisionSeverity
  353. return collisionRisk
  354. # 求两车之间当前距离
  355. def dist(self, x1, y1, x2, y2):
  356. dist = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
  357. return dist
  358. # TTC (time to collision)
  359. def _cal_TTC(self, dist, vrel_projection_in_dist):
  360. if vrel_projection_in_dist == 0:
  361. return math.inf
  362. TTC = dist / vrel_projection_in_dist
  363. return TTC
  364. def _cal_MTTC(self, dist, vrel_projection_in_dist, arel_projection_in_dist):
  365. MTTC = math.nan
  366. if arel_projection_in_dist != 0:
  367. tmp = vrel_projection_in_dist ** 2 + 2 * arel_projection_in_dist * dist # 投影为负数,不会发生碰撞风险
  368. if tmp < 0:
  369. return math.nan
  370. t1 = (-1 * vrel_projection_in_dist - math.sqrt(tmp)) / arel_projection_in_dist
  371. t2 = (-1 * vrel_projection_in_dist + math.sqrt(tmp)) / arel_projection_in_dist
  372. if t1 > 0 and t2 > 0:
  373. if t1 >= t2:
  374. MTTC = t2
  375. elif t1 < t2:
  376. MTTC = t1
  377. elif t1 > 0 and t2 <= 0:
  378. MTTC = t1
  379. elif t1 <= 0 and t2 > 0:
  380. MTTC = t2
  381. if arel_projection_in_dist == 0 and vrel_projection_in_dist > 0:
  382. MTTC = dist / vrel_projection_in_dist
  383. return MTTC
  384. # THW (time headway)
  385. def _cal_THW(self, dist, v_ego_projection_in_dist):
  386. if not v_ego_projection_in_dist:
  387. THW = None
  388. else:
  389. THW = dist / v_ego_projection_in_dist
  390. return THW
  391. def velocity(self, v_x, v_y):
  392. v = math.sqrt(v_x ** 2 + v_y ** 2) * 3.6
  393. return v
  394. def _cal_longitudinal_safe_dist(self, v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min, ego_decel_max):
  395. lon_dist_min = v_ego_p * rho + ego_accel_max * (rho ** 2) / 2 + (v_ego_p + rho * ego_accel_max) ** 2 / (
  396. 2 * ego_decel_min) - v_obj_p ** 2 / (2 * ego_decel_max)
  397. return lon_dist_min
  398. def _cal_lateral_safe_dist(self, lat_dist, v_right, v_left, rho, a_right_lat_brake_min, a_left_lat_brake_min,
  399. a_lat_max):
  400. v_right_rho = v_right + rho * a_lat_max
  401. v_left_rho = v_left + rho * a_lat_max
  402. dist_min = lat_dist + ((v_right + v_right_rho) * rho / 2 + v_right_rho ** 2 / a_right_lat_brake_min / 2 + (
  403. (v_left + v_right_rho) * rho / 2) + v_left_rho ** 2 / a_left_lat_brake_min / 2)
  404. return dist_min
  405. # DRAC (decelerate required avoid collision)
  406. def _cal_DRAC(self, dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2):
  407. dist_length = dist - (len2 / 2 - o_x2 + len1 / 2 + o_x1) # 4.671
  408. if dist_length < 0:
  409. dist_width = dist - (width2 / 2 + width1 / 2)
  410. if dist_width < 0:
  411. return math.inf
  412. else:
  413. d = dist_width
  414. else:
  415. d = dist_length
  416. DRAC = vrel_projection_in_dist ** 2 / (2 * d)
  417. return DRAC
  418. # BTN (brake threat number)
  419. def _cal_BTN_new(self, lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max):
  420. BTN = (lon_a1 + lon_a - lon_v ** 2 / (2 * lon_d)) / ego_decel_lon_max # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
  421. return BTN
  422. # STN (steer threat number)
  423. def _cal_STN_new(self, ttc, lat_a1, lat_a, lat_d, lat_v, ego_decel_lat_max, width1, width2):
  424. STN = (lat_a1 + lat_a + 2 / ttc ** 2 * (lat_d + abs(ego_decel_lat_max * lat_v) * (
  425. width1 + width2) / 2 + abs(lat_v * ttc))) / ego_decel_lat_max
  426. return STN
  427. # BTN (brake threat number)
  428. def cal_BTN(self, a_y1, ay, dy, vy, max_ay):
  429. BTN = (a_y1 + ay - vy ** 2 / (2 * dy)) / max_ay # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
  430. return BTN
  431. # STN (steer threat number)
  432. def cal_STN(self, ttc, a_x1, ax, dx, vx, max_ax, width1, width2):
  433. STN = (a_x1 + ax + 2 / ttc ** 2 * (dx + np.sign(max_ax * vx) * (width1 + width2) / 2 + vx * ttc)) / max_ax
  434. return STN
  435. # 追尾碰撞风险
  436. def _normal_distribution(self, x):
  437. mean = 1.32
  438. std_dev = 0.26
  439. return (1 / (math.sqrt(std_dev * 2 * math.pi))) * math.exp(-0.5 * (x - mean) ** 2 / std_dev)
  440. def continuous_group(self, df):
  441. time_list = df['simTime'].values.tolist()
  442. frame_list = df['simFrame'].values.tolist()
  443. group_time = []
  444. group_frame = []
  445. sub_group_time = []
  446. sub_group_frame = []
  447. for i in range(len(frame_list)):
  448. if not sub_group_time or frame_list[i] - frame_list[i - 1] <= 1:
  449. sub_group_time.append(time_list[i])
  450. sub_group_frame.append(frame_list[i])
  451. else:
  452. group_time.append(sub_group_time)
  453. group_frame.append(sub_group_frame)
  454. sub_group_time = [time_list[i]]
  455. sub_group_frame = [frame_list[i]]
  456. group_time.append(sub_group_time)
  457. group_frame.append(sub_group_frame)
  458. group_time = [g for g in group_time if len(g) >= 2]
  459. group_frame = [g for g in group_frame if len(g) >= 2]
  460. # 输出图表值
  461. time = [[g[0], g[-1]] for g in group_time]
  462. frame = [[g[0], g[-1]] for g in group_frame]
  463. unfunc_time_df = pd.DataFrame(time, columns=['start_time', 'end_time'])
  464. unfunc_frame_df = pd.DataFrame(frame, columns=['start_frame', 'end_frame'])
  465. unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
  466. return unfunc_df
  467. # def continuous_group_old(self, df):
  468. # time_list = df['simTime'].values.tolist()
  469. # frame_list = df['simFrame'].values.tolist()
  470. #
  471. # group = []
  472. # sub_group = []
  473. #
  474. # for i in range(len(frame_list)):
  475. # if not sub_group or frame_list[i] - frame_list[i - 1] <= 1:
  476. # sub_group.append(time_list[i])
  477. # else:
  478. # group.append(sub_group)
  479. # sub_group = [time_list[i]]
  480. #
  481. # group.append(sub_group)
  482. # group = [g for g in group if len(g) >= 2]
  483. #
  484. # # 输出图表值
  485. # time = [[g[0], g[-1]] for g in group]
  486. # unsafe_df = pd.DataFrame(time, columns=['start_time', 'end_time'])
  487. #
  488. # return unsafe_df
  489. def unsafe_time_ttc_df_statistic(self, obj_df):
  490. ttc_df = obj_df[obj_df['TTC'] < self.optimal1_dict['TTC']]
  491. ttc_df = ttc_df[['simTime', 'simFrame', 'TTC']]
  492. ttc_time_df = self.continuous_group(ttc_df)
  493. ttc_time_df['type'] = 'TTC'
  494. # ttc_time_df['type'] = 'time'
  495. self.unsafe_time_df = pd.concat([self.unsafe_time_df, ttc_time_df], ignore_index=True)
  496. def unsafe_time_mttc_df_statistic(self, obj_df):
  497. mttc_df = obj_df[obj_df['MTTC'] < self.optimal1_dict['MTTC']]
  498. mttc_df = mttc_df[['simTime', 'simFrame', 'MTTC']]
  499. mttc_time_df = self.continuous_group(mttc_df)
  500. mttc_time_df['type'] = 'MTTC'
  501. # mttc_time_df['type'] = 'time'
  502. self.unsafe_time_df = pd.concat([self.unsafe_time_df, mttc_time_df], ignore_index=True)
  503. def unsafe_time_thw_df_statistic(self, obj_df):
  504. thw_df = obj_df[obj_df['THW'] < self.optimal1_dict['THW']]
  505. thw_df = thw_df[['simTime', 'simFrame', 'THW']]
  506. thw_time_df = self.continuous_group(thw_df)
  507. thw_time_df['type'] = 'THW'
  508. # thw_time_df['type'] = 'time'
  509. self.unsafe_time_df = pd.concat([self.unsafe_time_df, thw_time_df], ignore_index=True)
  510. def unsafe_distance_lonsd_df_statistic(self, obj_df):
  511. lonsd_df = obj_df[obj_df['LonSD'] < self.optimal1_dict['LonSD']]
  512. lonsd_df = lonsd_df[['simTime', 'simFrame', 'LonSD']]
  513. lonsd_dist_df = self.continuous_group(lonsd_df)
  514. lonsd_dist_df['type'] = 'LonSD'
  515. # lonsd_dist_df['type'] = 'distance'
  516. self.unsafe_dist_df = pd.concat([self.unsafe_dist_df, lonsd_dist_df], ignore_index=True)
  517. def unsafe_distance_latsd_df_statistic(self, obj_df):
  518. latsd_df = obj_df[obj_df['LatSD'] < self.optimal1_dict['LatSD']]
  519. latsd_df = latsd_df[['simTime', 'simFrame', 'LatSD']]
  520. latsd_dist_df = self.continuous_group(latsd_df)
  521. latsd_dist_df['type'] = 'LatSD'
  522. # latsd_dist_df['type'] = 'distance'
  523. self.unsafe_dist_df = pd.concat([self.unsafe_dist_df, latsd_dist_df], ignore_index=True)
  524. def unsafe_acceleration_drac_df_statistic(self, obj_df):
  525. drac_df = obj_df[obj_df['DRAC'] > self.optimal1_dict['DRAC']]
  526. drac_df = drac_df[['simTime', 'simFrame', 'DRAC']]
  527. drac_acce_df = self.continuous_group(drac_df)
  528. drac_acce_df['type'] = 'DRAC'
  529. # drac_acce_df['type'] = 'acceleration'
  530. self.unsafe_acce_drac_df = pd.concat([self.unsafe_acce_drac_df, drac_acce_df], ignore_index=True)
  531. def unsafe_acceleration_btn_df_statistic(self, obj_df):
  532. btn_df = obj_df[obj_df['BTN'] > self.optimal1_dict['BTN']]
  533. btn_df = btn_df[['simTime', 'simFrame', 'BTN']]
  534. btn_acce_df = self.continuous_group(btn_df)
  535. btn_acce_df['type'] = 'BTN'
  536. # btn_acce_df['type'] = 'acceleration'
  537. self.unsafe_acce_xtn_df = pd.concat([self.unsafe_acce_xtn_df, btn_acce_df], ignore_index=True)
  538. def unsafe_acceleration_stn_df_statistic(self, obj_df):
  539. stn_df = obj_df[obj_df['STN'] > self.optimal1_dict['STN']]
  540. stn_df = stn_df[['simTime', 'simFrame', 'STN']]
  541. stn_acce_df = self.continuous_group(stn_df)
  542. stn_acce_df['type'] = 'STN'
  543. # stn_acce_df['type'] = 'acceleration'
  544. self.unsafe_acce_xtn_df = pd.concat([self.unsafe_acce_xtn_df, stn_acce_df], ignore_index=True)
  545. def unsafe_probability_cr_df_statistic(self, obj_df):
  546. cr_df = obj_df[obj_df['collisionRisk'] > self.optimal1_dict['collisionRisk']]
  547. cr_df = cr_df[['simTime', 'simFrame', 'collisionRisk']]
  548. cr_prob_df = self.continuous_group(cr_df)
  549. cr_prob_df['type'] = 'collisionRisk'
  550. # cr_prob_df['type'] = 'probability'
  551. self.unsafe_prob_df = pd.concat([self.unsafe_prob_df, cr_prob_df], ignore_index=True)
  552. def unsafe_probability_cs_df_statistic(self, obj_df):
  553. cs_df = obj_df[obj_df['collisionSeverity'] > self.optimal1_dict['collisionSeverity']]
  554. cs_df = cs_df[['simTime', 'simFrame', 'collisionSeverity']]
  555. cs_prob_df = self.continuous_group(cs_df)
  556. cs_prob_df['type'] = 'collisionSeverity'
  557. # cs_prob_df['type'] = 'probability'
  558. self.unsafe_prob_df = pd.concat([self.unsafe_prob_df, cs_prob_df], ignore_index=True)
  559. def _safe_statistic_most_dangerous(self):
  560. min_list = ['TTC', 'MTTC', 'THW', 'LonSD', 'LatSD']
  561. max_list = ['DRAC', 'BTN', 'STN', 'collisionRisk', 'collisionSeverity']
  562. for metric in min_list:
  563. if metric in self.metric_list:
  564. if metric in self.df.columns:
  565. self.most_dangerous[metric] = self.df[metric].min()
  566. else:
  567. self.most_dangerous[metric] = self.optimal1_dict[metric]
  568. if np.isnan(self.most_dangerous[metric]):
  569. self.most_dangerous[metric] = self.optimal1_dict[metric]
  570. for metric in max_list:
  571. if metric in self.metric_list:
  572. if metric in self.df.columns:
  573. self.most_dangerous[metric] = self.df[metric].max()
  574. else:
  575. self.most_dangerous[metric] = self.optimal1_dict[metric]
  576. # self.most_dangerous[metric] = self.df[metric].max()
  577. if np.isnan(self.most_dangerous[metric]):
  578. self.most_dangerous[metric] = self.optimal1_dict[metric]
  579. def _safe_statistic_pass_percent(self):
  580. greater_list = ['TTC', 'MTTC', 'THW', 'LonSD', 'LatSD']
  581. lesser_list = ['DRAC', 'BTN', 'STN', 'collisionRisk', 'collisionSeverity']
  582. for metric in greater_list:
  583. if metric in self.metric_list:
  584. if metric in self.df.columns:
  585. self.pass_percent[metric] = self.df[self.df[metric] >= self.optimal1_dict[metric]][metric].count() / \
  586. self.df[metric].count()
  587. else:
  588. self.pass_percent[metric] = 0.8
  589. if np.isnan(self.pass_percent[metric]):
  590. self.pass_percent[metric] = 0.8
  591. for metric in lesser_list:
  592. if metric in self.metric_list:
  593. if metric in self.df.columns:
  594. self.pass_percent[metric] = self.df[self.df[metric] <= self.optimal1_dict[metric]][metric].count() / \
  595. self.df[metric].count()
  596. else:
  597. self.pass_percent[metric] = 0.8
  598. if np.isnan(self.pass_percent[metric]):
  599. self.pass_percent[metric] = 0.8
  600. if "collisionSeverity" in self.metric_list:
  601. self.collisionRisk = 1 - self.pass_percent["collisionSeverity"]
  602. def _safe_statistic(self):
  603. # list_metric = ["TTC","MTTC","THW","LonSD","LatSD","DRAC","BTN","STN","collisionSeverity", "collisionRisk"]
  604. self._safe_statistic_most_dangerous()
  605. self._safe_statistic_pass_percent()
  606. most_dangerous_list = [abs(value) for key, value in self.most_dangerous.items() if key in self.metric_list]
  607. pass_percent_list = [abs(value) for key, value in self.pass_percent.items() if key in self.metric_list]
  608. arr_safe = [most_dangerous_list + pass_percent_list]
  609. return arr_safe
  610. def custom_metric_param_parser(self, param_list):
  611. """
  612. param_dict = {
  613. "paramA" [
  614. {
  615. "kind": "-1",
  616. "optimal": "1",
  617. "multiple": ["0.5","5"],
  618. "spare1": null,
  619. "spare2": null
  620. }
  621. ]
  622. }
  623. """
  624. kind_list = []
  625. optimal_list = []
  626. multiple_list = []
  627. spare_list = []
  628. # spare1_list = []
  629. # spare2_list = []
  630. for i in range(len(param_list)):
  631. kind_list.append(int(param_list[i]['kind']))
  632. optimal_list.append(float(param_list[i]['optimal']))
  633. multiple_list.append([float(x) for x in param_list[i]['multiple']])
  634. spare_list.append([item["param"] for item in param_list[i]["spare"]])
  635. # spare1_list.append(param_list[i]['spare1'])
  636. # spare2_list.append(param_list[i]['spare2'])
  637. result = {
  638. "kind": kind_list,
  639. "optimal": optimal_list,
  640. "multiple": multiple_list,
  641. "spare": spare_list,
  642. # "spare1": spare1_list,
  643. # "spare2": spare2_list
  644. }
  645. return result
  646. def custom_metric_score(self, metric, value, param_list):
  647. """
  648. """
  649. param = self.custom_metric_param_parser(param_list)
  650. self.custom_param_dict[metric] = param
  651. score_model = self.scoreModel(param['kind'], param['optimal'], param['multiple'], np.array([value]))
  652. score_sub = score_model.cal_score()
  653. score = sum(score_sub) / len(score_sub)
  654. return score
  655. def _safe_no_obj_statistic(self):
  656. # list_metric = ["TTC","MTTC","THW","LonSD","LatSD","DRAC","BTN","STN","collisionSeverity", "collisionRisk"]
  657. most_dangerous_list = [abs(value) for key, value in self.optimal1_dict.items() if key in self.metric_list]
  658. pass_percent_list = [1.0] * len(self.optimal1_dict.keys())
  659. arr_safe = [most_dangerous_list + pass_percent_list]
  660. return arr_safe
  661. def safe_score_new(self):
  662. """
  663. """
  664. score_metric_dict = {}
  665. score_type_dict = {}
  666. if len(self.obj_id_list) == 1:
  667. arr_safe = self._safe_no_obj_statistic()
  668. else:
  669. arr_safe = self._safe_statistic()
  670. print("\n[安全性表现及得分情况]")
  671. print("安全性各指标值:", [[round(num, 2) for num in row] for row in arr_safe])
  672. if arr_safe:
  673. arr_safe = np.array(arr_safe)
  674. score_model = self.scoreModel(self.kind_list, self.optimal_list, self.multiple_list, arr_safe)
  675. score_sub = score_model.cal_score()
  676. metric_list = [x for x in self.metric_list if x in self.config.builtinMetricList]
  677. metric_num = len(metric_list)
  678. if len(self.obj_id_list) > 1 and not self.empty_flag:
  679. score_sub[-metric_num:] = [num * 1.25 for num in score_sub[-metric_num:]]
  680. else:
  681. score_sub = [80] * len(score_sub)
  682. score_sub = list(map(lambda x: 100 if np.isnan(x) else x, score_sub)) # 对None值做特判
  683. score_metric = []
  684. for i in range(metric_num):
  685. score_tmp = (score_sub[i] + score_sub[i + metric_num]) / 2
  686. score_metric.append(round(score_tmp, 2))
  687. score_metric_dict = {key: value for key, value in zip(metric_list, score_metric)}
  688. for metric in self.custom_metric_list:
  689. value = self.custom_data[metric]['value']
  690. param_list = self.customMetricParam[metric]
  691. score = self.custom_metric_score(metric, value, param_list)
  692. score_metric_dict[metric] = round(score, 2)
  693. score_metric_dict = {key: score_metric_dict[key] for key in self.metric_list}
  694. score_metric = list(score_metric_dict.values())
  695. if self.weight_custom: # 用户自定义权重
  696. score_metric_with_weight_dict = {key: score_metric_dict[key] * self.weight_dict[key] for key in
  697. self.weight_dict}
  698. for type in self.type_list:
  699. type_score = sum(
  700. value for key, value in score_metric_with_weight_dict.items() if key in self.metric_dict[type])
  701. score_type_dict[type] = round(type_score, 2) if type_score < 100 else 100
  702. score_type_with_weight_dict = {key: score_type_dict[key] * self.weight_type_dict[key] for key in
  703. score_type_dict}
  704. score_safe = sum(score_type_with_weight_dict.values())
  705. else: # 动态客观赋权
  706. self.weight_list = cal_weight_from_80(score_metric)
  707. self.weight_dict = {key: value for key, value in zip(self.metric_list, self.weight_list)}
  708. score_safe = cal_score_with_priority(score_metric, self.weight_list, self.priority_list)
  709. for type in self.type_list:
  710. type_weight = sum(value for key, value in self.weight_dict.items() if key in self.metric_dict[type])
  711. for key, value in self.weight_dict.items():
  712. if key in self.metric_dict[type]:
  713. # self.weight_dict[key] = round(value / type_weight, 4)
  714. self.weight_dict[key] = value / type_weight
  715. type_score_metric = [value for key, value in score_metric_dict.items() if key in self.metric_dict[type]]
  716. type_weight_list = [value for key, value in self.weight_dict.items() if key in self.metric_dict[type]]
  717. type_priority_list = [value for key, value in self.priority_dict.items() if
  718. key in self.metric_dict[type]]
  719. type_score = cal_score_with_priority(type_score_metric, type_weight_list, type_priority_list)
  720. score_type_dict[type] = round(type_score, 2) if type_score < 100 else 100
  721. for key in self.weight_dict:
  722. self.weight_dict[key] = round(self.weight_dict[key], 4)
  723. score_type = list(score_type_dict.values())
  724. self.weight_type_list = cal_weight_from_80(score_type)
  725. self.weight_type_dict = {key: value for key, value in zip(self.type_list, self.weight_type_list)}
  726. score_safe = round(score_safe, 2)
  727. # score_type = [round(x, 2) for key, x in score_type_dict.items()]
  728. # score_metric = [round(x, 2) for key, x in score_metric_dict.items()]
  729. print("安全性各指标基准值:", self.optimal_list)
  730. print(f"安全性得分为:{score_safe:.2f}分。")
  731. print(f"安全性各类型得分为:{score_type_dict}。")
  732. print(f"安全性各指标得分为:{score_metric_dict}。")
  733. # return score_safe, score_type, score_metric
  734. return score_safe, score_type_dict, score_metric_dict
  735. # def zip_time_pairs(self, zip_list, upper_limit=9999):
  736. # zip_time_pairs = zip(self.time_list, zip_list)
  737. # zip_vs_time = [[x, upper_limit if y > upper_limit else y] for x, y in zip_time_pairs if not math.isnan(y)]
  738. # return zip_vs_time
  739. def zip_time_pairs(self, zip_list):
  740. zip_time_pairs = zip(self.time_list, zip_list)
  741. zip_vs_time = [[x, "" if math.isnan(y) else y] for x, y in zip_time_pairs]
  742. return zip_vs_time
  743. def _get_weight_distribution(self, dimension):
  744. # get weight distribution
  745. weight_distribution = {}
  746. weight_distribution["name"] = self.config.dimension_name[dimension]
  747. for type in self.type_list:
  748. type_weight_indexes_dict = {key: f"{self.name_dict[key]}({value * 100:.2f}%)" for key, value in
  749. self.weight_dict.items() if
  750. key in self.metric_dict[type]}
  751. weight_distribution_type = {
  752. "weight": f"{self.type_name_dict[type]}({self.weight_type_dict[type] * 100:.2f}%)",
  753. "indexes": type_weight_indexes_dict
  754. }
  755. weight_distribution[type] = weight_distribution_type
  756. return weight_distribution
  757. def safe_weight_distribution(self):
  758. # get weight distribution
  759. weight_distribution = {}
  760. weight_distribution["name"] = "安全性"
  761. if "safeTime" in self.type_list:
  762. time_weight_indexes_dict = {key: f"{key}({value * 100:.2f}%)" for key, value in self.weight_dict.items() if
  763. key in ['TTC', 'MTTC', 'THW']}
  764. weight_distribution_time = {
  765. "timeWeight": f"时间指标({self.weight_type_dict['safeTime'] * 100:.2f}%)",
  766. "indexes": time_weight_indexes_dict
  767. }
  768. weight_distribution["safeTime"] = weight_distribution_time
  769. if "safeDistance" in self.type_list:
  770. distance_weight_indexes_dict = {key: f"{key}({value * 100:.2f}%)" for key, value in self.weight_dict.items()
  771. if
  772. key in ['LonSD', 'LatSD']}
  773. weight_distribution_distance = {
  774. "distanceWeight": f"距离指标({self.weight_type_dict['safeDistance'] * 100:.2f}%)",
  775. "indexes": distance_weight_indexes_dict
  776. }
  777. weight_distribution["safeDistance"] = weight_distribution_distance
  778. if "safeAcceleration" in self.type_list:
  779. acceleration_weight_indexes_dict = {key: f"{key}({value * 100:.2f}%)" for key, value in
  780. self.weight_dict.items() if
  781. key in ['DRAC', 'BTN', 'STN']}
  782. weight_distribution_acceleration = {
  783. "accelerationWeight": f"加速度指标({self.weight_type_dict['safeAcceleration'] * 100:.2f}%)",
  784. "indexes": acceleration_weight_indexes_dict
  785. }
  786. weight_distribution["safeAcceleration"] = weight_distribution_acceleration
  787. if "safeProbability" in self.type_list:
  788. probability_weight_indexes_dict = {key: f"{key}({value * 100:.2f}%)" for key, value in
  789. self.weight_dict.items() if
  790. key in ['collisionRisk', 'collisionSeverity']}
  791. weight_distribution_probability = {
  792. "probabilityWeight": f"概率指标({self.weight_type_dict['safeProbability'] * 100:.2f}%)",
  793. "indexes": probability_weight_indexes_dict
  794. }
  795. weight_distribution["safeProbability"] = weight_distribution_probability
  796. return weight_distribution
  797. def normalize_dict_values(self, dictionary):
  798. # 计算字典中键的数量
  799. n = len(dictionary)
  800. # 初始化总和为0
  801. total_sum = 0
  802. # 遍历字典,对每个值进行赋值,并累加总和
  803. for key, value in dictionary.items():
  804. # 计算当前值,除了最后一个值外都四舍五入到两位小数
  805. if key != list(dictionary.keys())[-1]:
  806. new_value = round(1 / n, 2)
  807. else:
  808. # 最后一个值的计算:1减去之前所有值的和
  809. new_value = round(1 - total_sum, 2)
  810. # 更新字典的值
  811. dictionary[key] = new_value
  812. # 累加当前值到总和
  813. total_sum += new_value
  814. return dictionary
  815. def report_statistic(self):
  816. # time_list = self.data_processed.driver_ctrl_data['time_list']
  817. brakePedal_list = self.data_processed.driver_ctrl_data['brakePedal_list']
  818. throttlePedal_list = self.data_processed.driver_ctrl_data['throttlePedal_list']
  819. steeringWheel_list = self.data_processed.driver_ctrl_data['steeringWheel_list']
  820. # common parameter calculate
  821. brake_vs_time = self.zip_time_pairs(brakePedal_list)
  822. throttle_vs_time = self.zip_time_pairs(throttlePedal_list)
  823. steering_vs_time = self.zip_time_pairs(steeringWheel_list)
  824. # if len(self.obj_id_list) == 1:
  825. if self.empty_flag:
  826. # report_dict = {
  827. # "name": "安全性",
  828. # "weight": f"{self.weight * 100:.2f}%",
  829. # "weightDistribution": weight_distribution,
  830. # "score": 80,
  831. # "level": "良好",
  832. #
  833. # 'collisionRisk': self.collisionRisk,
  834. # "description1": safe_description1,
  835. # "description2": safe_description2,
  836. # "noObjectCar": True,
  837. #
  838. # "safeTime": time_dict,
  839. # "safeDistance": distance_dict,
  840. # "safeAcceleration": acceleration_dict,
  841. # "safeProbability": probability_dict
  842. #
  843. # }
  844. self.weight_dict = self.normalize_dict_values(self.weight_dict)
  845. self.weight_type_dict = self.normalize_dict_values(self.weight_type_dict)
  846. score_safe, score_type_dict, score_metric_dict = self.safe_score_new()
  847. # format score
  848. score_safe = int(score_safe) if int(score_safe) == score_safe else round(score_safe, 2)
  849. grade_safe = score_grade(score_safe)
  850. report_dict = {
  851. "name": "安全性",
  852. "weight": f"{self.weight * 100:.2f}%",
  853. "score": score_safe,
  854. "level": grade_safe,
  855. 'collisionRisk': self.collisionRisk,
  856. "noObjectCar": True,
  857. "weightDistribution": self._get_weight_distribution("safe")
  858. }
  859. # get weight distribution
  860. safe_description1 = "算法在无目标车情况下安全性表现良好,无碰撞风险;"
  861. safe_description2 = "安全性在无目标车情况下表现良好。"
  862. report_dict["description1"] = safe_description1
  863. report_dict["description2"] = safe_description2
  864. type_details_dict = {}
  865. for type in self.type_list:
  866. score_type = score_type_dict[type]
  867. grade_type = score_grade(score_type)
  868. type_dict = {
  869. "name":self.type_name_dict[type],
  870. "score": score_type,
  871. "level": grade_type,
  872. "description1": "无目标车数据可计算",
  873. "description2": "表现良好",
  874. }
  875. builtin_graph_dict = {}
  876. custom_graph_dict = {}
  877. type_dict_indexes = {}
  878. for metric in self.metric_dict[type]:
  879. type_dict_indexes[metric] = {
  880. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  881. "name": f"{self.name_dict[metric]}",
  882. "meaning": f"{self.name_dict[metric]}",
  883. "score": 80,
  884. "extremum": "-",
  885. # "range": f"[{self.optimal1_dict['TTC']}, inf)",
  886. "rate": "-"
  887. }
  888. if metric in self.bulitin_metric_list:
  889. if self.kind1_dict[metric] == -1:
  890. type_dict_indexes[metric]["range"] = f"[0, {self.optimal1_dict[metric]}]"
  891. elif self.kind1_dict[metric] == 1:
  892. type_dict_indexes[metric]["range"] = f"[{self.optimal1_dict[metric]}, inf)"
  893. elif self.kind1_dict[metric] == 0:
  894. type_dict_indexes[metric][
  895. "range"] = f"[{self.optimal1_dict[metric] * self.multiple_dict[metric][0]}, {self.optimal1_dict[metric] * self.multiple_dict[metric][1]}]"
  896. else:
  897. if self.custom_param_dict[metric]['kind'][0] == -1:
  898. type_dict_indexes[metric][
  899. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  900. elif self.custom_param_dict[metric]['kind'][0] == 1:
  901. type_dict_indexes[metric][
  902. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  903. elif self.custom_param_dict[metric]['kind'][0] == 0:
  904. type_dict_indexes[metric][
  905. "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]}]"
  906. type_dict["indexes"] = type_dict_indexes
  907. type_dict["builtin"] = builtin_graph_dict
  908. type_dict["custom"] = custom_graph_dict
  909. type_details_dict[type] = type_dict
  910. report_dict["details"] = type_details_dict
  911. report_dict['commonData'] = {
  912. "per": {
  913. "name": "脚刹/油门踏板开度(百分比)",
  914. "legend": ["刹车踏板开度", "油门踏板开度"],
  915. "data": [brake_vs_time, throttle_vs_time]
  916. },
  917. "ang": {
  918. "name": "方向盘转角(角度°)",
  919. "data": steering_vs_time
  920. }
  921. # "spe": {
  922. # "name": "速度(km/h)",
  923. # "legend": ["自车速度", "目标车速度", "自车与目标车相对速度"],
  924. # "data": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  925. #
  926. # },
  927. # "acc": {
  928. # "name": "加速度(m/s²)",
  929. # "legend": ["横向加速度", "纵向加速度"],
  930. # "data": [lat_acc_vs_time, lon_acc_vs_time]
  931. #
  932. # },
  933. # "dis": {
  934. # "name": "前车距离(m)",
  935. # "data": distance_vs_time
  936. # }
  937. }
  938. return report_dict
  939. # report_dict = {
  940. # "name": "安全性",
  941. # "weight": f"{self.weight * 100:.2f}%",
  942. # "weightDistribution": weight_distribution,
  943. # "score": score_safe,
  944. # "level": grade_safe,
  945. # 'collisionRisk': self.collisionRisk,
  946. # "description1": safe_description1,
  947. # "description2": safe_description2,
  948. # "noObjectCar": False,
  949. #
  950. # "safeTime": time_dict,
  951. # "safeDistance": distance_dict,
  952. # "safeAcceleration": acceleration_dict,
  953. # "safeProbability": probability_dict,
  954. #
  955. # "speData": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time],
  956. # "accData": [lat_acc_vs_time, lon_acc_vs_time],
  957. #
  958. # }
  959. report_dict = {
  960. "name": "安全性",
  961. "weight": f"{self.weight * 100:.2f}%",
  962. 'collisionRisk': self.collisionRisk,
  963. "noObjectCar": False,
  964. }
  965. upper_limit = 40
  966. times_upper = 2
  967. len_time = len(self.time_list)
  968. duration = self.time_list[-1]
  969. score_safe, score_type_dict, score_metric_dict = self.safe_score_new()
  970. # format score
  971. score_safe = int(score_safe) if int(score_safe) == score_safe else round(score_safe, 2)
  972. grade_safe = score_grade(score_safe)
  973. report_dict["score"] = score_safe
  974. report_dict["level"] = grade_safe
  975. # get weight distribution
  976. report_dict['weightDistribution'] = self._get_weight_distribution("safe")
  977. # speData
  978. ego_speed_list = self.ego_df['v'].values.tolist()
  979. ego_speed_vs_time = self.zip_time_pairs(ego_speed_list)
  980. obj_id = 2
  981. obj_df = self.df[self.df['playerId'] == obj_id]
  982. obj_speed_list = obj_df['v'].values.tolist()
  983. obj_speed_vs_time = self.zip_time_pairs(obj_speed_list)
  984. rel_speed_list = obj_df['vrel_projection_in_dist'].values.tolist()
  985. rel_speed_vs_time = self.zip_time_pairs(rel_speed_list)
  986. # accData
  987. lon_acc_list = self.ego_df['lon_acc'].values.tolist()
  988. lon_acc_vs_time = self.zip_time_pairs(lon_acc_list)
  989. lat_acc_list = self.ego_df['lat_acc'].values.tolist()
  990. lat_acc_vs_time = self.zip_time_pairs(lat_acc_list)
  991. # disData
  992. distance_list = obj_df['dist'].values.tolist()
  993. distance_vs_time = self.zip_time_pairs(distance_list)
  994. # report_dict["speData"] = [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  995. # report_dict["accData"] = [lat_acc_vs_time, lon_acc_vs_time]
  996. # report_dict["disData"] = distance_vs_time
  997. # ttcData
  998. ttc_list = obj_df['TTC'].values.tolist()
  999. ttc_list = [9999 if math.isinf(x) else x for x in ttc_list]
  1000. ttc_vs_time = self.zip_time_pairs(ttc_list)
  1001. # for description
  1002. good_type_list = []
  1003. bad_type_list = []
  1004. # good_metric_list = []
  1005. # bad_metric_list = []
  1006. # str for description
  1007. # str_over_optimal = ""
  1008. safe_over_optimal_dict = {}
  1009. type_details_dict = {}
  1010. for type in self.type_list:
  1011. if type == "safeTime":
  1012. time_dict = {
  1013. "name": self.type_name_dict[type],
  1014. }
  1015. builtin_graph_dict = {}
  1016. custom_graph_dict = {}
  1017. # ------------------------------
  1018. bad_type_list.append(type) if score_type_dict[type] < 80 else good_type_list.append(type)
  1019. # time metric dict
  1020. score_time = score_type_dict['safeTime']
  1021. grade_time = score_grade(score_time)
  1022. time_dict["score"] = score_time
  1023. time_dict["level"] = grade_time
  1024. # safeTime description
  1025. unsafe_time_type_list = [key for key, value in score_metric_dict.items() if
  1026. (key in self.metric_dict[type]) and (value < 80)]
  1027. safe_time_type_list = [key for key, value in score_metric_dict.items() if
  1028. (key in self.metric_dict[type]) and (value >= 80)]
  1029. str_time_over_optimal = ''
  1030. str_time_over_optimal_time = ''
  1031. if not unsafe_time_type_list:
  1032. str_safe_time_type = string_concatenate(safe_time_type_list)
  1033. time_description1 = f'{str_safe_time_type}指标均表现良好'
  1034. time_description2 = f'{str_safe_time_type}指标均在合理范围内,表现良好'
  1035. else:
  1036. for metric in unsafe_time_type_list:
  1037. if metric in self.bulitin_metric_list:
  1038. metric_over_optimal = ((self.optimal1_dict[metric] - self.most_dangerous[metric]) /
  1039. self.optimal1_dict[metric]) * 100
  1040. str_time_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%,'
  1041. metric_over_optimal_time = (1 - self.pass_percent[metric]) * duration * self.df[
  1042. metric].count() / len_time
  1043. str_time_over_optimal_time += f'{metric}指标共有{metric_over_optimal_time:.2f}秒超出合理范围;'
  1044. else:
  1045. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] -
  1046. self.custom_data[metric]["value"][0]) /
  1047. self.custom_param_dict[metric]['optimal'][0]) * 100
  1048. str_time_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%;'
  1049. str_time_over_optimal = str_time_over_optimal[:-1]
  1050. str_time_over_optimal_time = str_time_over_optimal_time[:-1]
  1051. str_safe_time_type = string_concatenate(safe_time_type_list)
  1052. str_unsafe_time_type = string_concatenate(unsafe_time_type_list)
  1053. if not safe_time_type_list:
  1054. time_description1 = f"{str_unsafe_time_type}指标表现不佳,{str_time_over_optimal}"
  1055. time_description2 = f"{str_time_over_optimal_time},算法应加强在该时间段对跟车距离的控制"
  1056. else:
  1057. time_description1 = f"{str_safe_time_type}指标表现良好,{str_unsafe_time_type}指标表现不佳,{str_time_over_optimal}"
  1058. time_description2 = f"{str_safe_time_type}指标均在合理范围内,表现良好,{str_time_over_optimal_time},算法应加强在该时间段对跟车距离的控制"
  1059. time_dict["description1"] = replace_key_with_value(time_description1, self.name_dict)
  1060. time_dict["description2"] = replace_key_with_value(time_description2, self.name_dict)
  1061. safe_over_optimal_dict['safeTime'] = str_time_over_optimal_time
  1062. # safeTime extremum
  1063. time_dict_indexes = {}
  1064. if "TTC" in self.metric_list:
  1065. self.unsafe_time_ttc_df_statistic(obj_df)
  1066. if "MTTC" in self.metric_list:
  1067. self.unsafe_time_mttc_df_statistic(obj_df)
  1068. if "THW" in self.metric_list:
  1069. self.unsafe_time_thw_df_statistic(obj_df)
  1070. unsafe_time_df = self.unsafe_time_df.copy()
  1071. unsafe_time_df['type'] = "origin"
  1072. unsafe_time_slices = unsafe_time_df.to_dict('records')
  1073. for metric in self.metric_dict[type]:
  1074. if metric in self.bulitin_metric_list:
  1075. metric_extremum = upper_limit if self.most_dangerous[metric] > upper_limit else \
  1076. self.most_dangerous[
  1077. metric]
  1078. metric_list = obj_df[metric].values.tolist()
  1079. metric_vs_time = self.zip_time_pairs(metric_list)
  1080. unsafe_metric_df = self.unsafe_time_df.copy()
  1081. unsafe_metric_df.loc[unsafe_metric_df['type'] != metric, 'type'] = "origin"
  1082. unsafe_metric_df.loc[unsafe_metric_df['type'] == metric, 'type'] = "time"
  1083. unsafe_metric_slices = unsafe_metric_df.to_dict('records')
  1084. time_dict_indexes[metric] = {
  1085. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1086. "name": f"{self.name_dict[metric]}",
  1087. "meaning": f"{self.name_dict[metric]}",
  1088. "score": score_metric_dict[metric],
  1089. "extremum": f'{metric_extremum:.2f}',
  1090. "range": f"[{self.optimal1_dict[metric]}, inf)",
  1091. "rate": str(
  1092. int(self.pass_percent[metric] * 100) if int(self.pass_percent[metric] * 100) ==
  1093. self.pass_percent[metric] * 100 else round(
  1094. self.pass_percent[metric] * 100, 2)) + '%'
  1095. }
  1096. if metric != 'TTC': # TTC in commonData
  1097. metric_data = {
  1098. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1099. "name": f"{self.name_dict[metric]}",
  1100. "data": metric_vs_time,
  1101. "range": f"[{self.optimal1_dict[metric]}, inf)",
  1102. # "markLine": unsafe_metric_slices,
  1103. # "markLine2": [self.optimal1_dict[metric]]
  1104. }
  1105. builtin_graph_dict[metric] = metric_data
  1106. else:
  1107. value = self.custom_data[metric]["value"][0]
  1108. metric_extremum = upper_limit if value > upper_limit else value
  1109. time_dict_indexes[metric] = {
  1110. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1111. "name": f"{self.name_dict[metric]}",
  1112. "meaning": f"{self.name_dict[metric]}",
  1113. "score": score_metric_dict[metric],
  1114. "extremum": f'{metric_extremum:.2f}',
  1115. # "range": f"[{self.optimal1_dict[metric]}, inf)",
  1116. "rate": "-"
  1117. }
  1118. if self.custom_param_dict[metric]['kind'][0] == -1:
  1119. time_dict_indexes[metric][
  1120. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1121. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1122. time_dict_indexes[metric][
  1123. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1124. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1125. time_dict_indexes[metric][
  1126. "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]}]"
  1127. metric_data = self.custom_data[metric]["reportData"]
  1128. custom_graph_dict[metric] = metric_data
  1129. time_dict["indexes"] = time_dict_indexes
  1130. time_dict["builtin"] = builtin_graph_dict
  1131. time_dict["custom"] = custom_graph_dict
  1132. # time_dict["disData"] = distance_vs_time
  1133. # time_dict["disMarkLine"] = unsafe_time_slices
  1134. # time_dict = {
  1135. # "score": score_time,
  1136. # "level": grade_time,
  1137. # "description1": time_description1,
  1138. # "description2": time_description2,
  1139. # "indexes": time_dict_indexes,
  1140. #
  1141. # "disData": distance_vs_time,
  1142. # "disMarkLine": unsafe_time_slices,
  1143. #
  1144. # "TTC": ttc_data,
  1145. # "MTTC": mttc_data,
  1146. # "THW": thw_data
  1147. # }
  1148. type_details_dict[type] = time_dict
  1149. elif type == "safeDistance":
  1150. distance_dict = {
  1151. "name": self.type_name_dict[type],
  1152. }
  1153. builtin_graph_dict = {}
  1154. custom_graph_dict = {}
  1155. bad_type_list.append(type) if score_type_dict[type] < 80 else good_type_list.append(type)
  1156. # ------------------------------
  1157. # distance metric dict
  1158. score_distance = score_type_dict['safeDistance']
  1159. grade_distance = score_grade(score_distance)
  1160. distance_dict["score"] = score_distance
  1161. distance_dict["level"] = grade_distance
  1162. # safeDistance description
  1163. unsafe_dist_type_list = [key for key, value in score_metric_dict.items() if
  1164. (key in self.metric_dict[type]) and (value < 80)]
  1165. safe_dist_type_list = [key for key, value in score_metric_dict.items() if
  1166. (key in self.metric_dict[type]) and (value >= 80)]
  1167. str_dist_over_optimal = ''
  1168. str_dist_over_optimal_time = ''
  1169. if not unsafe_dist_type_list:
  1170. str_safe_dist_type = string_concatenate(safe_dist_type_list)
  1171. distance_description1 = f"{str_safe_dist_type}指标均表现良好"
  1172. distance_description2 = f"{str_safe_dist_type}指标均在合理范围内,表现良好"
  1173. else:
  1174. for metric in unsafe_dist_type_list:
  1175. if metric in self.bulitin_metric_list:
  1176. metric_over_optimal = ((self.optimal1_dict[metric] - self.most_dangerous[metric]) /
  1177. self.optimal1_dict[metric]) * 100
  1178. str_dist_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%,'
  1179. metric_over_optimal_time = (1 - self.pass_percent[metric]) * duration * self.df[
  1180. metric].count() / len_time
  1181. str_dist_over_optimal_time += f'{metric}指标共有{metric_over_optimal_time:.2f}秒超出合理范围;'
  1182. else:
  1183. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] -
  1184. self.custom_data[metric]["value"][0]) /
  1185. self.custom_param_dict[metric]['optimal'][0]) * 100
  1186. str_dist_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%;'
  1187. str_dist_over_optimal = str_dist_over_optimal[:-1]
  1188. str_dist_over_optimal_time = str_dist_over_optimal_time[:-1]
  1189. str_safe_dist_type = string_concatenate(safe_dist_type_list)
  1190. str_unsafe_dist_type = string_concatenate(unsafe_dist_type_list)
  1191. if not safe_dist_type_list:
  1192. distance_description1 = f"{str_unsafe_dist_type}指标表现不佳,{str_dist_over_optimal}"
  1193. distance_description2 = f"{str_dist_over_optimal_time}"
  1194. else:
  1195. distance_description1 = f"{str_safe_dist_type}指标表现良好,{str_unsafe_dist_type}指标表现不佳,{str_dist_over_optimal}"
  1196. distance_description2 = f"{str_safe_dist_type}指标均在合理范围内,表现良好,{str_dist_over_optimal_time}"
  1197. distance_dict["description1"] = replace_key_with_value(distance_description1, self.name_dict)
  1198. distance_dict["description2"] = replace_key_with_value(distance_description2, self.name_dict)
  1199. safe_over_optimal_dict['safeDistance'] = str_dist_over_optimal_time
  1200. # safeDistance extremum
  1201. distance_dict_indexes = {}
  1202. if "LonSD" in self.metric_list:
  1203. self.unsafe_distance_lonsd_df_statistic(obj_df)
  1204. if "LatSD" in self.metric_list:
  1205. self.unsafe_distance_latsd_df_statistic(obj_df)
  1206. unsafe_dist_df = self.unsafe_dist_df.copy()
  1207. unsafe_dist_df['type'] = "origin"
  1208. # unsafe_dist_slices = unsafe_dist_df.to_dict('records')
  1209. for metric in self.metric_dict[type]:
  1210. if metric in self.bulitin_metric_list:
  1211. metric_extremum = upper_limit if self.most_dangerous[metric] > upper_limit else \
  1212. self.most_dangerous[metric]
  1213. metric_list = obj_df[metric].values.tolist()
  1214. metric_vs_time = self.zip_time_pairs(metric_list)
  1215. unsafe_metric_df = self.unsafe_dist_df.copy().dropna()
  1216. unsafe_metric_df.loc[unsafe_metric_df['type'] != metric, 'type'] = "origin"
  1217. unsafe_metric_df.loc[unsafe_metric_df['type'] == metric, 'type'] = "distance"
  1218. unsafe_metric_slices = unsafe_metric_df.to_dict('records')
  1219. distance_dict_indexes[metric] = {
  1220. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1221. "name": f"{self.name_dict[metric]}",
  1222. "meaning": f"{self.name_dict[metric]}",
  1223. "score": score_metric_dict[metric],
  1224. "extremum": f'{metric_extremum:.2f}',
  1225. "range": f"[{self.optimal1_dict[metric]}, inf)",
  1226. "rate": str(
  1227. int(self.pass_percent[metric] * 100) if int(self.pass_percent[metric] * 100) ==
  1228. self.pass_percent[metric] * 100 else round(
  1229. self.pass_percent[metric] * 100, 2)) + '%'
  1230. }
  1231. metric_data = {
  1232. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1233. "name": f"{self.name_dict[metric]}",
  1234. "data": metric_vs_time,
  1235. "range": f"[{self.optimal1_dict[metric]}, inf)",
  1236. # "markLine": unsafe_metric_slices,
  1237. # "markLine2": [self.optimal1_dict[metric]]
  1238. }
  1239. builtin_graph_dict[metric] = metric_data
  1240. else:
  1241. value = self.custom_data[metric]["value"][0]
  1242. metric_extremum = upper_limit if value > upper_limit else value
  1243. distance_dict_indexes[metric] = {
  1244. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1245. "name": f"{self.name_dict[metric]}",
  1246. "meaning": f"{self.name_dict[metric]}",
  1247. "score": score_metric_dict[metric],
  1248. "extremum": f'{metric_extremum:.2f}',
  1249. # "range": f"[{self.optimal1_dict[metric]}, inf)",
  1250. "rate": "-"
  1251. }
  1252. if self.custom_param_dict[metric]['kind'][0] == -1:
  1253. distance_dict_indexes[metric][
  1254. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1255. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1256. distance_dict_indexes[metric][
  1257. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1258. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1259. distance_dict_indexes[metric][
  1260. "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]}]"
  1261. metric_data = self.custom_data[metric]["reportData"]
  1262. custom_graph_dict[metric] = metric_data
  1263. distance_dict["indexes"] = distance_dict_indexes
  1264. distance_dict["builtin"] = builtin_graph_dict
  1265. distance_dict["custom"] = custom_graph_dict
  1266. type_details_dict[type] = distance_dict
  1267. # distance_dict = {
  1268. # "score": score_distance,
  1269. # "level": grade_distance,
  1270. # "description1": distance_description1,
  1271. # "description2": distance_description2,
  1272. # "indexes": distance_dict_indexes,
  1273. #
  1274. # "LonSD": lonsd_data,
  1275. # "LatSD": latsd_data
  1276. # }
  1277. elif type == "safeAcceleration":
  1278. acceleration_dict = {
  1279. "name": self.type_name_dict[type],
  1280. }
  1281. builtin_graph_dict = {}
  1282. custom_graph_dict = {}
  1283. bad_type_list.append(type) if score_type_dict[type] < 80 else good_type_list.append(type)
  1284. # ------------------------------
  1285. # acceleration metric dict
  1286. score_acceleration = score_type_dict['safeAcceleration']
  1287. grade_acceleration = score_grade(score_acceleration)
  1288. acceleration_dict["score"] = score_acceleration
  1289. acceleration_dict["level"] = grade_acceleration
  1290. # safeAcceleration data for graph
  1291. lat_dist_list = obj_df['lat_d'].values.tolist()
  1292. lat_dist_vs_time = self.zip_time_pairs(lat_dist_list)
  1293. lon_dist_list = obj_df['lon_d'].values.tolist()
  1294. lon_dist_vs_time = self.zip_time_pairs(lon_dist_list)
  1295. # safeAcceleration description
  1296. unsafe_acce_type_list = [key for key, value in score_metric_dict.items() if
  1297. (key in self.metric_dict[type]) and (value < 80)]
  1298. safe_acce_type_list = [key for key, value in score_metric_dict.items() if
  1299. (key in self.metric_dict[type]) and (value >= 80)]
  1300. str_acce_over_optimal = ''
  1301. str_acce_over_optimal_time = ''
  1302. if not unsafe_acce_type_list:
  1303. str_safe_acce_type = string_concatenate(safe_acce_type_list)
  1304. acceleration_description1 = f"{str_safe_acce_type}指标均表现良好"
  1305. acceleration_description2 = f"{str_safe_acce_type}指标均在合理范围内,表现良好"
  1306. else:
  1307. for metric in unsafe_acce_type_list:
  1308. if metric in self.bulitin_metric_list:
  1309. metric_over_optimal = ((self.optimal1_dict[metric] - self.most_dangerous[metric]) /
  1310. self.optimal1_dict[metric]) * 100
  1311. str_acce_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%,'
  1312. metric_over_optimal_time = (1 - self.pass_percent[metric]) * duration * self.df[
  1313. metric].count() / len_time
  1314. str_acce_over_optimal_time += f'{metric}指标共有{metric_over_optimal_time:.2f}秒超出合理范围;'
  1315. else:
  1316. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] -
  1317. self.custom_data[metric]["value"][0]) /
  1318. self.custom_param_dict[metric]['optimal'][0]) * 100
  1319. str_acce_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%;'
  1320. str_acce_over_optimal = str_acce_over_optimal[:-1]
  1321. str_acce_over_optimal_time = str_acce_over_optimal_time[:-1]
  1322. str_safe_acce_type = string_concatenate(safe_acce_type_list)
  1323. str_unsafe_acce_type = string_concatenate(unsafe_acce_type_list)
  1324. if not safe_acce_type_list:
  1325. acceleration_description1 = f"{str_unsafe_acce_type}指标表现不佳,{str_acce_over_optimal}"
  1326. acceleration_description2 = f"{str_acce_over_optimal_time}"
  1327. else:
  1328. acceleration_description1 = f"{str_safe_acce_type}指标表现良好,{str_unsafe_acce_type}指标表现不佳,{str_acce_over_optimal}"
  1329. acceleration_description2 = f"{str_safe_acce_type}指标均在合理范围内,表现良好,{str_acce_over_optimal_time}"
  1330. acceleration_dict["description1"] = replace_key_with_value(acceleration_description1, self.name_dict)
  1331. acceleration_dict["description2"] = replace_key_with_value(acceleration_description2, self.name_dict)
  1332. safe_over_optimal_dict['safeAcceleration'] = str_acce_over_optimal_time
  1333. # safeAcceleration extremum
  1334. acceleration_dict_indexes = {}
  1335. if "DRAC" in self.metric_list:
  1336. self.unsafe_acceleration_drac_df_statistic(obj_df)
  1337. if "BTN" in self.metric_list:
  1338. self.unsafe_acceleration_btn_df_statistic(obj_df)
  1339. if "STN" in self.metric_list:
  1340. self.unsafe_acceleration_stn_df_statistic(obj_df)
  1341. unsafe_acce_drac_df = self.unsafe_acce_drac_df.copy().dropna()
  1342. unsafe_acce_drac_df['type'] = "origin"
  1343. unsafe_acce_drac_slices = unsafe_acce_drac_df.to_dict('records')
  1344. unsafe_acce_xtn_df = self.unsafe_acce_xtn_df.copy()
  1345. unsafe_acce_xtn_df['type'] = "origin"
  1346. unsafe_acce_xtn_slices = unsafe_acce_xtn_df.to_dict('records')
  1347. for metric in self.metric_dict[type]:
  1348. if metric in self.bulitin_metric_list:
  1349. metric_extremum = upper_limit if self.most_dangerous[metric] > upper_limit else \
  1350. self.most_dangerous[metric]
  1351. metric_list = obj_df[metric].values.tolist()
  1352. metric_vs_time = self.zip_time_pairs(metric_list)
  1353. if metric == "DRAC":
  1354. unsafe_metric_df = self.unsafe_acce_drac_df.copy().dropna()
  1355. else:
  1356. unsafe_metric_df = self.unsafe_acce_xtn_df.copy().dropna()
  1357. unsafe_metric_df.loc[unsafe_metric_df['type'] != metric, 'type'] = "origin"
  1358. unsafe_metric_df.loc[unsafe_metric_df['type'] == metric, 'type'] = "time"
  1359. unsafe_metric_slices = unsafe_metric_df.to_dict('records')
  1360. acceleration_dict_indexes[metric] = {
  1361. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1362. "name": f"{self.name_dict[metric]}",
  1363. "meaning": f"{self.name_dict[metric]}",
  1364. "score": score_metric_dict[metric],
  1365. "extremum": f'{metric_extremum:.2f}',
  1366. "range": f"[0, {self.optimal1_dict[metric]}]",
  1367. "rate": str(
  1368. int(self.pass_percent[metric] * 100) if int(self.pass_percent[metric] * 100) ==
  1369. self.pass_percent[metric] * 100 else round(
  1370. self.pass_percent[metric] * 100, 2)) + '%'
  1371. }
  1372. metric_data = {
  1373. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1374. "name": f"{self.name_dict[metric]}",
  1375. "data": metric_vs_time,
  1376. "range": f"[0, {self.optimal1_dict[metric]}]",
  1377. # "markLine": unsafe_metric_slices,
  1378. # "markLine2": [self.optimal1_dict[metric]]
  1379. }
  1380. builtin_graph_dict[metric] = metric_data
  1381. else:
  1382. value = self.custom_data[metric]["value"][0]
  1383. metric_extremum = upper_limit if value > upper_limit else value
  1384. acceleration_dict_indexes[metric] = {
  1385. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1386. "name": f"{self.name_dict[metric]}",
  1387. "meaning": f"{self.name_dict[metric]}",
  1388. "score": score_metric_dict[metric],
  1389. "extremum": f'{metric_extremum:.2f}',
  1390. # "range": f"[{self.optimal1_dict[metric]}, inf)",
  1391. "rate": "-"
  1392. }
  1393. if self.custom_param_dict[metric]['kind'][0] == -1:
  1394. acceleration_dict_indexes[metric][
  1395. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1396. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1397. acceleration_dict_indexes[metric][
  1398. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1399. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1400. acceleration_dict_indexes[metric][
  1401. "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]}]"
  1402. metric_data = self.custom_data[metric]["reportData"]
  1403. custom_graph_dict[metric] = metric_data
  1404. acceleration_dict["indexes"] = acceleration_dict_indexes
  1405. acceleration_dict["builtin"] = builtin_graph_dict
  1406. acceleration_dict["custom"] = custom_graph_dict
  1407. # acceleration_dict["disData"] = distance_vs_time
  1408. # acceleration_dict["disMarkLine"] = unsafe_acce_drac_slices
  1409. # acceleration_dict["dis2Data"] = [lat_dist_vs_time, lon_dist_vs_time]
  1410. # acceleration_dict["dis2MarkLine"] = unsafe_acce_xtn_slices
  1411. type_details_dict[type] = acceleration_dict
  1412. # acceleration_dict = {
  1413. # "score": score_acceleration,
  1414. # "level": grade_acceleration,
  1415. # "description1": acceleration_description1,
  1416. # "description2": acceleration_description2,
  1417. # "indexes": acceleration_dict_indexes,
  1418. #
  1419. # "disData": distance_vs_time,
  1420. # "disMarkLine": unsafe_acce_drac_slices,
  1421. #
  1422. # "dis2Data": [lat_dist_vs_time, lon_dist_vs_time],
  1423. # "dis2MarkLine": unsafe_acce_xtn_slices,
  1424. #
  1425. # "DRAC": drac_data,
  1426. # "BTN": btn_data,
  1427. # "STN": stn_data
  1428. # }
  1429. elif type == "safeProbability":
  1430. probability_dict = {
  1431. "name": self.type_name_dict[type],
  1432. }
  1433. builtin_graph_dict = {}
  1434. custom_graph_dict = {}
  1435. bad_type_list.append(type) if score_type_dict[type] < 80 else good_type_list.append(type)
  1436. # ------------------------------
  1437. # probability metric dict
  1438. score_probability = score_type_dict['safeProbability']
  1439. grade_probability = score_grade(score_probability)
  1440. probability_dict["score"] = score_probability
  1441. probability_dict["level"] = grade_probability
  1442. # safeProbability description
  1443. unsafe_prob_type_list = [key for key, value in score_metric_dict.items() if
  1444. (key in self.metric_dict[type]) and (value < 80)]
  1445. safe_prob_type_list = [key for key, value in score_metric_dict.items() if
  1446. (key in self.metric_dict[type]) and (value >= 80)]
  1447. str_prob_over_optimal = ''
  1448. str_prob_over_optimal_time = ''
  1449. if not unsafe_prob_type_list:
  1450. str_safe_prob_type = string_concatenate(safe_prob_type_list)
  1451. probability_description1 = f"{str_safe_prob_type}指标均表现良好"
  1452. probability_description2 = f"{str_safe_prob_type}指标均在合理范围内,表现良好"
  1453. else:
  1454. for metric in unsafe_prob_type_list:
  1455. if metric in self.bulitin_metric_list:
  1456. metric_over_optimal = ((self.optimal1_dict[metric] - self.most_dangerous[metric]) /
  1457. self.optimal1_dict[metric]) * 100
  1458. str_prob_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%,'
  1459. metric_over_optimal_time = (1 - self.pass_percent[metric]) * duration * self.df[
  1460. metric].count() / len_time
  1461. str_prob_over_optimal_time += f'{metric}指标共有{metric_over_optimal_time:.2f}秒超出合理范围;'
  1462. else:
  1463. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] -
  1464. self.custom_data[metric]["value"][0]) /
  1465. self.custom_param_dict[metric]['optimal'][0]) * 100
  1466. str_prob_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%;'
  1467. str_prob_over_optimal = str_prob_over_optimal[:-1]
  1468. str_prob_over_optimal_time = str_prob_over_optimal_time[:-1]
  1469. str_safe_prob_type = string_concatenate(safe_prob_type_list)
  1470. str_unsafe_prob_type = string_concatenate(unsafe_prob_type_list)
  1471. if not safe_prob_type_list:
  1472. probability_description1 = f"{str_unsafe_prob_type}指标表现不佳,{str_prob_over_optimal}"
  1473. probability_description2 = f"{str_prob_over_optimal_time}"
  1474. else:
  1475. probability_description1 = f"{str_safe_prob_type}指标表现良好,{str_unsafe_prob_type}指标表现不佳,{str_prob_over_optimal}"
  1476. probability_description2 = f"{str_safe_prob_type}指标均在合理范围内,表现良好,{str_prob_over_optimal_time}"
  1477. probability_dict["description1"] = replace_key_with_value(probability_description1, self.name_dict)
  1478. probability_dict["description2"] = replace_key_with_value(probability_description2, self.name_dict)
  1479. safe_over_optimal_dict['safeProbability'] = str_prob_over_optimal_time
  1480. # safeProbability extremum
  1481. probability_dict_indexes = {}
  1482. if "collisionRisk" in self.metric_list:
  1483. self.unsafe_probability_cr_df_statistic(obj_df)
  1484. if "collisionSeverity" in self.metric_list:
  1485. self.unsafe_probability_cs_df_statistic(obj_df)
  1486. unsafe_prob_df = self.unsafe_prob_df.copy().dropna()
  1487. unsafe_prob_df['type'] = "origin"
  1488. unsafe_prob_slices = unsafe_prob_df.to_dict('records')
  1489. for metric in self.metric_dict[type]:
  1490. if metric in self.bulitin_metric_list:
  1491. metric_extremum = upper_limit if self.most_dangerous[metric] > upper_limit else \
  1492. self.most_dangerous[
  1493. metric]
  1494. metric_list = obj_df[metric].values.tolist()
  1495. metric_vs_time = self.zip_time_pairs(metric_list)
  1496. unsafe_metric_df = self.unsafe_prob_df.copy().dropna()
  1497. unsafe_metric_df.loc[unsafe_metric_df['type'] != metric, 'type'] = "origin"
  1498. unsafe_metric_df.loc[unsafe_metric_df['type'] == metric, 'type'] = "time"
  1499. unsafe_metric_slices = unsafe_metric_df.to_dict('records')
  1500. probability_dict_indexes[metric] = {
  1501. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1502. "name": f"{self.name_dict[metric]}",
  1503. "meaning": f"{self.name_dict[metric]}",
  1504. "score": score_metric_dict[metric],
  1505. "extremum": f'{metric_extremum:.2f}',
  1506. "range": f"[0, {self.optimal1_dict[metric]}]",
  1507. "rate": str(
  1508. int(self.pass_percent[metric] * 100) if int(self.pass_percent[metric] * 100) ==
  1509. self.pass_percent[metric] * 100 else round(
  1510. self.pass_percent[metric] * 100, 2)) + '%'
  1511. }
  1512. metric_data = {
  1513. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1514. "name": f"{self.name_dict[metric]}",
  1515. "data": metric_vs_time,
  1516. "range": f"[0, {self.optimal1_dict[metric]}]",
  1517. # "markLine": unsafe_metric_slices,
  1518. # "markLine2": [self.optimal1_dict[metric]]
  1519. }
  1520. builtin_graph_dict[metric] = metric_data
  1521. else:
  1522. value = self.custom_data[metric]["value"][0]
  1523. metric_extremum = upper_limit if value > upper_limit else value
  1524. probability_dict_indexes[metric] = {
  1525. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1526. "name": f"{self.name_dict[metric]}",
  1527. "meaning": f"{self.name_dict[metric]}",
  1528. "score": score_metric_dict[metric],
  1529. "extremum": f'{metric_extremum:.2f}',
  1530. # "range": f"[{self.optimal1_dict[metric]}, inf)",
  1531. "rate": "-"
  1532. }
  1533. if self.custom_param_dict[metric]['kind'][0] == -1:
  1534. probability_dict_indexes[metric][
  1535. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1536. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1537. probability_dict_indexes[metric][
  1538. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1539. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1540. probability_dict_indexes[metric][
  1541. "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]}]"
  1542. metric_data = self.custom_data[metric]["reportData"]
  1543. custom_graph_dict[metric] = metric_data
  1544. probability_dict["indexes"] = probability_dict_indexes
  1545. probability_dict["builtin"] = builtin_graph_dict
  1546. probability_dict["custom"] = custom_graph_dict
  1547. # probability_dict["ttcData"] = ttc_vs_time
  1548. # probability_dict["ttcMarkLine"] = unsafe_prob_slices
  1549. type_details_dict[type] = probability_dict
  1550. # probability_dict = {
  1551. # "score": score_probability,
  1552. # "level": grade_probability,
  1553. # "description1": probability_description1,
  1554. # "description2": probability_description2,
  1555. # "indexes": probability_dict_indexes,
  1556. #
  1557. # "ttcData": ttc_vs_time,
  1558. # "ttcMarkLine": unsafe_prob_slices,
  1559. #
  1560. # "collisionRisk": cr_data,
  1561. # "collisionSeverity": cs_data
  1562. # }
  1563. else:
  1564. bad_type_list.append(type) if score_type_dict[type] < 80 else good_type_list.append(type)
  1565. type_dict = {
  1566. "name": self.type_name_dict[type],
  1567. }
  1568. builtin_graph_dict = {}
  1569. custom_graph_dict = {}
  1570. # get score and grade
  1571. score_custom_type = score_type_dict[type]
  1572. grade_custom_type = score_grade(score_custom_type)
  1573. type_dict["score"] = score_custom_type
  1574. type_dict["level"] = grade_custom_type
  1575. # custom type description
  1576. bad_custom_metric_list = [key for key, value in score_metric_dict.items() if
  1577. (key in self.metric_dict[type]) and (value < 80)]
  1578. good_custom_metric_list = [key for key, value in score_metric_dict.items() if
  1579. (key in self.metric_dict[type]) and (value >= 80)]
  1580. str_type_over_optimal = ''
  1581. str_type_over_optimal_time = ''
  1582. if not bad_custom_metric_list:
  1583. str_safe_type_type = string_concatenate(good_custom_metric_list)
  1584. type_description1 = f'{str_safe_type_type}指标均表现良好'
  1585. type_description2 = f'{str_safe_type_type}指标均在合理范围内,表现良好'
  1586. else:
  1587. for metric in bad_custom_metric_list:
  1588. metric_over_optimal = ((self.custom_param_dict[metric]['optimal'][0] -
  1589. self.custom_data[metric]["value"][0]) /
  1590. self.custom_param_dict[metric]['optimal'][0]) * 100
  1591. str_type_over_optimal += f'{self.name_dict[metric]}极值超过合理范围{metric_over_optimal:.2f}%;'
  1592. str_type_over_optimal = str_type_over_optimal[:-1]
  1593. str_type_over_optimal_time = str_type_over_optimal_time[:-1]
  1594. str_safe_type_type = string_concatenate(good_custom_metric_list)
  1595. str_unsafe_type_type = string_concatenate(bad_custom_metric_list)
  1596. if not good_custom_metric_list:
  1597. type_description1 = f"{str_unsafe_type_type}指标表现不佳,{str_type_over_optimal}"
  1598. type_description2 = f"{str_type_over_optimal_time},算法应加强在该时间段对跟车距离的控制"
  1599. else:
  1600. type_description1 = f"{str_safe_type_type}指标表现良好,{str_unsafe_type_type}指标表现不佳,{str_type_over_optimal}"
  1601. type_description2 = f"{str_safe_type_type}指标均在合理范围内,表现良好,{str_type_over_optimal_time},算法应加强在该时间段对跟车距离的控制"
  1602. type_dict["description1"] = replace_key_with_value(type_description1, self.name_dict)
  1603. type_dict["description2"] = replace_key_with_value(type_description2, self.name_dict)
  1604. type_dict_indexes = {}
  1605. for metric in self.metric_dict[type]:
  1606. value = self.custom_data[metric]["value"][0]
  1607. metric_extremum = upper_limit if value > upper_limit else value
  1608. type_dict_indexes[metric] = {
  1609. # "name": f"{self.name_dict[metric]}({self.unit_dict[metric]})",
  1610. "name": f"{self.name_dict[metric]}",
  1611. "meaning": f"{self.name_dict[metric]}",
  1612. "score": score_metric_dict[metric],
  1613. "extremum": f'{metric_extremum:.2f}',
  1614. # "range": f"[{self.optimal1_dict[metric]}, inf)",
  1615. "rate": "-"
  1616. }
  1617. if self.custom_param_dict[metric]['kind'][0] == -1:
  1618. type_dict_indexes[metric][
  1619. "range"] = f"[0, {self.custom_param_dict[metric]['optimal'][0]}]"
  1620. elif self.custom_param_dict[metric]['kind'][0] == 1:
  1621. type_dict_indexes[metric][
  1622. "range"] = f"[{self.custom_param_dict[metric]['optimal'][0]}, inf)"
  1623. elif self.custom_param_dict[metric]['kind'][0] == 0:
  1624. type_dict_indexes[metric][
  1625. "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]}]"
  1626. metric_data = self.custom_data[metric]["reportData"]
  1627. custom_graph_dict[metric] = metric_data
  1628. type_dict["indexes"] = type_dict_indexes
  1629. type_dict["builtin"] = builtin_graph_dict
  1630. type_dict["custom"] = custom_graph_dict
  1631. type_details_dict[type] = type_dict
  1632. report_dict["details"] = type_details_dict
  1633. # good_type_list = []
  1634. # bad_type_list = []
  1635. #
  1636. # for type in self.type_list:
  1637. # bad_type_list.append(type) if any(i < 80 for key, i in score_metric_dict.items() if
  1638. # key in self.metric_dict[type]) else good_type_list.append(type)
  1639. unsafe_time = self.df['unsafe_flag'].sum() * duration / len_time
  1640. unsafe_time = round(unsafe_time, 2)
  1641. safe_over_optimal = [value for key, value in safe_over_optimal_dict.items() if value] # 解决空字符串多逗号问题
  1642. str_safe_over_optimal = ';'.join(safe_over_optimal)
  1643. if grade_safe == '优秀':
  1644. safe_description1 = '车辆在本轮测试中无碰撞风险;'
  1645. elif grade_safe == '良好':
  1646. safe_description1 = '算法在本轮测试中的表现满足设计指标要求;'
  1647. elif grade_safe == '一般':
  1648. str_unsafe_type = string_concatenate(bad_type_list)
  1649. safe_description1 = f'未满足设计指标要求。算法需要在{str_unsafe_type}上进一步优化。在仿真过程中共有{unsafe_time}s的时间处于危险状态。' \
  1650. f'在{str_unsafe_type}中,{str_safe_over_optimal};'
  1651. elif grade_safe == '较差':
  1652. str_unsafe_type = string_concatenate(bad_type_list)
  1653. safe_description1 = f'未满足设计指标要求。算法在本轮测试中有碰撞风险,需要提高算法在{str_unsafe_type}上的表现。在{str_unsafe_type}中,' \
  1654. f'{str_safe_over_optimal};'
  1655. if not bad_type_list:
  1656. safe_description2 = '安全性在各个指标上的表现俱佳。'
  1657. else:
  1658. str_unsafe_type = string_concatenate(bad_type_list)
  1659. safe_description2 = f"安全性在{str_unsafe_type}上存在严重风险,需要重点优化。"
  1660. report_dict["description1"] = replace_key_with_value(safe_description1, self.name_dict)
  1661. report_dict["description1"] = replace_key_with_value(safe_description1, self.type_name_dict)
  1662. report_dict["description2"] = replace_key_with_value(safe_description2, self.type_name_dict)
  1663. report_dict['commonData'] = {
  1664. "per": {
  1665. "name": "脚刹/油门踏板开度(百分比)",
  1666. "legend": ["刹车踏板开度", "油门踏板开度"],
  1667. "data": [brake_vs_time, throttle_vs_time]
  1668. },
  1669. "ang": {
  1670. "name": "方向盘转角(角度°)",
  1671. "data": steering_vs_time
  1672. },
  1673. "spe": {
  1674. "name": "速度(km/h)",
  1675. "legend": ["自车速度", "目标车速度", "自车与目标车相对速度"],
  1676. "data": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time]
  1677. },
  1678. "acc": {
  1679. "name": "加速度(m/s²)",
  1680. "legend": ["横向加速度", "纵向加速度"],
  1681. "data": [lat_acc_vs_time, lon_acc_vs_time]
  1682. },
  1683. "dis": {
  1684. "name": "前车距离(m)",
  1685. "data": distance_vs_time
  1686. },
  1687. "ttc": {
  1688. "name": 'TTC(m)',
  1689. "data": ttc_vs_time
  1690. }
  1691. }
  1692. # self.unsafe_df = pd.concat([self.unsafe_df, self.unsafe_time_df], ignore_index=True)
  1693. # self.unsafe_df = pd.concat([self.unsafe_df, self.unsafe_dist_df], ignore_index=True)
  1694. # self.unsafe_df = pd.concat([self.unsafe_df, self.unsafe_acce_drac_df], ignore_index=True)
  1695. # self.unsafe_df = pd.concat([self.unsafe_df, self.unsafe_acce_xtn_df], ignore_index=True)
  1696. # self.unsafe_df = pd.concat([self.unsafe_df, self.unsafe_prob_df], ignore_index=True)
  1697. self.unsafe_df = pd.concat([self.unsafe_df, self.unsafe_time_df, self.unsafe_dist_df, self.unsafe_acce_drac_df,
  1698. self.unsafe_acce_xtn_df, self.unsafe_prob_df], ignore_index=True)
  1699. unsafe_df = self.unsafe_df.copy().dropna()
  1700. unsafe_slices = unsafe_df.to_dict('records')
  1701. report_dict["commonMarkLine"] = unsafe_slices
  1702. # report_dict = {
  1703. # "name": "安全性",
  1704. # "weight": f"{self.weight * 100:.2f}%",
  1705. # "weightDistribution": weight_distribution,
  1706. # "score": score_safe,
  1707. # "level": grade_safe,
  1708. # 'collisionRisk': self.collisionRisk,
  1709. # "description1": safe_description1,
  1710. # "description2": safe_description2,
  1711. # "noObjectCar": False,
  1712. #
  1713. # "safeTime": time_dict,
  1714. # "safeDistance": distance_dict,
  1715. # "safeAcceleration": acceleration_dict,
  1716. # "safeProbability": probability_dict,
  1717. #
  1718. # "speData": [ego_speed_vs_time, obj_speed_vs_time, rel_speed_vs_time],
  1719. # "accData": [lat_acc_vs_time, lon_acc_vs_time],
  1720. #
  1721. # }
  1722. return report_dict
  1723. def get_eval_data(self):
  1724. if not self.eval_data.empty and not self.empty_flag:
  1725. df = self.eval_data[
  1726. ['simTime', 'simFrame', 'playerId', 'dist', 'lon_d', 'lat_d', 'lat_v_rel', 'lon_v_rel',
  1727. 'vrel_projection_in_dist', 'arel_projection_in_dist', 'TTC', 'MTTC', 'THW', 'LonSD', 'LatSD',
  1728. 'DRAC', 'BTN', 'STN', 'collisionSeverity', 'pr_death', 'collisionRisk']].copy()
  1729. elif 'dist' in self.eval_data.columns:
  1730. df = self.eval_data[
  1731. ['simTime', 'simFrame', 'playerId', 'dist', 'lon_d', 'lat_d']].copy()
  1732. else:
  1733. df = self.eval_data.copy()
  1734. return df