safe.py 100 KB

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