single_case_eval.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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: yangzihao(yangzihao@china-icv.cn)
  10. @Data: 2024/01/30
  11. @Last Modified: 2024/01/30
  12. @Summary: Evaluateion functions
  13. """
  14. import os
  15. import sys
  16. sys.path.append('../config')
  17. sys.path.append('../common')
  18. sys.path.append('../modules')
  19. sys.path.append('../results')
  20. import json
  21. import traceback
  22. import pandas as pd
  23. import log
  24. from config_parser import ConfigParse
  25. from single_case_evaluate import single_case_evaluate, single_case_statistic
  26. from common import df2csv, dict2json
  27. from data_quality import frame_loss_statistic
  28. def single_case_eval(configPath, dataPath, reportPath, csvPath, playbackPath, customMetricPath, customScorePath,
  29. case_name):
  30. logger = log.get_logger()
  31. # case_name = os.path.basename(os.path.dirname(dataPath))
  32. # 判断文件夹是否为空
  33. if len(os.listdir(dataPath)) == 0:
  34. print("No files in data_path!") # 路径异常
  35. logger.error(f"[case:{case_name}] SINGLE_CASE_EVAL: No files in data_path!")
  36. sys.exit(-1)
  37. # 加载配置文件
  38. try:
  39. # json_file = os.path.join(configPath, 'config.json')
  40. config = ConfigParse(configPath)
  41. except Exception as e:
  42. print('Config file parsing ERROR!', e)
  43. traceback.print_exc()
  44. logger.error(f"[case:{case_name}] SINGLE_CASE_EVAL: Config file parsing ERROR: {repr(e)}!", exc_info=True)
  45. sys.exit(-1)
  46. # data quality detect
  47. is_bad_quality = data_quality_detect(dataPath, case_name)
  48. if is_bad_quality:
  49. print("Frame loss > 10%, system exit.")
  50. # sys.exit(-1)
  51. # data complement
  52. """
  53. TODO: data complement
  54. """
  55. # 单用例评价,并生成报告
  56. try:
  57. case_dict = single_case_evaluate(dataPath, config, customMetricPath, customScorePath, case_name) # 评估单用例
  58. single_case_dict = single_case_statistic(case_dict) # 对单用例结果增加内容,并生成报告
  59. # 回放
  60. df2csv(case_dict['playbackData'], playbackPath)
  61. # 将DataFrame保存为csv文件
  62. df2csv(case_dict['evalData'], csvPath)
  63. # 将单用例测试结果保存为json文件
  64. single_case_dict.pop('playbackData')
  65. single_case_dict.pop('evalData')
  66. dict2json(single_case_dict, reportPath)
  67. except Exception as e:
  68. traceback.print_exc()
  69. logger.error(f"[case:{case_name}] SINGLE_CASE_EVAL: Evaluate single case ERROR: {repr(e)}!", exc_info=True)
  70. # guarantee_result(reportPath, csvPath, playbackPath) # 保底生成文件
  71. sys.exit(-1)
  72. def data_quality_detect(dataPath, case_name):
  73. logger = log.get_logger()
  74. # FIRST_ORDER_LOSS = 0.01 # first : little loss 100
  75. SECOND_ORDER_LOSS = 0.05 # second : could use 95
  76. THIRD_ORDER_LOSS = 0.10 # third : could not use 90
  77. is_bad_quality = False
  78. try:
  79. frame_loss_dict = frame_loss_statistic(dataPath)
  80. except Exception as e:
  81. traceback.print_exc()
  82. logger.error(f"[case:{case_name}] SINGLE_CASE_EVAL: frame loss statistic ERROR: {repr(e)}!", exc_info=True)
  83. is_bad_quality = True
  84. return is_bad_quality
  85. for key, value in frame_loss_dict.items():
  86. # sensor data
  87. sensor_data = ["RoadMark", "RoadPos", "TrafficLight", "TrafficSign"]
  88. if any(file in key for file in sensor_data):
  89. logger.info(f"[case:{case_name}] SINGLE_CASE_EVAL: [{key}] : {value['result']}")
  90. continue
  91. if value['frame_loss_rate'] > THIRD_ORDER_LOSS:
  92. is_bad_quality = True
  93. logger.error(
  94. f"[case:{case_name}] SINGLE_CASE_EVAL: [{key}] frame loss rate > {THIRD_ORDER_LOSS * 100}%: {value['result']}")
  95. elif value['frame_loss_rate'] > SECOND_ORDER_LOSS:
  96. logger.info(
  97. f"[case:{case_name}] SINGLE_CASE_EVAL: [{key}] frame loss rate > {SECOND_ORDER_LOSS * 100}%: {value['result']}")
  98. else:
  99. logger.info(
  100. f"[case:{case_name}] SINGLE_CASE_EVAL: [{key}] frame loss rate < {SECOND_ORDER_LOSS * 100}%: {value['result']}")
  101. return is_bad_quality
  102. def guarantee_result(reportPath, csvPath, playbackPath):
  103. result = {
  104. "details": {
  105. "safe": {
  106. "name": "安全性",
  107. "weight": "100.00%",
  108. "collisionRisk": 0,
  109. "noObjectCar": "false",
  110. "score": 100,
  111. "level": "优秀",
  112. "weightDistribution": {
  113. "name": "安全性",
  114. "safeTime": {
  115. "weight": "时间类型(27.71%)",
  116. "indexes": {
  117. "TTC": "TTC(18.34%)",
  118. "MTTC": "MTTC(50.01%)",
  119. "THW": "THW(31.65%)"
  120. }
  121. },
  122. "safeDistance": {
  123. "weight": "距离类型(44.37%)",
  124. "indexes": {
  125. "LonSD": "LonSD(76.80%)",
  126. "LatSD": "LatSD(23.20%)"
  127. }
  128. },
  129. "safeAcceleration": {
  130. "weight": "加速度类型(2.60%)",
  131. "indexes": {
  132. "DRAC": "DRAC(66.67%)",
  133. "BTN": "BTN(6.22%)",
  134. "STN": "STN(27.11%)"
  135. }
  136. },
  137. "safeProbability": {
  138. "weight": "概率类型(25.32%)",
  139. "indexes": {
  140. "collisionRisk": "碰撞风险概率(50.00%)",
  141. "collisionSeverity": "碰撞严重程度(50.00%)"
  142. }
  143. }
  144. },
  145. "details": {
  146. "safeTime": {
  147. "name": "时间类型",
  148. "score": 100,
  149. "level": "较差",
  150. "description1": "TTC和THW指标表现良好,MTTC指标表现不佳,MTTC极值超过合理范围73.59%",
  151. "description2": "TTC和THW指标均在合理范围内,表现良好,MTTC指标共有0.32秒超出合理范围,算法应加强在该时间段对跟车距离的控制",
  152. "indexes": {
  153. "TTC": {
  154. "name": "TTC",
  155. "meaning": "TTC",
  156. "score": 100,
  157. "extremum": "3.76",
  158. "range": "[2.86, inf)",
  159. "rate": "100%"
  160. },
  161. "MTTC": {
  162. "name": "MTTC",
  163. "meaning": "MTTC",
  164. "score": 100,
  165. "extremum": "0.32",
  166. "range": "[1.2, inf)",
  167. "rate": "98.9%"
  168. },
  169. "THW": {
  170. "name": "THW",
  171. "meaning": "THW",
  172. "score": 100,
  173. "extremum": "2.98",
  174. "range": "[0.4, inf)",
  175. "rate": "100%"
  176. }
  177. },
  178. "builtin": {
  179. "MTTC": {
  180. "name": "MTTC",
  181. "data": [],
  182. "range": "[1.2, inf)"
  183. },
  184. "THW": {
  185. "name": "THW",
  186. "data": [],
  187. "range": "[0.4, inf)"
  188. }
  189. },
  190. "custom": {}
  191. },
  192. },
  193. "description1": "未满足设计指标要求。算法在本轮测试中有碰撞风险,需要提高算法在时间类型和距离类型上的表现。在时间类型和距离类型中,MTTC指标共有0.32秒超出合理范围;LonSD指标共有3.93秒超出合理范围;STN指标共有0.07秒超出合理范围;",
  194. "description2": "安全性在时间类型和距离类型上存在严重风险,需要重点优化。",
  195. },
  196. "commonData": {
  197. "per": {
  198. "name": "脚刹/油门踏板开度(百分比)",
  199. "legend": [
  200. "刹车踏板开度",
  201. "油门踏板开度"
  202. ],
  203. "data": []
  204. },
  205. "ang": {
  206. "name": "方向盘转角(角度°)",
  207. "data": []
  208. },
  209. "spe": {
  210. "name": "速度(km/h)",
  211. "legend": [
  212. "自车速度",
  213. "目标车速度",
  214. "自车与目标车相对速度"
  215. ],
  216. "data": []
  217. },
  218. "acc": {
  219. "name": "加速度(m/s²)",
  220. "legend": [
  221. "横向加速度",
  222. "纵向加速度"
  223. ],
  224. "data": []
  225. },
  226. "dis": {
  227. "name": "前车距离(m)",
  228. "data": []
  229. },
  230. "ttc": {
  231. "name": "TTC(m)",
  232. "data": []
  233. }
  234. },
  235. "commonMarkLine": []
  236. },
  237. "algorithmComprehensiveScore": 100,
  238. "algorithmLevel": "优秀",
  239. "testMileage": "0.00米",
  240. "testDuration": "0.00秒",
  241. "algorithmResultDescription1": "车辆在本轮测试中,未出现违反交通规则行为、跟停行为和不舒适行为。",
  242. "algorithmResultDescription2": "综上所述,算法表现良好。"
  243. }
  244. with open(f'{reportPath}', 'w', encoding='utf-8') as f:
  245. f.write(json.dumps(result, ensure_ascii=False))
  246. eval_data_columns = ['simTime', 'simFrame', 'playerId', 'type', 'posX', 'posY', 'posZ', 'posH', 'speedX', 'speedY',
  247. 'speedZ', 'accelX', 'accelY', 'accelZ', 'dimX', 'dimY', 'dimZ', 'offX', 'speedH', 'accelH',
  248. 'travelDist']
  249. eval_data_df = pd.DataFrame(columns=eval_data_columns)
  250. eval_data_df.to_csv(f'{csvPath}', index=False)
  251. playback_data_columns = ['simTime', 'simFrame', 'speed', 'curvHor', 'rollRel', 'pitchRel', 'latSpeedRel',
  252. 'lonSpeedRel', 'latDistanceRel', 'lonDistanceRel']
  253. playback_data_df = pd.DataFrame(columns=playback_data_columns)
  254. playback_data_df.to_csv(f'{playbackPath}', index=False)