safety.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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)
  10. @Data: 2023/07/25
  11. @Last Modified: 2023/07/26
  12. @Summary: safe metrics
  13. """
  14. import sys
  15. import os
  16. import math
  17. import numpy as np
  18. import pandas as pd
  19. from pathlib import Path
  20. root_path = Path(__file__).resolve().parent.parent
  21. sys.path.append(str(root_path))
  22. from models.common.score import Score
  23. from config import config
  24. from collections import defaultdict
  25. import scipy.integrate as spi
  26. from models.common import log # 确保这个路径是正确的,或者调整它
  27. log_path = config.LOG_PATH
  28. logger = log.get_logger(log_path)
  29. class Safe(object):
  30. def __init__(self, data_processed):
  31. self.data_processed = data_processed
  32. self.df = data_processed.object_df.copy()
  33. self.ego_df = data_processed.ego_data
  34. self.obj_id_list = data_processed.obj_id_list
  35. self.metric_list = config.SAFETY_METRIC_LIST
  36. # score data
  37. self.calculated_value = {
  38. 'TTC': 1.0,
  39. 'MTTC': 1.0,
  40. 'THW': 1.0,
  41. 'LonSD': 0.0,
  42. 'LatSD': 0.0,
  43. 'DRAC': 0.0,
  44. 'BTN': 1.0,
  45. 'STN': 1.0,
  46. 'collisionRisk': 0.0,
  47. 'collisionSeverity': 0.0,
  48. }
  49. # lists of drving control info
  50. self.time_list = data_processed.driver_ctrl_data['time_list']
  51. self.frame_list = self.ego_df['simFrame'].values.tolist()
  52. self.collisionRisk = 0
  53. self.empty_flag = True
  54. # no car following scene
  55. if len(self.obj_id_list) > 1:
  56. self.unsafe_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  57. self.unsafe_time_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  58. self.unsafe_dist_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  59. # self.unsafe_acce_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  60. self.unsafe_acce_drac_df = pd.DataFrame(
  61. columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  62. self.unsafe_acce_xtn_df = pd.DataFrame(
  63. columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  64. self.unsafe_prob_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  65. self.most_dangerous = {}
  66. self.pass_percent = {}
  67. self._safe_param_cal_new()
  68. def _safe_param_cal_new(self):
  69. Tc = config.TC # 安全距离
  70. rho = config.RHO # 驾驶员制动反应时间
  71. ego_accel_max = config.EGO_ACCEL_MAX # 自车油门最大加速度
  72. obj_decel_max = config.OBJ_DECEL_MAX # 前车刹车最大减速度
  73. ego_decel_min = config.EGO_DECEL_MIN # 自车刹车最小减速度 ug
  74. ego_decel_lon_max = config.EGO_DECEL_LON_MAX
  75. ego_decel_lat_max = config.EGO_DECEL_LAT_MAX
  76. # 构建双层字典数据结构
  77. obj_dict = defaultdict(dict)
  78. # 构建字典列表,每个元素是一个字典,包含'start_time', 'end_time', 'start_frame', 'end_frame', 'type'五个键值对
  79. obj_data_dict = self.df.to_dict('records')
  80. for item in obj_data_dict:
  81. obj_dict[item['simFrame']][item['playerId']] = item
  82. df_list = []
  83. EGO_PLAYER_ID = 1
  84. # self.empty_flag = True
  85. for frame_num in self.frame_list:
  86. ego_data = obj_dict[frame_num][EGO_PLAYER_ID]
  87. v1 = ego_data['v'] # km/h to m/s
  88. x1 = ego_data['posX']
  89. y1 = ego_data['posY']
  90. h1 = ego_data['posH']
  91. len1 = ego_data['dimX']
  92. width1 = ego_data['dimY']
  93. o_x1 = ego_data['offX']
  94. v_x1 = ego_data['speedX'] # km/h to m/s
  95. v_y1 = ego_data['speedY'] # km/h to m/s
  96. a_x1 = ego_data['accelX']
  97. a_y1 = ego_data['accelY']
  98. # a1 = ego_data['accel']
  99. for playerId in self.obj_id_list:
  100. if playerId == EGO_PLAYER_ID:
  101. continue
  102. try:
  103. obj_data = obj_dict[frame_num][playerId]
  104. except KeyError:
  105. continue
  106. x2 = obj_data['posX']
  107. y2 = obj_data['posY']
  108. dist = self.dist(x1, y1, x2, y2)
  109. obj_data['dist'] = dist
  110. v_x2 = obj_data['speedX'] # km/h to m/s
  111. v_y2 = obj_data['speedY'] # km/h to m/s
  112. v2 = obj_data['v'] # km/h to m/s
  113. # h2 = obj_data['posH']
  114. len2 = obj_data['dimX']
  115. width2 = obj_data['dimY']
  116. o_x2 = obj_data['offX']
  117. a_x2 = obj_data['accelX']
  118. a_y2 = obj_data['accelY']
  119. # a2 = obj_data['accel']
  120. dx, dy = x2 - x1, y2 - y1
  121. # 定义矢量A和x轴正向向量x
  122. A = np.array([dx, dy])
  123. x = np.array([1, 0])
  124. # 计算点积和向量长度
  125. dot_product = np.dot(A, x)
  126. vector_length_A = np.linalg.norm(A)
  127. vector_length_x = np.linalg.norm(x)
  128. # 计算夹角的余弦值
  129. cos_theta = dot_product / (vector_length_A * vector_length_x)
  130. # 将余弦值转换为角度值(弧度制)
  131. beta = np.arccos(cos_theta) # 如何通过theta正负确定方向
  132. lon_d = dist * math.cos(beta - h1)
  133. lat_d = abs(dist * math.sin(beta - h1)) # 需要增加左正右负的判断,但beta取值为[0,pi)
  134. obj_dict[frame_num][playerId]['lon_d'] = lon_d
  135. obj_dict[frame_num][playerId]['lat_d'] = lat_d
  136. # 代码注释,这里是筛选出车前100米,车后5米,车右边4米的目标车,用于计算安全距离
  137. if lon_d > 100 or lon_d < -5 or lat_d > 4:
  138. continue
  139. self.empty_flag = False
  140. vx, vy = v_x1 - v_x2, v_y1 - v_y2
  141. ax, ay = a_x2 - a_x1, a_y2 - a_y1
  142. v_ego_p = self._cal_v_ego_projection(dx, dy, v_x1, v_y1)
  143. v_obj_p = self._cal_v_ego_projection(dx, dy, v_x2, v_y2)
  144. vrel_projection_in_dist = self._cal_v_projection(dx, dy, vx, vy)
  145. arel_projection_in_dist = self._cal_a_projection(dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1,
  146. v_x2, v_y2)
  147. obj_dict[frame_num][playerId]['vrel_projection_in_dist'] = vrel_projection_in_dist
  148. obj_dict[frame_num][playerId]['arel_projection_in_dist'] = arel_projection_in_dist
  149. obj_dict[frame_num][playerId]['v_ego_projection_in_dist'] = v_ego_p
  150. obj_dict[frame_num][playerId]['v_obj_projection_in_dist'] = v_obj_p
  151. obj_type = obj_data['type']
  152. TTC = self._cal_TTC(dist, vrel_projection_in_dist)
  153. MTTC = self._cal_MTTC(TTC, vrel_projection_in_dist, arel_projection_in_dist)
  154. THW = self._cal_THW(dist, v_ego_p)
  155. # 单车道时可用
  156. LonSD = self._cal_longitudinal_safe_dist(v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min,
  157. obj_decel_max)
  158. lat_dist = 0.5
  159. v_right = v1
  160. v_left = v2
  161. a_right_lat_brake_min = 1
  162. a_left_lat_brake_min = 1
  163. a_lat_max = 5
  164. LatSD = self._cal_lateral_safe_dist(lat_dist, v_right, v_left, rho, a_right_lat_brake_min,
  165. a_left_lat_brake_min,
  166. a_lat_max)
  167. DRAC = self._cal_DRAC(dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2)
  168. lon_a1 = a_x1 * math.cos(h1) + a_y1 * math.sin(h1)
  169. lon_a2 = a_x2 * math.cos(h1) + a_y2 * math.sin(h1)
  170. lon_a = abs(lon_a1 - lon_a2)
  171. lon_d = dist * abs(math.cos(beta - h1))
  172. lon_v = v_x1 * math.cos(h1) + v_y1 * math.sin(h1)
  173. BTN = self._cal_BTN_new(lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max)
  174. lat_a1 = a_x1 * math.sin(h1) * -1 + a_y1 * math.cos(h1)
  175. lat_a2 = a_x2 * math.sin(h1) * -1 + a_y2 * math.cos(h1)
  176. lat_a = abs(lat_a1 - lat_a2)
  177. lat_d = dist * abs(math.sin(beta - h1))
  178. lat_v = v_x1 * math.sin(h1) * -1 + v_y1 * math.cos(h1)
  179. STN = self._cal_STN_new(TTC, lat_a1, lat_a, lat_d, lat_v, ego_decel_lat_max, width1, width2)
  180. obj_dict[frame_num][playerId]['lat_v_rel'] = v_x1 - v_x2
  181. obj_dict[frame_num][playerId]['lon_v_rel'] = v_y1 - v_y2
  182. # BTN = self.cal_BTN(a_y1, ay, dy, vy, max_ay)
  183. # STN = self.cal_STN(TTC, a_x1, ax, dx, vx, max_ax, len1, len2)
  184. TTC = None if (not TTC or TTC < 0) else TTC
  185. MTTC = None if (not MTTC or MTTC < 0) else MTTC
  186. THW = None if (not THW or THW < 0) else THW
  187. DRAC = 10 if DRAC >= 10 else DRAC
  188. # TTC要进行筛选,否则会出现nan或者TTC过大的情况
  189. if not TTC or TTC > 4000: # threshold = 4258.41
  190. collisionSeverity = 0
  191. pr_death = 0
  192. collisionRisk = 0
  193. else:
  194. result, error = spi.quad(self._normal_distribution, 0, TTC - Tc)
  195. collisionSeverity = 1 - result
  196. pr_death = self._death_pr(obj_type, vrel_projection_in_dist)
  197. collisionRisk = 0.4 * pr_death + 0.6 * collisionSeverity
  198. obj_dict[frame_num][playerId]['TTC'] = TTC
  199. obj_dict[frame_num][playerId]['MTTC'] = MTTC
  200. obj_dict[frame_num][playerId]['THW'] = THW
  201. obj_dict[frame_num][playerId]['LonSD'] = LonSD
  202. obj_dict[frame_num][playerId]['LatSD'] = LatSD
  203. obj_dict[frame_num][playerId]['DRAC'] = DRAC
  204. obj_dict[frame_num][playerId]['BTN'] = abs(BTN)
  205. obj_dict[frame_num][playerId]['STN'] = abs(STN)
  206. obj_dict[frame_num][playerId]['collisionSeverity'] = collisionSeverity * 100
  207. obj_dict[frame_num][playerId]['pr_death'] = pr_death * 100
  208. obj_dict[frame_num][playerId]['collisionRisk'] = collisionRisk * 100
  209. df_fnum = pd.DataFrame(obj_dict[frame_num].values())
  210. df_list.append(df_fnum)
  211. df_safe = pd.concat(df_list)
  212. col_list = ['simTime', 'simFrame', 'playerId',
  213. 'TTC', 'MTTC', 'THW', 'LonSD', 'LatSD', 'DRAC', 'BTN', 'STN', 'collisionSeverity', 'pr_death',
  214. 'collisionRisk']
  215. self.df_safe = df_safe[col_list].reset_index(drop=True)
  216. def _cal_v_ego_projection(self, dx, dy, v_x1, v_y1):
  217. # 计算 AB 连线的向量 AB
  218. # dx = x2 - x1
  219. # dy = y2 - y1
  220. # 计算 AB 连线的模长 |AB|
  221. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  222. # 计算 AB 连线的单位向量 U_AB
  223. U_ABx = dx / AB_mod
  224. U_ABy = dy / AB_mod
  225. # 计算 A 在 AB 连线上的速度 V1_on_AB
  226. V1_on_AB = v_x1 * U_ABx + v_y1 * U_ABy
  227. return V1_on_AB
  228. def _cal_v_projection(self, dx, dy, vx, vy):
  229. # 计算 AB 连线的向量 AB
  230. # dx = x2 - x1
  231. # dy = y2 - y1
  232. # 计算 AB 连线的模长 |AB|
  233. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  234. # 计算 AB 连线的单位向量 U_AB
  235. U_ABx = dx / AB_mod
  236. U_ABy = dy / AB_mod
  237. # 计算 A 相对于 B 的速度 V_relative
  238. # vx = vx1 - vx2
  239. # vy = vy1 - vy2
  240. # 计算 A 相对于 B 在 AB 连线上的速度 V_on_AB
  241. V_on_AB = vx * U_ABx + vy * U_ABy
  242. return V_on_AB
  243. def _cal_a_projection(self, dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1, v_x2, v_y2):
  244. # 计算 AB 连线的向量 AB
  245. # dx = x2 - x1
  246. # dy = y2 - y1
  247. # 计算 θ
  248. V_mod = math.sqrt(vx ** 2 + vy ** 2)
  249. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  250. if V_mod == 0 or AB_mod == 0:
  251. return 0
  252. cos_theta = (vx * dx + vy * dy) / (V_mod * AB_mod)
  253. theta = math.acos(cos_theta)
  254. # 计算 AB 连线的模长 |AB|
  255. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  256. # 计算 AB 连线的单位向量 U_AB
  257. U_ABx = dx / AB_mod
  258. U_ABy = dy / AB_mod
  259. # 计算 A 相对于 B 的加速度 a_relative
  260. # ax = ax1 - ax2
  261. # ay = ay1 - ay2
  262. # 计算 A 相对于 B 在 AB 连线上的加速度 a_on_AB
  263. a_on_AB = ax * U_ABx + ay * U_ABy
  264. VA = np.array([v_x1, v_y1])
  265. VB = np.array([v_x2, v_y2])
  266. D_A = np.array([x1, y1])
  267. D_B = np.array([x2, y2])
  268. V_r = VA - VB
  269. V = np.linalg.norm(V_r)
  270. w = self._cal_relative_angular_v(theta, D_A, D_B, VA, VB)
  271. a_on_AB_back = self._calculate_derivative(a_on_AB, w, V, theta)
  272. return a_on_AB_back
  273. # 计算相对加速度
  274. def _calculate_derivative(self, a, w, V, theta):
  275. # 计算(V×cos(θ))'的值
  276. # derivative = a * math.cos(theta) - w * V * math.sin(theta)theta
  277. derivative = a - w * V * math.sin(theta)
  278. return derivative
  279. def _cal_relative_angular_v(self, theta, A, B, VA, VB):
  280. dx = A[0] - B[0]
  281. dy = A[1] - B[1]
  282. dvx = VA[0] - VB[0]
  283. dvy = VA[1] - VB[1]
  284. # (dx * dvy - dy * dvx)
  285. angular_velocity = math.sqrt(dvx ** 2 + dvy ** 2) * math.sin(theta) / math.sqrt(dx ** 2 + dy ** 2)
  286. return angular_velocity
  287. def _death_pr(self, obj_type, v_relative):
  288. if obj_type == 5:
  289. p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
  290. else:
  291. p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
  292. return p_death
  293. def _cal_collisionRisk_level(self, obj_type, v_relative, collisionSeverity):
  294. if obj_type == 5:
  295. p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
  296. else:
  297. p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
  298. collisionRisk = 0.4 * p_death + 0.6 * collisionSeverity
  299. return collisionRisk
  300. # 求两车之间当前距离
  301. def dist(self, x1, y1, x2, y2):
  302. dist = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
  303. return dist
  304. # TTC (time to collision)
  305. def _cal_TTC(self, dist, vrel_projection_in_dist):
  306. if vrel_projection_in_dist == 0:
  307. return math.inf
  308. TTC = dist / vrel_projection_in_dist
  309. return TTC
  310. def _cal_MTTC(self, dist, vrel_projection_in_dist, arel_projection_in_dist):
  311. MTTC = math.nan
  312. if arel_projection_in_dist != 0:
  313. tmp = vrel_projection_in_dist ** 2 + 2 * arel_projection_in_dist * dist
  314. if tmp < 0:
  315. return math.nan
  316. t1 = (-1 * vrel_projection_in_dist - math.sqrt(tmp)) / arel_projection_in_dist
  317. t2 = (-1 * vrel_projection_in_dist + math.sqrt(tmp)) / arel_projection_in_dist
  318. if t1 > 0 and t2 > 0:
  319. if t1 >= t2:
  320. MTTC = t2
  321. elif t1 < t2:
  322. MTTC = t1
  323. elif t1 > 0 and t2 <= 0:
  324. MTTC = t1
  325. elif t1 <= 0 and t2 > 0:
  326. MTTC = t2
  327. if arel_projection_in_dist == 0 and vrel_projection_in_dist > 0:
  328. MTTC = dist / vrel_projection_in_dist
  329. return MTTC
  330. # THW (time headway)
  331. def _cal_THW(self, dist, v_ego_projection_in_dist):
  332. if not v_ego_projection_in_dist:
  333. THW = None
  334. else:
  335. THW = dist / v_ego_projection_in_dist
  336. return THW
  337. def velocity(self, v_x, v_y):
  338. v = math.sqrt(v_x ** 2 + v_y ** 2) * 3.6
  339. return v
  340. def _cal_longitudinal_safe_dist(self, v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min, ego_decel_max):
  341. lon_dist_min = v_ego_p * rho + ego_accel_max * (rho ** 2) / 2 + (v_ego_p + rho * ego_accel_max) ** 2 / (
  342. 2 * ego_decel_min) - v_obj_p ** 2 / (2 * ego_decel_max)
  343. return lon_dist_min
  344. def _cal_lateral_safe_dist(self, lat_dist, v_right, v_left, rho, a_right_lat_brake_min, a_left_lat_brake_min,
  345. a_lat_max):
  346. v_right_rho = v_right + rho * a_lat_max
  347. v_left_rho = v_left + rho * a_lat_max
  348. dist_min = lat_dist + ((v_right + v_right_rho) * rho / 2 + v_right_rho ** 2 / a_right_lat_brake_min / 2 + (
  349. (v_left + v_right_rho) * rho / 2) + v_left_rho ** 2 / a_left_lat_brake_min / 2)
  350. return dist_min
  351. # DRAC (decelerate required avoid collision)
  352. def _cal_DRAC(self, dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2):
  353. dist_length = dist - (len2 / 2 - o_x2 + len1 / 2 + o_x1) # 4.671
  354. if dist_length < 0:
  355. dist_width = dist - (width2 / 2 + width1 / 2)
  356. if dist_width < 0:
  357. return math.inf
  358. else:
  359. d = dist_width
  360. else:
  361. d = dist_length
  362. DRAC = vrel_projection_in_dist ** 2 / (2 * d)
  363. return DRAC
  364. # BTN (brake threat number)
  365. def _cal_BTN_new(self, lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max):
  366. BTN = (lon_a1 + lon_a - lon_v ** 2 / (2 * lon_d)) / ego_decel_lon_max # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
  367. return BTN
  368. # STN (steer threat number)
  369. def _cal_STN_new(self, ttc, lat_a1, lat_a, lat_d, lat_v, ego_decel_lat_max, width1, width2):
  370. STN = (lat_a1 + lat_a + 2 / ttc ** 2 * (lat_d + abs(ego_decel_lat_max * lat_v) * (
  371. width1 + width2) / 2 + abs(lat_v * ttc))) / ego_decel_lat_max
  372. return STN
  373. # BTN (brake threat number)
  374. def cal_BTN(self, a_y1, ay, dy, vy, max_ay):
  375. BTN = (a_y1 + ay - vy ** 2 / (2 * dy)) / max_ay # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
  376. return BTN
  377. # STN (steer threat number)
  378. def cal_STN(self, ttc, a_x1, ax, dx, vx, max_ax, width1, width2):
  379. STN = (a_x1 + ax + 2 / ttc ** 2 * (dx + np.sign(max_ax * vx) * (width1 + width2) / 2 + vx * ttc)) / max_ax
  380. return STN
  381. # 追尾碰撞风险
  382. def _normal_distribution(self, x):
  383. mean = 1.32
  384. std_dev = 0.26
  385. return (1 / (math.sqrt(std_dev * 2 * math.pi))) * math.exp(-0.5 * (x - mean) ** 2 / std_dev)
  386. def continuous_group(self, df):
  387. time_list = df['simTime'].values.tolist()
  388. frame_list = df['simFrame'].values.tolist()
  389. group_time = []
  390. group_frame = []
  391. sub_group_time = []
  392. sub_group_frame = []
  393. for i in range(len(frame_list)):
  394. if not sub_group_time or frame_list[i] - frame_list[i - 1] <= 1:
  395. sub_group_time.append(time_list[i])
  396. sub_group_frame.append(frame_list[i])
  397. else:
  398. group_time.append(sub_group_time)
  399. group_frame.append(sub_group_frame)
  400. sub_group_time = [time_list[i]]
  401. sub_group_frame = [frame_list[i]]
  402. group_time.append(sub_group_time)
  403. group_frame.append(sub_group_frame)
  404. group_time = [g for g in group_time if len(g) >= 2]
  405. group_frame = [g for g in group_frame if len(g) >= 2]
  406. # 输出图表值
  407. time = [[g[0], g[-1]] for g in group_time]
  408. frame = [[g[0], g[-1]] for g in group_frame]
  409. unfunc_time_df = pd.DataFrame(time, columns=['start_time', 'end_time'])
  410. unfunc_frame_df = pd.DataFrame(frame, columns=['start_frame', 'end_frame'])
  411. unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
  412. return unfunc_df
  413. # 统计最危险的指标
  414. def _safe_statistic_most_dangerous(self):
  415. min_list = ['TTC', 'MTTC', 'THW', 'LonSD', 'LatSD']
  416. max_list = ['DRAC', 'BTN', 'STN', 'collisionRisk', 'collisionSeverity']
  417. for metric in min_list:
  418. if metric in self.metric_list:
  419. if metric in self.df.columns:
  420. self.calculated_value[metric] = self.df[metric].min()
  421. else:
  422. self.calculated_value[metric] = 10.0
  423. for metric in max_list:
  424. if metric in self.metric_list:
  425. if metric in self.df.columns:
  426. self.calculated_value[metric] = self.df[metric].max()
  427. else:
  428. self.calculated_value[metric] = 10.0
  429. return self.calculated_value
  430. def _safe_no_obj_statistic(self):
  431. # list_metric = ["TTC","MTTC","THW","LonSD","LatSD","DRAC","BTN","STN","collisionSeverity", "collisionRisk"]
  432. return self.calculated_value
  433. def report_statistic(self, ):
  434. safety_result = {}
  435. if len(self.obj_id_list) == 1:
  436. safety_result = self._safe_no_obj_statistic()
  437. else:
  438. safety_result = self._safe_statistic_most_dangerous()
  439. evaluator = Score(config.SAFETY_CONFIG_PATH)
  440. result = evaluator.evaluate(safety_result)
  441. print("\n[安全性表现及得分情况]")
  442. return result