safety.py 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. 安全指标计算模块
  5. """
  6. import numpy as np
  7. import pandas as pd
  8. import math
  9. from collections import defaultdict
  10. from typing import Dict, Any, List, Optional
  11. import ast
  12. from modules.lib.score import Score
  13. from modules.lib.log_manager import LogManager
  14. # 安全指标相关常量
  15. SAFETY_INFO = [
  16. "simTime",
  17. "simFrame",
  18. "playerId",
  19. "posX",
  20. "posY",
  21. "posH",
  22. "speedX",
  23. "speedY",
  24. "accelX",
  25. "accelY",
  26. "v",
  27. "type",
  28. "lane_width",
  29. "lane_type",
  30. "road_type",
  31. "lane_coords",
  32. "link_coords"
  33. ]
  34. # ----------------------
  35. # 独立指标计算函数
  36. # ----------------------
  37. def calculate_ttc(data_processed) -> dict:
  38. """计算TTC (Time To Collision)"""
  39. if data_processed is None or not hasattr(data_processed, 'object_df'):
  40. return {"TTC": None}
  41. try:
  42. safety = SafetyCalculator(data_processed)
  43. ttc_value = safety.get_ttc_value()
  44. LogManager().get_logger().info(f"安全指标[TTC]计算结果: {ttc_value}")
  45. return {"TTC": ttc_value}
  46. except Exception as e:
  47. LogManager().get_logger().error(f"TTC计算异常: {str(e)}", exc_info=True)
  48. return {"TTC": None}
  49. def calculate_mttc(data_processed) -> dict:
  50. """计算MTTC (Modified Time To Collision)"""
  51. if data_processed is None or not hasattr(data_processed, 'object_df'):
  52. return {"MTTC": None}
  53. try:
  54. safety = SafetyCalculator(data_processed)
  55. mttc_value = safety.get_mttc_value()
  56. LogManager().get_logger().info(f"安全指标[MTTC]计算结果: {mttc_value}")
  57. return {"MTTC": mttc_value}
  58. except Exception as e:
  59. LogManager().get_logger().error(f"MTTC计算异常: {str(e)}", exc_info=True)
  60. return {"MTTC": None}
  61. def calculate_thw(data_processed) -> dict:
  62. """计算THW (Time Headway)"""
  63. if data_processed is None or not hasattr(data_processed, 'object_df'):
  64. return {"THW": None}
  65. try:
  66. safety = SafetyCalculator(data_processed)
  67. thw_value = safety.get_thw_value()
  68. LogManager().get_logger().info(f"安全指标[THW]计算结果: {thw_value}")
  69. return {"THW": thw_value}
  70. except Exception as e:
  71. LogManager().get_logger().error(f"THW计算异常: {str(e)}", exc_info=True)
  72. return {"THW": None}
  73. def calculate_tlc(data_processed) -> dict:
  74. """计算TLC (Time to Line Crossing)"""
  75. if data_processed is None or not hasattr(data_processed, 'object_df'):
  76. return {"TLC": None}
  77. try:
  78. safety = SafetyCalculator(data_processed)
  79. tlc_value = safety.get_tlc_value()
  80. LogManager().get_logger().info(f"安全指标[TLC]计算结果: {tlc_value}")
  81. return {"TLC": tlc_value}
  82. except Exception as e:
  83. LogManager().get_logger().error(f"TLC计算异常: {str(e)}", exc_info=True)
  84. return {"TLC": None}
  85. def calculate_ttb(data_processed) -> dict:
  86. """计算TTB (Time to Brake)"""
  87. if data_processed is None or not hasattr(data_processed, 'object_df'):
  88. return {"TTB": None}
  89. try:
  90. safety = SafetyCalculator(data_processed)
  91. ttb_value = safety.get_ttb_value()
  92. LogManager().get_logger().info(f"安全指标[TTB]计算结果: {ttb_value}")
  93. return {"TTB": ttb_value}
  94. except Exception as e:
  95. LogManager().get_logger().error(f"TTB计算异常: {str(e)}", exc_info=True)
  96. return {"TTB": None}
  97. def calculate_tm(data_processed) -> dict:
  98. """计算TM (Time Margin)"""
  99. if data_processed is None or not hasattr(data_processed, 'object_df'):
  100. return {"TM": None}
  101. try:
  102. safety = SafetyCalculator(data_processed)
  103. tm_value = safety.get_tm_value()
  104. LogManager().get_logger().info(f"安全指标[TM]计算结果: {tm_value}")
  105. return {"TM": tm_value}
  106. except Exception as e:
  107. LogManager().get_logger().error(f"TM计算异常: {str(e)}", exc_info=True)
  108. return {"TM": None}
  109. # def calculate_MPrTTC(data_processed) -> dict:
  110. # """计算MPrTTC (Model Predictive Time-to-Collision)"""
  111. # if data_processed is None or not hasattr(data_processed, 'object_df'):
  112. # return {"MPrTTC": None}
  113. # try:
  114. # safety = SafetyCalculator(data_processed)
  115. # mprttc_value = safety.get_mprttc_value()
  116. # LogManager().get_logger().info(f"安全指标[MPrTTC]计算结果: {mprttc_value}")
  117. # return {"MPrTTC": mprttc_value}
  118. # except Exception as e:
  119. # LogManager().get_logger().error(f"MPrTTC计算异常: {str(e)}", exc_info=True)
  120. # return {"MPrTTC": None}
  121. def calculate_dtc(data_processed) -> dict:
  122. """计算DTC (Distance to Collision)"""
  123. if data_processed is None or not hasattr(data_processed, 'object_df'):
  124. return {"DTC": None}
  125. try:
  126. safety = SafetyCalculator(data_processed)
  127. dtc_value = safety.get_dtc_value()
  128. LogManager().get_logger().info(f"安全指标[DTC]计算结果: {dtc_value}")
  129. return {"DTC": dtc_value}
  130. except Exception as e:
  131. LogManager().get_logger().error(f"DTC计算异常: {str(e)}", exc_info=True)
  132. return {"DTC": None}
  133. def calculate_pet(data_processed) -> dict:
  134. """计算PET (Post Encroachment Time)"""
  135. if data_processed is None or not hasattr(data_processed, 'object_df'):
  136. return {"PET": None}
  137. try:
  138. safety = SafetyCalculator(data_processed)
  139. pet_value = safety.get_dtc_value()
  140. LogManager().get_logger().info(f"安全指标[PET]计算结果: {pet_value}")
  141. return {"PET": pet_value}
  142. except Exception as e:
  143. LogManager().get_logger().error(f"PET计算异常: {str(e)}", exc_info=True)
  144. return {"PET": None}
  145. def calculate_psd(data_processed) -> dict:
  146. """计算PSD (Potential Safety Distance)"""
  147. if data_processed is None or not hasattr(data_processed, 'object_df'):
  148. return {"PSD": None}
  149. try:
  150. safety = SafetyCalculator(data_processed)
  151. psd_value = safety.get_psd_value()
  152. LogManager().get_logger().info(f"安全指标[PSD]计算结果: {psd_value}")
  153. return {"PSD": psd_value}
  154. except Exception as e:
  155. LogManager().get_logger().error(f"PSD计算异常: {str(e)}", exc_info=True)
  156. return {"PSD": None}
  157. def calculate_collisionrisk(data_processed) -> dict:
  158. """计算碰撞风险"""
  159. safety = SafetyCalculator(data_processed)
  160. collision_risk_value = safety.get_collision_risk_value()
  161. LogManager().get_logger().info(f"安全指标[collisionRisk]计算结果: {collision_risk_value}")
  162. return {"collisionRisk": collision_risk_value}
  163. def calculate_lonsd(data_processed) -> dict:
  164. """计算纵向安全距离"""
  165. safety = SafetyCalculator(data_processed)
  166. lonsd_value = safety.get_lonsd_value()
  167. LogManager().get_logger().info(f"安全指标[LonSD]计算结果: {lonsd_value}")
  168. return {"LonSD": lonsd_value}
  169. def calculate_latsd(data_processed) -> dict:
  170. """计算横向安全距离"""
  171. safety = SafetyCalculator(data_processed)
  172. latsd_value = safety.get_latsd_value()
  173. LogManager().get_logger().info(f"安全指标[LatSD]计算结果: {latsd_value}")
  174. return {"LatSD": latsd_value}
  175. def calculate_btn(data_processed) -> dict:
  176. """计算制动威胁数"""
  177. safety = SafetyCalculator(data_processed)
  178. btn_value = safety.get_btn_value()
  179. LogManager().get_logger().info(f"安全指标[BTN]计算结果: {btn_value}")
  180. return {"BTN": btn_value}
  181. def calculate_collisionseverity(data_processed) -> dict:
  182. """计算碰撞严重性"""
  183. safety = SafetyCalculator(data_processed)
  184. collision_severity_value = safety.get_collision_severity_value()
  185. LogManager().get_logger().info(f"安全指标[collisionSeverity]计算结果: {collision_severity_value}")
  186. return {"collisionSeverity": collision_severity_value}
  187. class SafetyRegistry:
  188. """安全指标注册器"""
  189. def __init__(self, data_processed):
  190. self.logger = LogManager().get_logger()
  191. self.data = data_processed
  192. self.safety_config = data_processed.safety_config["safety"]
  193. self.metrics = self._extract_metrics(self.safety_config)
  194. self._registry = self._build_registry()
  195. def _extract_metrics(self, config_node: dict) -> list:
  196. """从配置中提取指标名称"""
  197. metrics = []
  198. def _recurse(node):
  199. if isinstance(node, dict):
  200. if 'name' in node and not any(isinstance(v, dict) for v in node.values()):
  201. metrics.append(node['name'])
  202. for v in node.values():
  203. _recurse(v)
  204. _recurse(config_node)
  205. self.logger.info(f'评比的安全指标列表:{metrics}')
  206. return metrics
  207. def _build_registry(self) -> dict:
  208. """构建指标函数注册表"""
  209. registry = {}
  210. for metric_name in self.metrics:
  211. func_name = f"calculate_{metric_name.lower()}"
  212. if func_name in globals():
  213. registry[metric_name] = globals()[func_name]
  214. else:
  215. self.logger.warning(f"未实现安全指标函数: {func_name}")
  216. return registry
  217. def batch_execute(self) -> dict:
  218. """批量执行指标计算"""
  219. results = {}
  220. for name, func in self._registry.items():
  221. try:
  222. result = func(self.data)
  223. results.update(result)
  224. except Exception as e:
  225. self.logger.error(f"{name} 执行失败: {str(e)}", exc_info=True)
  226. results[name] = None
  227. self.logger.info(f'安全指标计算结果:{results}')
  228. return results
  229. class SafeManager:
  230. """安全指标管理类"""
  231. def __init__(self, data_processed):
  232. self.data = data_processed
  233. self.registry = SafetyRegistry(self.data)
  234. def report_statistic(self):
  235. """计算并报告安全指标结果"""
  236. safety_result = self.registry.batch_execute()
  237. return safety_result
  238. class SafetyCalculator:
  239. """安全指标计算类 - 兼容Safe类风格"""
  240. def __init__(self, data_processed):
  241. self.logger = LogManager().get_logger()
  242. self.data_processed = data_processed
  243. self.df = data_processed.object_df.copy()
  244. self.ego_df = data_processed.ego_data.copy() # 使用copy()避免修改原始数据
  245. self.obj_id_list = data_processed.obj_id_list
  246. self.metric_list = [
  247. 'TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'TM', 'DTC', 'PET', 'PSD', 'LonSD', 'LatSD', 'BTN', 'collisionRisk', 'collisionSeverity'
  248. ]
  249. # 初始化默认值
  250. self.calculated_value = {
  251. "TTC": 10.0,
  252. "MTTC": 10.0,
  253. "THW": 10.0,
  254. "TLC": 10.0,
  255. "TTB": 10.0,
  256. "TM": 10.0,
  257. # "MPrTTC": 10.0,
  258. "PET": 10.0,
  259. "DTC": 10.0,
  260. "PSD": 10.0,
  261. "LatSD": 3.0,
  262. "BTN": 1.0,
  263. "collisionRisk": 0.0,
  264. "collisionSeverity": 0.0,
  265. }
  266. self.time_list = self.ego_df['simTime'].values.tolist()
  267. self.frame_list = self.ego_df['simFrame'].values.tolist()
  268. self.collisionRisk = 0
  269. self.empty_flag = True
  270. self.logger.info("SafetyCalculator初始化完成,场景中包含自车的目标物一共为: %d", len(self.obj_id_list))
  271. if len(self.obj_id_list) > 1:
  272. self.unsafe_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  273. self.unsafe_time_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  274. self.unsafe_dist_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  275. self.unsafe_acce_drac_df = pd.DataFrame(
  276. columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  277. self.unsafe_acce_xtn_df = pd.DataFrame(
  278. columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  279. self.unsafe_prob_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
  280. self.most_dangerous = {}
  281. self.pass_percent = {}
  282. self.logger.info("开始执行安全参数计算 _safe_param_cal_new")
  283. self._safe_param_cal_new()
  284. self.logger.info("安全参数计算完成")
  285. def _safe_param_cal_new(self):
  286. self.logger.debug("进入 _safe_param_cal_new 方法")
  287. # 直接复用Safe类的实现
  288. Tc = 0.3 # 安全距离
  289. rho = self.data_processed.vehicle_config["RHO"]
  290. ego_accel_max = self.data_processed.vehicle_config["EGO_ACCEL_MAX"]
  291. obj_decel_max = self.data_processed.vehicle_config["OBJ_DECEL_MAX"]
  292. ego_decel_min = self.data_processed.vehicle_config["EGO_DECEL_MIN"]
  293. ego_decel_lon_max = self.data_processed.vehicle_config["EGO_DECEL_LON_MAX"]
  294. ego_decel_lat_max = self.data_processed.vehicle_config["EGO_DECEL_LAT_MAX"]
  295. driver_reaction_time = self.data_processed.vehicle_config["RHO"]
  296. ego_decel_max = np.sqrt(ego_decel_lon_max ** 2 + ego_decel_lat_max ** 2)
  297. x_relative_start_dist = self.ego_df["x_relative_dist"]
  298. obj_dict = defaultdict(dict)
  299. obj_data_dict = self.df.to_dict('records')
  300. for item in obj_data_dict:
  301. obj_dict[item['simFrame']][item['playerId']] = item
  302. df_list = []
  303. EGO_PLAYER_ID = 1
  304. ramp_poss = self.ego_df[self.ego_df["link_type"] == 19]["link_coords"].drop_duplicates().tolist() # 寻找匝道的位置坐标
  305. lane_poss = self.ego_df[self.ego_df["lane_type"] == 2]["lane_coords"].drop_duplicates().tolist() # 寻找匝道的位置坐标
  306. for frame_num in self.frame_list:
  307. ego_data = obj_dict[frame_num][EGO_PLAYER_ID]
  308. v1 = ego_data['v']
  309. x1 = ego_data['posX']
  310. y1 = ego_data['posY']
  311. h1 = ego_data['posH']
  312. laneOffset = ego_data["laneOffset"]
  313. v_x1 = ego_data['speedX']
  314. v_y1 = ego_data['speedY']
  315. a_x1 = ego_data['accelX']
  316. a_y1 = ego_data['accelY']
  317. a1 = np.sqrt(a_x1 ** 2 + a_y1 ** 2)
  318. for playerId in self.obj_id_list:
  319. if playerId == EGO_PLAYER_ID:
  320. continue
  321. try:
  322. obj_data = obj_dict[frame_num][playerId]
  323. except KeyError:
  324. continue
  325. x2 = obj_data['posX']
  326. y2 = obj_data['posY']
  327. dist = self.dist(x1, y1, x2, y2)
  328. obj_data['dist'] = dist
  329. v_x2 = obj_data['speedX']
  330. v_y2 = obj_data['speedY']
  331. v2 = obj_data['v']
  332. a_x2 = obj_data['accelX']
  333. a_y2 = obj_data['accelY']
  334. a2 = np.sqrt(a_x2 ** 2 + a_y2 ** 2)
  335. dx, dy = x2 - x1, y2 - y1
  336. # 计算目标车相对于自车的方位角
  337. beta = math.atan2(dy, dx)
  338. # 将全局坐标系下的相对位置向量转换到自车坐标系
  339. # 自车坐标系:车头方向为x轴正方向,车辆左侧为y轴正方向
  340. h1_rad = math.radians(90 - h1) # 转换为与x轴的夹角
  341. # 坐标变换
  342. lon_d = dx * math.cos(h1_rad) + dy * math.sin(h1_rad) # 纵向距离(前为正,后为负)
  343. lat_d = abs(-dx * math.sin(h1_rad) + dy * math.cos(h1_rad)) # 横向距离(取绝对值)
  344. obj_dict[frame_num][playerId]['lon_d'] = lon_d
  345. obj_dict[frame_num][playerId]['lat_d'] = lat_d
  346. if lon_d > 100 or lon_d < -5 or lat_d > 4:
  347. continue
  348. self.empty_flag = False
  349. vx, vy = v_x1 - v_x2, v_y1 - v_y2
  350. ax, ay = a_x2 - a_x1, a_y2 - a_y1
  351. relative_v = np.sqrt(vx ** 2 + vy ** 2)
  352. v_ego_p = self._cal_v_ego_projection(dx, dy, v_x1, v_y1)
  353. v_obj_p = self._cal_v_ego_projection(dx, dy, v_x2, v_y2)
  354. vrel_projection_in_dist = self._cal_v_projection(dx, dy, vx, vy)
  355. arel_projection_in_dist = self._cal_a_projection(dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1,
  356. v_x2, v_y2)
  357. obj_dict[frame_num][playerId]['vrel_projection_in_dist'] = vrel_projection_in_dist
  358. obj_dict[frame_num][playerId]['arel_projection_in_dist'] = arel_projection_in_dist
  359. obj_dict[frame_num][playerId]['v_ego_projection_in_dist'] = v_ego_p
  360. obj_dict[frame_num][playerId]['v_obj_projection_in_dist'] = v_obj_p
  361. obj_type = obj_data['type']
  362. TTC = self._cal_TTC(dist, vrel_projection_in_dist) if abs(vrel_projection_in_dist) > 1e-6 else None
  363. MTTC = self._cal_MTTC(dist, vrel_projection_in_dist, arel_projection_in_dist)
  364. THW = self._cal_THW(dist, v_ego_p) if abs(v_ego_p) > 1e-6 else None
  365. TLC = self._cal_TLC(v1, h1, laneOffset)
  366. TTB = self._cal_TTB(x_relative_start_dist, relative_v, ego_decel_max)
  367. TM = self._cal_TM(x_relative_start_dist, v2, a2, v1, a1)
  368. DTC = self._cal_DTC(vrel_projection_in_dist, arel_projection_in_dist, driver_reaction_time)
  369. # MPrTTC = self._cal_MPrTTC(x_relative_start_dist)
  370. # PET = self._cal_PET(lane_posx1, lane_posy1, lane_posx2, lane_posy2, ramp_posx1, ramp_posy1, ramp_posx2, ramp_posy2, ego_posx, ego_posy, obj_posx, obj_posy, lane_width, delta_t, v1, v2, a1, a2)
  371. PET = None
  372. for lane_pos in lane_poss:
  373. lane_posx1 = ast.literal_eval(lane_pos)[0][0]
  374. lane_posy1 = ast.literal_eval(lane_pos)[0][1]
  375. lane_posx2 = ast.literal_eval(lane_pos)[-1][0]
  376. lane_posy2 = ast.literal_eval(lane_pos)[-1][1]
  377. for ramp_pos in ramp_poss:
  378. ramp_posx1 = ast.literal_eval(ramp_pos)[0][0]
  379. ramp_posy1 = ast.literal_eval(ramp_pos)[0][1]
  380. ramp_posx2 = ast.literal_eval(ramp_pos)[-1][0]
  381. ramp_posy2 = ast.literal_eval(ramp_pos)[-1][1]
  382. ego_posx = x1
  383. ego_posy = y1
  384. obj_posx = x2
  385. obj_posy = y2
  386. delta_t = self._cal_reaction_time_to_avgspeed(self.ego_df)
  387. lane_width = self.ego_df["lane_width"].iloc[0]
  388. PET = self._cal_PET(lane_posx1, lane_posy1, lane_posx2, lane_posy2, ramp_posx1, ramp_posy1, ramp_posx2,
  389. ramp_posy2, ego_posx, ego_posy, obj_posx, obj_posy, lane_width, delta_t, v1, v2, a1, a2)
  390. PSD = self._cal_PSD(x_relative_start_dist, v1, ego_decel_lon_max)
  391. LonSD = self._cal_longitudinal_safe_dist(v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min, obj_decel_max)
  392. lat_dist = 0.5
  393. v_right = v1
  394. v_left = v2
  395. a_right_lat_brake_min = 1
  396. a_left_lat_brake_min = 1
  397. a_lat_max = 5
  398. LatSD = self._cal_lateral_safe_dist(lat_dist, v_right, v_left, rho, a_right_lat_brake_min,
  399. a_left_lat_brake_min, a_lat_max)
  400. # 使用自车坐标系下的纵向加速度
  401. lon_a1 = a_x1 * math.cos(h1_rad) + a_y1 * math.sin(h1_rad)
  402. lon_a2 = a_x2 * math.cos(h1_rad) + a_y2 * math.sin(h1_rad)
  403. lon_a = abs(lon_a1 - lon_a2)
  404. lon_d = max(0.1, lon_d) # 确保纵向距离为正
  405. lon_v = v_x1 * math.cos(h1_rad) + v_y1 * math.sin(h1_rad)
  406. BTN = self._cal_BTN_new(lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max)
  407. # 使用自车坐标系下的横向加速度
  408. lat_a1 = -a_x1 * math.sin(h1_rad) + a_y1 * math.cos(h1_rad)
  409. lat_a2 = -a_x2 * math.sin(h1_rad) + a_y2 * math.cos(h1_rad)
  410. lat_a = abs(lat_a1 - lat_a2)
  411. lat_v = -v_x1 * math.sin(h1_rad) + v_y1 * math.cos(h1_rad)
  412. obj_dict[frame_num][playerId]['lat_v_rel'] = lat_v - (-v_x2 * math.sin(h1_rad) + v_y2 * math.cos(h1_rad))
  413. obj_dict[frame_num][playerId]['lon_v_rel'] = lon_v - (v_x2 * math.cos(h1_rad) + v_y2 * math.sin(h1_rad))
  414. TTC = None if (TTC is None or TTC < 0) else TTC
  415. MTTC = None if (MTTC is None or MTTC < 0) else MTTC
  416. THW = None if (THW is None or THW < 0) else THW
  417. TLC = None if (TLC is None or TLC < 0) else TLC
  418. TTB = None if (TTB is None or TTB < 0) else TTB
  419. TM = None if (TM is None or TM < 0) else TM
  420. DTC = None if (DTC is None or DTC < 0) else DTC
  421. PET = None if (PET is None or PET < 0) else PET
  422. PSD = None if (PSD is None or PSD < 0) else PSD
  423. obj_dict[frame_num][playerId]['TTC'] = TTC
  424. obj_dict[frame_num][playerId]['MTTC'] = MTTC
  425. obj_dict[frame_num][playerId]['THW'] = THW
  426. obj_dict[frame_num][playerId]['TLC'] = TLC
  427. obj_dict[frame_num][playerId]['TTB'] = TTB
  428. obj_dict[frame_num][playerId]['TM'] = TM
  429. obj_dict[frame_num][playerId]['DTC'] = DTC
  430. obj_dict[frame_num][playerId]['PET'] = PET
  431. obj_dict[frame_num][playerId]['PSD'] = PSD
  432. obj_dict[frame_num][playerId]['LonSD'] = LonSD
  433. obj_dict[frame_num][playerId]['LatSD'] = LatSD
  434. obj_dict[frame_num][playerId]['BTN'] = abs(BTN)
  435. collisionSeverity = 0
  436. pr_death = 0
  437. collisionRisk = 0
  438. obj_dict[frame_num][playerId]['collisionSeverity'] = collisionSeverity * 100
  439. obj_dict[frame_num][playerId]['pr_death'] = pr_death * 100
  440. obj_dict[frame_num][playerId]['collisionRisk'] = collisionRisk * 100
  441. df_fnum = pd.DataFrame(obj_dict[frame_num].values())
  442. df_list.append(df_fnum)
  443. df_safe = pd.concat(df_list)
  444. col_list = ['simTime', 'simFrame', 'playerId',
  445. 'TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'TM', 'DTC', 'PET', 'PSD', 'LonSD', 'LatSD', 'BTN',
  446. 'collisionSeverity', 'pr_death', 'collisionRisk']
  447. self.df_safe = df_safe[col_list].reset_index(drop=True)
  448. # 计算车辆从非匀速达到匀速的反应时间
  449. def _cal_reaction_time_to_avgspeed(self, ego_df, threshold = 0.01):
  450. ego_df = ego_df.reset_index(drop=True)
  451. ego_df['v_change'] = ego_df['v'].diff()
  452. # 初始化结果列表
  453. uniform_speed_segments = []
  454. start_index = 0
  455. # 遍历数据,找出匀速部分
  456. for i in range(1, len(ego_df)):
  457. if ego_df['v_change'].iloc[i] > threshold:
  458. if i - start_index > 1: # 至少有两个数据点才能形成一个匀速段
  459. uniform_speed_segments.append(
  460. (ego_df.iloc[start_index]['simTime'], ego_df.iloc[i - 1]['simTime'], ego_df.iloc[start_index]['v']))
  461. start_index = i
  462. # 检查最后一个段
  463. if len(ego_df) - start_index > 1:
  464. uniform_speed_segments.append(
  465. (ego_df.iloc[start_index]['simTime'], ego_df.iloc[-1]['simTime'], ego_df.iloc[start_index]['v']))
  466. return uniform_speed_segments[-1][0] - ego_df['simTime'].iloc[0]
  467. def _cal_v_ego_projection(self, dx, dy, v_x1, v_y1):
  468. # 计算 AB 连线的向量 AB
  469. # dx = x2 - x1
  470. # dy = y2 - y1
  471. # 计算 AB 连线的模长 |AB|
  472. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  473. # 计算 AB 连线的单位向量 U_AB
  474. U_ABx = dx / AB_mod
  475. U_ABy = dy / AB_mod
  476. # 计算 A 在 AB 连线上的速度 V1_on_AB
  477. V1_on_AB = v_x1 * U_ABx + v_y1 * U_ABy
  478. return V1_on_AB
  479. def _cal_v_projection(self, dx, dy, vx, vy):
  480. # 计算 AB 连线的向量 AB
  481. # dx = x2 - x1
  482. # dy = y2 - y1
  483. # 计算 AB 连线的模长 |AB|
  484. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  485. # 计算 AB 连线的单位向量 U_AB
  486. U_ABx = dx / AB_mod
  487. U_ABy = dy / AB_mod
  488. # 计算 A 相对于 B 的速度 V_relative
  489. # vx = vx1 - vx2
  490. # vy = vy1 - vy2
  491. # 计算 A 相对于 B 在 AB 连线上的速度 V_on_AB
  492. V_on_AB = vx * U_ABx + vy * U_ABy
  493. return V_on_AB
  494. def _cal_a_projection(self, dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1, v_x2, v_y2):
  495. # 计算 AB 连线的向量 AB
  496. # dx = x2 - x1
  497. # dy = y2 - y1
  498. # 计算 θ
  499. V_mod = math.sqrt(vx ** 2 + vy ** 2)
  500. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  501. if V_mod == 0 or AB_mod == 0:
  502. return 0
  503. cos_theta = (vx * dx + vy * dy) / (V_mod * AB_mod)
  504. theta = math.acos(cos_theta)
  505. # 计算 AB 连线的模长 |AB|
  506. AB_mod = math.sqrt(dx ** 2 + dy ** 2)
  507. # 计算 AB 连线的单位向量 U_AB
  508. U_ABx = dx / AB_mod
  509. U_ABy = dy / AB_mod
  510. # 计算 A 相对于 B 的加速度 a_relative
  511. # ax = ax1 - ax2
  512. # ay = ay1 - ay2
  513. # 计算 A 相对于 B 在 AB 连线上的加速度 a_on_AB
  514. a_on_AB = ax * U_ABx + ay * U_ABy
  515. VA = np.array([v_x1, v_y1])
  516. VB = np.array([v_x2, v_y2])
  517. D_A = np.array([x1, y1])
  518. D_B = np.array([x2, y2])
  519. V_r = VA - VB
  520. V = np.linalg.norm(V_r)
  521. w = self._cal_relative_angular_v(theta, D_A, D_B, VA, VB)
  522. a_on_AB_back = self._calculate_derivative(a_on_AB, w, V, theta)
  523. return a_on_AB_back
  524. # 计算相对加速度
  525. def _calculate_derivative(self, a, w, V, theta):
  526. # 计算(V×cos(θ))'的值
  527. # derivative = a * math.cos(theta) - w * V * math.sin(theta)theta
  528. derivative = a - w * V * math.sin(theta)
  529. return derivative
  530. def _cal_relative_angular_v(self, theta, A, B, VA, VB):
  531. dx = A[0] - B[0]
  532. dy = A[1] - B[1]
  533. dvx = VA[0] - VB[0]
  534. dvy = VA[1] - VB[1]
  535. # (dx * dvy - dy * dvx)
  536. angular_velocity = math.sqrt(dvx ** 2 + dvy ** 2) * math.sin(theta) / math.sqrt(dx ** 2 + dy ** 2)
  537. return angular_velocity
  538. def _death_pr(self, obj_type, v_relative):
  539. if obj_type == 5:
  540. p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
  541. else:
  542. p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
  543. return p_death
  544. def _cal_collisionRisk_level(self, obj_type, v_relative, collisionSeverity):
  545. if obj_type == 5:
  546. p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
  547. else:
  548. p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
  549. collisionRisk = 0.4 * p_death + 0.6 * collisionSeverity
  550. return collisionRisk
  551. # 求两车之间当前距离
  552. def dist(self, x1, y1, x2, y2):
  553. dist = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
  554. return dist
  555. # 求车辆与道路之间的横向距离
  556. def horizontal_distance(self, posx1, posy1, posx2, posy2, posx, posy):
  557. dist = np.sqrt((posx2 - posx1)(posy - posy1) - (posy2 - posy1)(posx - posy1))/np.sqrt((posx2 - posx1)**2 + (posy2 - posy1)**2)
  558. return dist
  559. # 求车辆与道路之间的纵向距离
  560. def _is_alone_the_road(self, posx1, posy1, posx2, posy2, posx, posy):
  561. pro_car = (posx2 - posx1)(posx - posx1) + (posy2 - posy1)(posy - posy1)
  562. if pro_car > 0:
  563. return True
  564. else:
  565. return False
  566. def _is_in_the_road(self, posx1, posy1, posx2, posy2, posx, posy):
  567. pro_obj1 = (posx2 - posx1)(posx - posx1) + (posy2 - posy1)(posy - posy1)
  568. pro_obj2 = (posx1 - posx2)(posx - posx2) + (posy1 - posy2)(posy - posy2)
  569. if pro_obj1 > 0 and pro_obj2 > 0:
  570. return True
  571. else:
  572. return False
  573. # TTC (time to collision)
  574. def _cal_TTC(self, dist, vrel_projection_in_dist):
  575. if vrel_projection_in_dist == 0:
  576. return math.inf
  577. TTC = dist / vrel_projection_in_dist
  578. return TTC
  579. def _cal_MTTC(self, dist, vrel_projection_in_dist, arel_projection_in_dist):
  580. MTTC = math.nan
  581. if arel_projection_in_dist != 0:
  582. tmp = vrel_projection_in_dist ** 2 + 2 * arel_projection_in_dist * dist
  583. if tmp < 0:
  584. return math.nan
  585. t1 = (-1 * vrel_projection_in_dist - math.sqrt(tmp)) / arel_projection_in_dist
  586. t2 = (-1 * vrel_projection_in_dist + math.sqrt(tmp)) / arel_projection_in_dist
  587. if t1 > 0 and t2 > 0:
  588. if t1 >= t2:
  589. MTTC = t2
  590. elif t1 < t2:
  591. MTTC = t1
  592. elif t1 > 0 and t2 <= 0:
  593. MTTC = t1
  594. elif t1 <= 0 and t2 > 0:
  595. MTTC = t2
  596. if arel_projection_in_dist == 0 and vrel_projection_in_dist > 0:
  597. MTTC = dist / vrel_projection_in_dist
  598. return MTTC
  599. # THW (time headway)
  600. def _cal_THW(self, dist, v_ego_projection_in_dist):
  601. if not v_ego_projection_in_dist:
  602. THW = None
  603. else:
  604. THW = dist / v_ego_projection_in_dist
  605. return THW
  606. # TLC (time to line crossing)
  607. def _cal_TLC(self, ego_v, ego_yaw, laneOffset):
  608. TLC = laneOffset/ego_v/np.sin(ego_yaw) if ((ego_v != 0) and (np.sin(ego_yaw) != 0)) else 10.0
  609. if TLC < 0:
  610. TLC = None
  611. return TLC
  612. def _cal_TTB(self, x_relative_start_dist, relative_v, ego_decel_max):
  613. if len(x_relative_start_dist):
  614. return None
  615. if (ego_decel_max == 0) or (relative_v == 0):
  616. return self.calculated_value["TTB"]
  617. else:
  618. x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
  619. TTB = (x_relative_start_dist0 + relative_v * relative_v/2/ego_decel_max)/relative_v
  620. return TTB
  621. def _cal_TM(self, x_relative_start_dist, v2, a2, v1, a1):
  622. if len(x_relative_start_dist):
  623. return None
  624. if (a2 == 0) or (v1 == 0):
  625. return self.calculated_value["TM"]
  626. if a1 == 0:
  627. return None
  628. x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
  629. TM = (x_relative_start_dist0 + v2**2/(2*a2) - v1**2/(2*a1)) / v1
  630. return TM
  631. # def _cal_MPrTTC(self, T=5, c = False, collision_dist = 5.99):
  632. # time_interval = self.ego_df['simTime'].tolist()[1] - self.ego_df['simTime'].tolist()[0]
  633. #
  634. # for i in range(len(self.obj_id_list)):
  635. # for j in range(T):
  636. # MPrTTC = j * time_interval
  637. def _cal_DTC(self, v_on_dist, a_on_dist, t):
  638. if a_on_dist == 0:
  639. return None
  640. DTC = v_on_dist * t + v_on_dist ** 2 / a_on_dist
  641. return DTC
  642. def _cal_PET(self, lane_posx1, lane_posy1, lane_posx2, lane_posy2, ramp_posx1, ramp_posy1, ramp_posx2, ramp_posy2, ego_posx, ego_posy, obj_posx, obj_posy, lane_width, delta_t, v1, v2, a1, a2):
  643. dist1 = self.horizontal_distance(lane_posx1, lane_posy1, lane_posx2, lane_posy2, ego_posx, ego_posy)
  644. dist2 = self.horizontal_distance(ramp_posx1, ramp_posy1, ramp_posx2, ramp_posy2, obj_posx, obj_posy)
  645. if ((dist1 <= lane_width/2) and (self._is_alone_the_road(lane_posx1, lane_posy1, lane_posx2, lane_posy2, ego_posx, ego_posy))
  646. and (self._is_in_the_road(ramp_posx1, ramp_posy1, ramp_posx2, ramp_posy2, obj_posx, obj_posy))
  647. and (dist2 <= lane_width/2) and (a1 != 0) and (a2 != 0)):
  648. dist_ego = np.sqrt((ego_posx - lane_posx1)**2 + (ego_posy-lane_posy1)**2)
  649. dist_obj = np.sqrt((obj_posx - ramp_posx2)**2 + (obj_posy-ramp_posy2)**2)
  650. PET = (-2*v2 + np.sqrt((4* v2**2)-8*a2*(v2*delta_t - dist_obj)))/ 2/ a2 - (2*v1 + np.sqrt((4* v1**2)-8*a1*dist_ego))/ 2/ a1 + delta_t
  651. return PET
  652. else:
  653. return None
  654. def _cal_PSD(self, x_relative_start_dist, v1, ego_decel_lon_max):
  655. if v1 == 0:
  656. return None
  657. else:
  658. if len(x_relative_start_dist) > 0:
  659. x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
  660. PSD = x_relative_start_dist0 * 2 * ego_decel_lon_max / v1
  661. return PSD
  662. else:
  663. return None
  664. def velocity(self, v_x, v_y):
  665. v = math.sqrt(v_x ** 2 + v_y ** 2) * 3.6
  666. return v
  667. def _cal_longitudinal_safe_dist(self, v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min, ego_decel_max):
  668. lon_dist_min = v_ego_p * rho + ego_accel_max * (rho ** 2) / 2 + (v_ego_p + rho * ego_accel_max) ** 2 / (
  669. 2 * ego_decel_min) - v_obj_p ** 2 / (2 * ego_decel_max)
  670. return lon_dist_min
  671. def _cal_lateral_safe_dist(self, lat_dist, v_right, v_left, rho, a_right_lat_brake_min,
  672. a_left_lat_brake_min, a_lat_max):
  673. # 检查除数是否为零
  674. if a_right_lat_brake_min == 0 or a_left_lat_brake_min == 0:
  675. return self._default_value('LatSD') # 返回默认值
  676. v_right_rho = v_right + rho * a_lat_max
  677. v_left_rho = v_left + rho * a_lat_max
  678. dist_min = lat_dist + (
  679. (v_right + v_right_rho) * rho / 2
  680. + v_right_rho**2 / a_right_lat_brake_min / 2
  681. + ((v_left + v_right_rho) * rho / 2)
  682. + v_left_rho**2 / a_left_lat_brake_min / 2
  683. )
  684. return dist_min
  685. # DRAC (decelerate required avoid collision)
  686. def _cal_DRAC(self, dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2):
  687. dist_length = dist - (len2 / 2 - o_x2 + len1 / 2 + o_x1) # 4.671
  688. if dist_length < 0:
  689. dist_width = dist - (width2 / 2 + width1 / 2)
  690. if dist_width < 0:
  691. return math.inf
  692. else:
  693. d = dist_width
  694. else:
  695. d = dist_length
  696. DRAC = vrel_projection_in_dist ** 2 / (2 * d)
  697. return DRAC
  698. # BTN (brake threat number)
  699. def _cal_BTN_new(self, lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max):
  700. BTN = (lon_a1 + lon_a - lon_v ** 2 / (2 * lon_d)) / ego_decel_lon_max # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
  701. return BTN
  702. # STN (steer threat number)
  703. def _cal_STN_new(self, ttc, lat_a1, lat_a, lat_d, lat_v, ego_decel_lat_max, width1, width2):
  704. STN = (lat_a1 + lat_a + 2 / ttc ** 2 * (lat_d + abs(ego_decel_lat_max * lat_v) * (
  705. width1 + width2) / 2 + abs(lat_v * ttc))) / ego_decel_lat_max
  706. return STN
  707. # BTN (brake threat number)
  708. def cal_BTN(self, a_y1, ay, dy, vy, max_ay):
  709. BTN = (a_y1 + ay - vy ** 2 / (2 * dy)) / max_ay # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
  710. return BTN
  711. # STN (steer threat number)
  712. def cal_STN(self, ttc, a_x1, ax, dx, vx, max_ax, width1, width2):
  713. STN = (a_x1 + ax + 2 / ttc ** 2 * (dx + np.sign(max_ax * vx) * (width1 + width2) / 2 + vx * ttc)) / max_ax
  714. return STN
  715. # 追尾碰撞风险
  716. def _normal_distribution(self, x):
  717. mean = 1.32
  718. std_dev = 0.26
  719. return (1 / (math.sqrt(std_dev * 2 * math.pi))) * math.exp(-0.5 * (x - mean) ** 2 / std_dev)
  720. def continuous_group(self, df):
  721. time_list = df['simTime'].values.tolist()
  722. frame_list = df['simFrame'].values.tolist()
  723. group_time = []
  724. group_frame = []
  725. sub_group_time = []
  726. sub_group_frame = []
  727. for i in range(len(frame_list)):
  728. if not sub_group_time or frame_list[i] - frame_list[i - 1] <= 1:
  729. sub_group_time.append(time_list[i])
  730. sub_group_frame.append(frame_list[i])
  731. else:
  732. group_time.append(sub_group_time)
  733. group_frame.append(sub_group_frame)
  734. sub_group_time = [time_list[i]]
  735. sub_group_frame = [frame_list[i]]
  736. group_time.append(sub_group_time)
  737. group_frame.append(sub_group_frame)
  738. group_time = [g for g in group_time if len(g) >= 2]
  739. group_frame = [g for g in group_frame if len(g) >= 2]
  740. # 输出图表值
  741. time = [[g[0], g[-1]] for g in group_time]
  742. frame = [[g[0], g[-1]] for g in group_frame]
  743. unfunc_time_df = pd.DataFrame(time, columns=['start_time', 'end_time'])
  744. unfunc_frame_df = pd.DataFrame(frame, columns=['start_frame', 'end_frame'])
  745. unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
  746. return unfunc_df
  747. # 统计最危险的指标
  748. def _safe_statistic_most_dangerous(self):
  749. min_list = ['TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'LonSD', 'LatSD', 'TM', 'PET', 'PSD']
  750. max_list = ['DTC', 'BTN', 'collisionRisk', 'collisionSeverity']
  751. result = {}
  752. for metric in min_list:
  753. if metric in self.metric_list:
  754. if metric in self.df.columns:
  755. val = self.df[metric].min()
  756. result[metric] = float(val) if pd.notnull(val) else self._default_value(metric)
  757. else:
  758. result[metric] = self._default_value(metric)
  759. for metric in max_list:
  760. if metric in self.metric_list:
  761. if metric in self.df.columns:
  762. val = self.df[metric].max()
  763. result[metric] = float(val) if pd.notnull(val) else self._default_value(metric)
  764. else:
  765. result[metric] = self._default_value(metric)
  766. return result
  767. def _safe_no_obj_statistic(self):
  768. # 仅有自车时的默认值
  769. result = {metric: self._default_value(metric) for metric in self.metric_list}
  770. return result
  771. def _default_value(self, metric):
  772. # 统一默认值
  773. defaults = {
  774. 'TTC': 10.0,
  775. 'MTTC': 4.2,
  776. 'THW': 2.1,
  777. 'TLC': 10.0,
  778. 'TTB': 10.0,
  779. 'TM': 10.0,
  780. 'DTC': 10.0,
  781. 'PET': 10.0,
  782. 'PSD': 10.0,
  783. 'LonSD': 10.0,
  784. 'LatSD': 2.0,
  785. 'BTN': 1.0,
  786. 'collisionRisk': 0.0,
  787. 'collisionSeverity': 0.0
  788. }
  789. return defaults.get(metric, None)
  790. def report_statistic(self):
  791. if len(self.obj_id_list) == 1:
  792. safety_result = self._safe_no_obj_statistic()
  793. else:
  794. safety_result = self._safe_statistic_most_dangerous()
  795. evaluator = Score(self.data_processed.safety_config)
  796. result = evaluator.evaluate(safety_result)
  797. print("\n[安全性表现及得分情况]")
  798. return result
  799. def get_ttc_value(self) -> float:
  800. if self.empty_flag or self.df_safe is None:
  801. return self._default_value('TTC')
  802. ttc_values = self.df_safe['TTC'].dropna()
  803. return float(ttc_values.min()) if not ttc_values.empty else self._default_value('TTC')
  804. def get_mttc_value(self) -> float:
  805. if self.empty_flag or self.df_safe is None:
  806. return self._default_value('MTTC')
  807. mttc_values = self.df_safe['MTTC'].dropna()
  808. return float(mttc_values.min()) if not mttc_values.empty else self._default_value('MTTC')
  809. def get_thw_value(self) -> float:
  810. if self.empty_flag or self.df_safe is None:
  811. return self._default_value('THW')
  812. thw_values = self.df_safe['THW'].dropna()
  813. return float(thw_values.min()) if not thw_values.empty else self._default_value('THW')
  814. def get_tlc_value(self) -> float:
  815. if self.empty_flag or self.df_safe is None:
  816. return self._default_value('TLC')
  817. tlc_values = self.df_safe['TLC'].dropna()
  818. return float(tlc_values.min()) if not tlc_values.empty else self._default_value('TLC')
  819. def get_ttb_value(self) -> float:
  820. if self.empty_flag or self.df_safe is None:
  821. return self._default_value('TTB')
  822. ttb_values = self.df_safe['TTB'].dropna()
  823. return float(ttb_values.min()) if not ttb_values.empty else self._default_value('TTB')
  824. def get_tm_value(self) -> float:
  825. if self.empty_flag or self.df_safe is None:
  826. return self._default_value('TM')
  827. tm_values = self.df_safe['TM'].dropna()
  828. return float(tm_values.min()) if not tm_values.empty else self._default_value('TM')
  829. def get_dtc_value(self) -> float:
  830. if self.empty_flag or self.df_safe is None:
  831. return self._default_value('DTC')
  832. dtc_values = self.df_safe['DTC'].dropna()
  833. return float(dtc_values.min()) if not dtc_values.empty else self._default_value('DTC')
  834. def get_pet_value(self) -> float:
  835. if self.empty_flag or self.df_safe is None:
  836. return self._default_value('PET')
  837. pet_values = self.df_safe['PET'].dropna()
  838. return float(pet_values.min()) if not pet_values.empty else self._default_value('PET')
  839. def get_psd_value(self) -> float:
  840. if self.empty_flag or self.df_safe is None:
  841. return self._default_value('PSD')
  842. psd_values = self.df_safe['PSD'].dropna()
  843. return float(psd_values.min()) if not psd_values.empty else self._default_value('PSD')
  844. def get_lonsd_value(self) -> float:
  845. if self.empty_flag or self.df_safe is None:
  846. return self._default_value('LonSD')
  847. lonsd_values = self.df_safe['LonSD'].dropna()
  848. return float(lonsd_values.mean()) if not lonsd_values.empty else self._default_value('LonSD')
  849. def get_latsd_value(self) -> float:
  850. if self.empty_flag or self.df_safe is None:
  851. return self._default_value('LatSD')
  852. latsd_values = self.df_safe['LatSD'].dropna()
  853. # 使用最小值而非平均值,与safety1.py保持一致
  854. return float(latsd_values.min()) if not latsd_values.empty else self._default_value('LatSD')
  855. def get_btn_value(self) -> float:
  856. if self.empty_flag or self.df_safe is None:
  857. return self._default_value('BTN')
  858. btn_values = self.df_safe['BTN'].dropna()
  859. return float(btn_values.max()) if not btn_values.empty else self._default_value('BTN')
  860. def get_collision_risk_value(self) -> float:
  861. if self.empty_flag or self.df_safe is None:
  862. return self._default_value('collisionRisk')
  863. risk_values = self.df_safe['collisionRisk'].dropna()
  864. return float(risk_values.max()) if not risk_values.empty else self._default_value('collisionRisk')
  865. def get_collision_severity_value(self) -> float:
  866. if self.empty_flag or self.df_safe is None:
  867. return self._default_value('collisionSeverity')
  868. severity_values = self.df_safe['collisionSeverity'].dropna()
  869. return float(severity_values.max()) if not severity_values.empty else self._default_value('collisionSeverity')