Browse Source

根据交通信号识别及响应数据修改新增功能性指标中的bug;去掉安全性中PET指标;增加PGVIL中的画图功能

XGJ_zhaoyuan 5 months ago
parent
commit
92bfcb679d

+ 42 - 22
config/all_metrics_config.yaml

@@ -71,6 +71,11 @@ safety:
       priority: 0
       priority: 0
       max: 2000.0
       max: 2000.0
       min: 2.0
       min: 2.0
+    DTC:
+      name: DTC
+      priority: 0
+      max: 2000.0
+      min: 2.0
   safeAcceleration:
   safeAcceleration:
     name: safeAcceleration
     name: safeAcceleration
     priority: 0
     priority: 0
@@ -92,6 +97,11 @@ safety:
       priority: 0
       priority: 0
       max: 10.0
       max: 10.0
       min: 0.0
       min: 0.0
+    PSD:
+      name: PSD
+      priority: 0
+      max: 2000.0
+      min: 2.0
 
 
 user:
 user:
   name: user
   name: user
@@ -216,29 +226,39 @@ efficient:
 function:
 function:
   name: function
   name: function
   priority: 0
   priority: 0
-  ForwardCollision:
-    name: ForwardCollision
+  TrafficSignalRecognitionAndResponse:
+    name: TrafficSignalRecognitionAndResponse
     priority: 0
     priority: 0
-    latestWarningDistance_TTC_LST:
-      name: latestWarningDistance_TTC_LST
-      priority: 0
-      max: 3.11
-      min: 1.89
-    earliestWarningDistance_TTC_LST:
-      name: earliestWarningDistance_TTC_LST
-      priority: 0
-      max: 3.11
-      min: 1.89
-    latestWarningDistance_LST:
-      name: latestWarningDistance_LST
-      priority: 0
-      max: 17.29
-      min: 10.51
-    earliestWarningDistance_LST:
-      name: earliestWarningDistance_LST
-      priority: 0
-      max: 17.29
-      min: 10.51
+    limitSpeed_LST:
+      name: limitSpeed_LST
+      priority: 0
+      max: 0
+      min: 30
+    leastDistance_LST:
+      name: leastDistance_LST
+      priority: 0
+      max: 0
+      min: 4
+    launchTimeinStopLine_LST:
+      name: launchTimeinStopLine_LST
+      priority: 0
+      max: 0
+      min: 5
+    noStop_LST:
+      name: noStop_LST
+      priority: 0
+      max: 0
+      min: 1
+    launchTimeinTrafficLight_LST:
+      name: launchTimeinTrafficLight_LST
+      priority: 0
+      max: 0
+      min: 5
+    crossJunctionToTargetLane_LST:
+      name: crossJunctionToTargetLane_LST
+      priority: 0
+      max: 1
+      min: 1
       
       
 traffic:
 traffic:
   name: traffic
   name: traffic

+ 308 - 3
modules/lib/chart_generator.py

@@ -110,6 +110,15 @@ def generate_function_chart_data(function_calculator, metric_name: str, output_d
             return generate_earliest_warning_distance_chart(function_calculator, output_dir)
             return generate_earliest_warning_distance_chart(function_calculator, output_dir)
         elif metric_name.lower() == 'latestwarningdistance_lst':
         elif metric_name.lower() == 'latestwarningdistance_lst':
             return generate_latest_warning_distance_chart(function_calculator, output_dir)
             return generate_latest_warning_distance_chart(function_calculator, output_dir)
+        elif metric_name.lower() == 'latestwarningdistance_ttc_pgvil':
+            return generate_latest_warning_ttc_pgvil_chart(function_calculator, output_dir)
+        elif metric_name.lower() == 'earliestwarningdistance_ttc_pgvil':
+            return generate_earliest_warning_distance_ttc_pgvil_chart(function_calculator, output_dir)
+
+        elif metric_name.lower() == 'earliestwarningdistance_pgvil':
+            return generate_earliest_warning_distance_pgvil_chart(function_calculator, output_dir)
+        elif metric_name.lower() == 'latestwarningdistance_pgvil':
+            return generate_latest_warning_distance_pgvil_chart(function_calculator, output_dir)
 
 
         elif metric_name.lower() == 'limitspeed_lst':
         elif metric_name.lower() == 'limitspeed_lst':
             return generate_limit_speed_chart(function_calculator, output_dir)
             return generate_limit_speed_chart(function_calculator, output_dir)
@@ -219,7 +228,7 @@ def generate_earliest_warning_distance_chart(function_calculator, output_dir: st
 def generate_earliest_warning_distance_pgvil_chart(function_calculator, output_dir: str) -> Optional[str]:
 def generate_earliest_warning_distance_pgvil_chart(function_calculator, output_dir: str) -> Optional[str]:
     """
     """
     Generate warning distance chart with data visualization.
     Generate warning distance chart with data visualization.
-    This function creates charts for earliestWarningDistance_LST and latestWarningDistance_LST metrics.
+    This function creates charts for earliestWarningDistance_PGVIL and latestWarningDistance_PGVIL metrics.
 
 
     Args:
     Args:
         function_calculator: FunctionCalculator instance
         function_calculator: FunctionCalculator instance
@@ -244,6 +253,7 @@ def generate_earliest_warning_distance_pgvil_chart(function_calculator, output_d
 
 
         # Get calculated warning distance and speed
         # Get calculated warning distance and speed
         warning_dist = getattr(function_calculator, 'warning_dist', None)
         warning_dist = getattr(function_calculator, 'warning_dist', None)
+        warning_time = getattr(function_calculator, 'warning_time', None)
 
 
         if warning_dist.empty:
         if warning_dist.empty:
             logger.warning(f"Cannot generate {"earliestWarningDistance_LST"} chart: empty data")
             logger.warning(f"Cannot generate {"earliestWarningDistance_LST"} chart: empty data")
@@ -255,7 +265,7 @@ def generate_earliest_warning_distance_pgvil_chart(function_calculator, output_d
         # Save CSV data
         # Save CSV data
         csv_filename = os.path.join(output_dir, f"earliestWarningDistance_PGVIL_data.csv")
         csv_filename = os.path.join(output_dir, f"earliestWarningDistance_PGVIL_data.csv")
         df_csv = pd.DataFrame({
         df_csv = pd.DataFrame({
-            'simTime': ego_df[(ego_df['ifwarning'] == correctwarning) & (ego_df['ifwarning'].notna())]['simTime'],
+            'simTime': warning_time,
             'warning_distance': warning_dist,
             'warning_distance': warning_dist,
             'min_threshold': min_threshold,
             'min_threshold': min_threshold,
             'max_threshold': max_threshold,
             'max_threshold': max_threshold,
@@ -309,6 +319,113 @@ def generate_earliest_warning_distance_pgvil_chart(function_calculator, output_d
 # from modules.metric.function import find_nested_name
 # from modules.metric.function import find_nested_name
 
 
 
 
+def generate_latest_warning_ttc_pgvil_chart(function_calculator, output_dir: str) -> Optional[str]:
+    """
+    Generate TTC warning chart with data visualization.
+    This version first saves data to CSV, then uses the CSV to generate the chart.
+
+    Args:
+        function_calculator: FunctionCalculator instance
+        output_dir: Output directory
+
+    Returns:
+        str: Chart file path, or None if generation fails
+    """
+    logger = LogManager().get_logger()
+
+    try:
+        # 获取数据
+        ego_df = function_calculator.ego_data.copy()
+        correctwarning = getattr(function_calculator, 'correctwarning', None)
+        # 获取配置的阈值
+
+        thresholds = get_metric_thresholds(function_calculator, 'latestWarningDistance_TTC_PGVIL')
+        max_threshold = thresholds["max"]
+        min_threshold = thresholds["min"]
+
+        warning_dist = getattr(function_calculator, 'warning_dist', None)
+        warning_speed = getattr(function_calculator, 'warning_speed', None)
+        warning_time = getattr(function_calculator, 'warning_time', None)
+        ttc = getattr(function_calculator, 'ttc', None)
+
+        if warning_dist.empty:
+            logger.warning("Cannot generate TTC warning chart: empty data")
+            return None
+
+        # 生成时间戳
+
+        # 保存 CSV 数据
+        csv_filename = os.path.join(output_dir, f"latestwarningdistance_ttc_pgvil_data.csv")
+        df_csv = pd.DataFrame({
+            'simTime': ego_df['simTime'],
+            'warning_distance': warning_dist,
+            'warning_speed': warning_speed,
+            'ttc': ttc,
+            'min_threshold': min_threshold,
+            'max_threshold': max_threshold,
+        })
+        df_csv.to_csv(csv_filename, index=False)
+        logger.info(f"latestwarningdistance_ttc_pgvil data saved to: {csv_filename}")
+
+        # 从 CSV 读取数据
+        df = pd.read_csv(csv_filename)
+
+        # 创建图表
+        plt.figure(figsize=(12, 8), constrained_layout=True)
+
+        # 图 1:预警距离
+        ax1 = plt.subplot(3, 1, 1)
+        ax1.plot(df['simTime'], df['warning_distance'], 'b-', label='Warning Distance')
+        ax1.set_xlabel('Time (s)')
+        ax1.set_ylabel('Distance (m)')
+        ax1.set_title('Warning Distance Over Time')
+        ax1.grid(True)
+        ax1.legend()
+
+        # 图 2:相对速度
+        ax2 = plt.subplot(3, 1, 2)
+        ax2.plot(df['simTime'], df['warning_speed'], 'g-', label='Relative Speed')
+        ax2.set_xlabel('Time (s)')
+        ax2.set_ylabel('Speed (m/s)')
+        ax2.set_title('Relative Speed Over Time')
+        ax2.grid(True)
+        ax2.legend()
+
+        # 图 3:TTC
+        ax3 = plt.subplot(3, 1, 3)
+        ax3.plot(df['simTime'], df['ttc'], 'r-', label='TTC')
+
+        # Add threshold lines
+        ax3.axhline(y=max_threshold, color='r', linestyle='--', label=f'Max Threshold ({max_threshold}s)')
+        ax3.axhline(y=min_threshold, color='g', linestyle='--', label=f'Min Threshold ({min_threshold}s)')
+
+        # Calculate metric value (latest TTC)
+        metric_value = float(ttc[-1]) if len(ttc) > 0 else max_threshold
+
+        # Mark latest TTC value
+        if len(df) > 0:
+            ax3.scatter(df['simTime'].iloc[-1], df['ttc'].iloc[-1],
+                        color='red', s=100, zorder=5,
+                        label=f'Latest TTC: {metric_value:.2f}s')
+
+        ax3.set_xlabel('Time (s)')
+        ax3.set_ylabel('TTC (s)')
+        ax3.set_title('Time To Collision (TTC) Over Time')
+        ax3.grid(True)
+        ax3.legend()
+
+        # 保存图像
+        chart_filename = os.path.join(output_dir, f"latestwarningdistance_ttc_pgvil_chart.png")
+        plt.savefig(chart_filename, dpi=300)
+        plt.close()
+
+        logger.info(f"latestwarningdistance_ttc_pgvil chart saved to: {chart_filename}")
+        return chart_filename
+
+    except Exception as e:
+        logger.error(f"Failed to generate latestwarningdistance_ttc_pgvil chart: {str(e)}", exc_info=True)
+        return None
+
 def generate_latest_warning_ttc_chart(function_calculator, output_dir: str) -> Optional[str]:
 def generate_latest_warning_ttc_chart(function_calculator, output_dir: str) -> Optional[str]:
     """
     """
     Generate TTC warning chart with data visualization.
     Generate TTC warning chart with data visualization.
@@ -415,7 +532,6 @@ def generate_latest_warning_ttc_chart(function_calculator, output_dir: str) -> O
         logger.error(f"Failed to generate latestwarningdistance_ttc_lst chart: {str(e)}", exc_info=True)
         logger.error(f"Failed to generate latestwarningdistance_ttc_lst chart: {str(e)}", exc_info=True)
         return None
         return None
 
 
-
 def generate_latest_warning_distance_chart(function_calculator, output_dir: str) -> Optional[str]:
 def generate_latest_warning_distance_chart(function_calculator, output_dir: str) -> Optional[str]:
     """
     """
     Generate warning distance chart with data visualization.
     Generate warning distance chart with data visualization.
@@ -504,6 +620,95 @@ def generate_latest_warning_distance_chart(function_calculator, output_dir: str)
         logger.error(f"Failed to generate latestWarningDistance_LST chart: {str(e)}", exc_info=True)
         logger.error(f"Failed to generate latestWarningDistance_LST chart: {str(e)}", exc_info=True)
         return None
         return None
 
 
+def generate_latest_warning_distance_pgvil_chart(function_calculator, output_dir: str) -> Optional[str]:
+    """
+    Generate warning distance chart with data visualization.
+    This function creates charts for latestWarningDistance_LST metric.
+
+    Args:
+        function_calculator: FunctionCalculator instance
+        metric_name: Metric name (latestWarningDistance_LST)
+        output_dir: Output directory
+
+    Returns:
+        str: Chart file path, or None if generation fails
+    """
+    logger = LogManager().get_logger()
+
+    try:
+        # Get data
+        ego_df = function_calculator.ego_data.copy()
+        # Check if correctwarning is already calculated
+        correctwarning = getattr(function_calculator, 'correctwarning', None)
+
+        # Get configured thresholds
+        thresholds = get_metric_thresholds(function_calculator, 'latestWarningDistance_PGVIL')
+        max_threshold = thresholds["max"]
+        min_threshold = thresholds["min"]
+
+        # Get calculated warning distance and speed
+        warning_dist = getattr(function_calculator, 'warning_dist', None)
+        warning_time = getattr(function_calculator, 'warning_time', None)
+
+        if warning_dist.empty:
+            logger.warning(f"Cannot generate latestWarningDistance_PGVIL chart: empty data")
+            return None
+
+        # Calculate metric value
+        metric_value = float(warning_dist.iloc[-1]) if len(warning_dist) > 0 else max_threshold
+
+        # Save CSV data
+        csv_filename = os.path.join(output_dir, f"latestWarningDistance_PGVIL_data.csv")
+        df_csv = pd.DataFrame({
+            'simTime': ego_df['simTime'],
+            'warning_distance': warning_dist,
+            'min_threshold': min_threshold,
+            'max_threshold': max_threshold
+        })
+        df_csv.to_csv(csv_filename, index=False)
+        logger.info(f"latestWarningDistance_PGVIL data saved to: {csv_filename}")
+
+        # Read data from CSV
+        df = pd.read_csv(csv_filename)
+
+        # Create single chart for warning distance
+        plt.figure(figsize=(12, 6), constrained_layout=True)  # Adjusted height for single chart
+
+        # Plot warning distance
+        plt.plot(df['simTime'], df['warning_distance'], 'b-', label='Warning Distance')
+
+        # Add threshold lines
+        plt.axhline(y=max_threshold, color='r', linestyle='--', label=f'Max Threshold ({max_threshold}m)')
+        plt.axhline(y=min_threshold, color='g', linestyle='--', label=f'Min Threshold ({min_threshold}m)')
+
+        # Mark metric value
+        if len(df) > 0:
+            label_text = 'Latest Warning Distance'
+            plt.scatter(df['simTime'].iloc[-1], df['warning_distance'].iloc[-1],
+                        color='red', s=100, zorder=5,
+                        label=f'{label_text}: {metric_value:.2f}m')
+
+        # Set y-axis range
+        plt.ylim(bottom=-1, top=max(max_threshold * 1.1, df['warning_distance'].max() * 1.1))
+
+        plt.xlabel('Time (s)')
+        plt.ylabel('Distance (m)')
+        plt.title(f'latestWarningDistance_PGVIL - Warning Distance Over Time')
+        plt.grid(True)
+        plt.legend()
+
+        # Save image
+        chart_filename = os.path.join(output_dir, f"latestWarningDistance_PGVIL_chart.png")
+        plt.savefig(chart_filename, dpi=300)
+        plt.close()
+
+        logger.info(f"latestWarningDistance_PGVIL chart saved to: {chart_filename}")
+        return chart_filename
+
+    except Exception as e:
+        logger.error(f"Failed to generate latestWarningDistance_PGVIL chart: {str(e)}", exc_info=True)
+        return None
+
 
 
 def generate_earliest_warning_distance_ttc_chart(function_calculator, output_dir: str) -> Optional[str]:
 def generate_earliest_warning_distance_ttc_chart(function_calculator, output_dir: str) -> Optional[str]:
     """
     """
@@ -606,6 +811,106 @@ def generate_earliest_warning_distance_ttc_chart(function_calculator, output_dir
         logger.error(f"Failed to generate earliestwarningdistance_ttc_lst chart: {str(e)}", exc_info=True)
         logger.error(f"Failed to generate earliestwarningdistance_ttc_lst chart: {str(e)}", exc_info=True)
         return None
         return None
 
 
+def generate_earliest_warning_distance_ttc_pgvil_chart(function_calculator, output_dir: str) -> Optional[str]:
+    """
+    Generate TTC warning chart with data visualization for earliestWarningDistance_TTC_PGVIL metric.
+
+    Args:
+        function_calculator: FunctionCalculator instance
+        output_dir: Output directory
+
+    Returns:
+        str: Chart file path, or None if generation fails
+    """
+    logger = LogManager().get_logger()
+    metric_name = 'earliestWarningDistance_TTC_PGVIL'
+
+    try:
+        # Get data
+        ego_df = function_calculator.ego_data.copy()
+        # Check if correctwarning is already calculated
+        correctwarning = getattr(function_calculator, 'correctwarning', None)
+
+        # Get configured thresholds
+        thresholds = get_metric_thresholds(function_calculator, metric_name)
+        max_threshold = thresholds["max"]
+        min_threshold = thresholds["min"]
+
+        # Get calculated warning distance and speed
+        warning_dist = getattr(function_calculator, 'correctwarning', None)
+        warning_speed = getattr(function_calculator, 'warning_speed', None)
+        ttc = getattr(function_calculator, 'ttc', None)
+
+        # Calculate metric value
+        metric_value = float(ttc[0]) if len(ttc) > 0 else max_threshold
+        # Save CSV data
+        csv_filename = os.path.join(output_dir, f"{metric_name.lower()}_data.csv")
+        df_csv = pd.DataFrame({
+            'simTime': ego_df[(ego_df['ifwarning'] == correctwarning) & (ego_df['ifwarning'].notna())]['simTime'],
+            'warning_distance': warning_dist,
+            'warning_speed': warning_speed,
+            'ttc': ttc,
+            'min_threshold': min_threshold,
+            'max_threshold': max_threshold
+        })
+        df_csv.to_csv(csv_filename, index=False)
+        logger.info(f"{metric_name} data saved to: {csv_filename}")
+
+        # Read data from CSV
+        df = pd.read_csv(csv_filename)
+
+        # Create chart
+        plt.figure(figsize=(12, 8), constrained_layout=True)
+
+        # 图 1:预警距离
+        ax1 = plt.subplot(3, 1, 1)
+        ax1.plot(df['simTime'], df['warning_distance'], 'b-', label='Warning Distance')
+        ax1.set_xlabel('Time (s)')
+        ax1.set_ylabel('Distance (m)')
+        ax1.set_title('Warning Distance Over Time')
+        ax1.grid(True)
+        ax1.legend()
+
+        # 图 2:相对速度
+        ax2 = plt.subplot(3, 1, 2)
+        ax2.plot(df['simTime'], df['warning_speed'], 'g-', label='Relative Speed')
+        ax2.set_xlabel('Time (s)')
+        ax2.set_ylabel('Speed (m/s)')
+        ax2.set_title('Relative Speed Over Time')
+        ax2.grid(True)
+        ax2.legend()
+
+        # 图 3:TTC
+        ax3 = plt.subplot(3, 1, 3)
+        ax3.plot(df['simTime'], df['ttc'], 'r-', label='TTC')
+
+        # Add threshold lines
+        ax3.axhline(y=max_threshold, color='r', linestyle='--', label=f'Max Threshold ({max_threshold}s)')
+        ax3.axhline(y=min_threshold, color='g', linestyle='--', label=f'Min Threshold ({min_threshold}s)')
+
+        # Mark earliest TTC value
+        if len(df) > 0:
+            ax3.scatter(df['simTime'].iloc[0], df['ttc'].iloc[0],
+                        color='red', s=100, zorder=5,
+                        label=f'Earliest TTC: {metric_value:.2f}s')
+
+        ax3.set_xlabel('Time (s)')
+        ax3.set_ylabel('TTC (s)')
+        ax3.set_title('Time To Collision (TTC) Over Time')
+        ax3.grid(True)
+        ax3.legend()
+
+        # Save image
+        chart_filename = os.path.join(output_dir, f"earliestwarningdistance_ttc_pgvil_chart.png")
+        plt.savefig(chart_filename, dpi=300)
+        plt.close()
+
+        logger.info(f"{metric_name} chart saved to: {chart_filename}")
+        return chart_filename
+
+    except Exception as e:
+        logger.error(f"Failed to generate earliestwarningdistance_ttc_pgvil chart: {str(e)}", exc_info=True)
+        return None
 
 
 def generate_limit_speed_chart(function_calculator, output_dir: str) -> Optional[str]:
 def generate_limit_speed_chart(function_calculator, output_dir: str) -> Optional[str]:
     """
     """

+ 30 - 10
modules/metric/function.py

@@ -378,10 +378,10 @@ def leastDistance_LST(data):
     ego_df = data.ego_data
     ego_df = data.ego_data
     dist_row = ego_df[ego_df['v'] == 0]['relative_dist'].tolist()
     dist_row = ego_df[ego_df['v'] == 0]['relative_dist'].tolist()
     if len(dist_row) == 0:
     if len(dist_row) == 0:
-        return {"minimumDistance_LST": -1}
+        return {"leastDistance_LST": -1}
     else:
     else:
         min_dist = min(dist_row)
         min_dist = min(dist_row)
-        return {"minimumDistance_LST": min_dist}
+        return {"leastDistance_LST": min_dist}
 
 
 
 
 def launchTimeinStopLine_LST(data):
 def launchTimeinStopLine_LST(data):
@@ -409,9 +409,12 @@ def launchTimewhenFollowingCar_LST(data):
 
 
 
 
 def noStop_LST(data):
 def noStop_LST(data):
-    ego_df = data.ego_data
+    ego_df_ini = data.ego_data
+    min_time = ego_df_ini['simTime'].min() + 5
+    max_time = ego_df_ini['simTime'].max() - 5
+    ego_df = ego_df_ini[(ego_df_ini['simTime'] >= min_time) & (ego_df_ini['simTime'] <= max_time)]
     speed = ego_df['v'].tolist()
     speed = ego_df['v'].tolist()
-    if (speed.any() == 0):
+    if (any(speed) == 0):
         return {"noStop_LST": -1}
         return {"noStop_LST": -1}
     else:
     else:
         return {"noStop_LST": 1}
         return {"noStop_LST": 1}
@@ -426,7 +429,7 @@ def launchTimeinTrafficLight_LST(data):
     ego_df = data.ego_data
     ego_df = data.ego_data
     simtime_of_redlight = ego_df[ego_df['stateMask'] == 0]['simTime']
     simtime_of_redlight = ego_df[ego_df['stateMask'] == 0]['simTime']
     simtime_of_stop = ego_df[ego_df['v'] == 0]['simTime']
     simtime_of_stop = ego_df[ego_df['v'] == 0]['simTime']
-    if simtime_of_stop.empty() or simtime_of_redlight.empty():
+    if len(simtime_of_stop) or len(simtime_of_redlight):
         return {"timeInterval_LST": -1}
         return {"timeInterval_LST": -1}
     simtime_of_launch = simtime_of_redlight[simtime_of_redlight.isin(simtime_of_stop)].tolist()
     simtime_of_launch = simtime_of_redlight[simtime_of_redlight.isin(simtime_of_stop)].tolist()
     if len(simtime_of_launch) == 0:
     if len(simtime_of_launch) == 0:
@@ -437,7 +440,8 @@ def launchTimeinTrafficLight_LST(data):
 def crossJunctionToTargetLane_LST(data):
 def crossJunctionToTargetLane_LST(data):
     ego_df = data.ego_data
     ego_df = data.ego_data
     lane_in_leftturn = set(ego_df['lane_id'].tolist())
     lane_in_leftturn = set(ego_df['lane_id'].tolist())
-    target_lane_id = data.function_config["function"]["scenario"]["crossJunctionToTargetLane_LST"]['max']
+    scenario_name = find_nested_name(data.function_config["function"])
+    target_lane_id = data.function_config["function"][scenario_name]["crossJunctionToTargetLane_LST"]['max']
     if target_lane_id not in lane_in_leftturn:
     if target_lane_id not in lane_in_leftturn:
         return {"crossJunctionToTargetLane_LST": -1}
         return {"crossJunctionToTargetLane_LST": -1}
     else:
     else:
@@ -446,7 +450,8 @@ def crossJunctionToTargetLane_LST(data):
 
 
 def keepInLane_LST(data):
 def keepInLane_LST(data):
     ego_df = data.ego_data
     ego_df = data.ego_data
-    target_road_type = data.function_config["function"]["scenario"]["keepInLane_LST"]['max']
+    scenario_name = find_nested_name(data.function_config["function"])
+    target_road_type = data.function_config["function"][scenario_name]["keepInLane_LST"]['max']
     data_in_tunnel = ego_df[ego_df['road_type'] == target_road_type]
     data_in_tunnel = ego_df[ego_df['road_type'] == target_road_type]
     if data_in_tunnel.empty:
     if data_in_tunnel.empty:
         return {"keepInLane_LST": -1}
         return {"keepInLane_LST": -1}
@@ -513,7 +518,7 @@ def noCollision_LST(data):
 
 
 def noReverse_LST(data):
 def noReverse_LST(data):
     ego_df = data.ego_data
     ego_df = data.ego_data
-    if ego_df["lon_v_vehicle"] * ego_df["posH"].any() < 0:
+    if (ego_df["lon_v_vehicle"] * ego_df["posH"]).any() < 0:
         return {"noReverse_LST": -1}
         return {"noReverse_LST": -1}
     else:
     else:
         return {"noReverse_LST": 1}
         return {"noReverse_LST": 1}
@@ -530,7 +535,10 @@ def turnAround_LST(data):
 
 
 def laneOffset_LST(data):
 def laneOffset_LST(data):
     car_width = data.function_config['vehicle']['CAR_WIDTH']
     car_width = data.function_config['vehicle']['CAR_WIDTH']
-    ego_df = data.ego_data
+    ego_df_ini = data.ego_data
+    min_time = ego_df_ini['simTime'].min() + 5
+    max_time = ego_df_ini['simTime'].max() - 5
+    ego_df = ego_df_ini[(ego_df_ini['simTime'] >= min_time) & (ego_df_ini['simTime'] <= max_time)]
     laneoffset = ego_df['y_relative_dist'] - car_width / 2
     laneoffset = ego_df['y_relative_dist'] - car_width / 2
     return {"laneOffset_LST": max(laneoffset)}
     return {"laneOffset_LST": max(laneoffset)}
 
 
@@ -588,6 +596,9 @@ def latestWarningDistance_PGVIL(data_processed) -> dict:
     distances = calculate_distance_PGVIL(
     distances = calculate_distance_PGVIL(
         np.array([[ego["posX"], ego["posY"]]]), obj[["posX", "posY"]].values
         np.array([[ego["posX"], ego["posY"]]]), obj[["posX", "posY"]].values
     )
     )
+
+    # 将计算结果保存到data对象中,供图表生成使用
+    data_processed.warning_dist = distances
     if distances.size == 0:
     if distances.size == 0:
         print("没有找到数据!")
         print("没有找到数据!")
         return {"latestWarningDistance_PGVIL": 15}  # 或返回其他默认值,如0.0
         return {"latestWarningDistance_PGVIL": 15}  # 或返回其他默认值,如0.0
@@ -614,11 +625,15 @@ def latestWarningDistance_TTC_PGVIL(data_processed) -> dict:
     distances = calculate_distance_PGVIL(ego_pos, obj_pos)
     distances = calculate_distance_PGVIL(ego_pos, obj_pos)
     rel_speeds = calculate_relative_speed_PGVIL(ego_speed, obj_speed)
     rel_speeds = calculate_relative_speed_PGVIL(ego_speed, obj_speed)
 
 
+    data_processed.warning_dist = distances
+    data_processed.warning_speed = rel_speeds
+
     with np.errstate(divide="ignore", invalid="ignore"):
     with np.errstate(divide="ignore", invalid="ignore"):
         ttc = np.where(rel_speeds != 0, distances / rel_speeds, np.inf)
         ttc = np.where(rel_speeds != 0, distances / rel_speeds, np.inf)
     if ttc.size == 0:
     if ttc.size == 0:
         print("没有找到数据!")
         print("没有找到数据!")
         return {"latestWarningDistance_TTC_PGVIL": 2}  # 或返回其他默认值,如0.0
         return {"latestWarningDistance_TTC_PGVIL": 2}  # 或返回其他默认值,如0.0
+    data_processed.ttc = ttc
 
 
     return {"latestWarningDistance_TTC_PGVIL": float(np.nanmin(ttc))}
     return {"latestWarningDistance_TTC_PGVIL": float(np.nanmin(ttc))}
 
 
@@ -636,6 +651,8 @@ def earliestWarningDistance_PGVIL(data_processed) -> dict:
     distances = calculate_distance_PGVIL(
     distances = calculate_distance_PGVIL(
         np.array([[ego["posX"], ego["posY"]]]), obj[["posX", "posY"]].values
         np.array([[ego["posX"], ego["posY"]]]), obj[["posX", "posY"]].values
     )
     )
+    # 将计算结果保存到data对象中,供图表生成使用
+    data_processed.warning_dist = distances
     if distances.size == 0:
     if distances.size == 0:
         print("没有找到数据!")
         print("没有找到数据!")
         return {"earliestWarningDistance_PGVIL": 15}  # 或返回其他默认值,如0.0
         return {"earliestWarningDistance_PGVIL": 15}  # 或返回其他默认值,如0.0
@@ -663,12 +680,15 @@ def earliestWarningDistance_TTC_PGVIL(data_processed) -> dict:
     distances = calculate_distance_PGVIL(ego_pos, obj_pos)
     distances = calculate_distance_PGVIL(ego_pos, obj_pos)
     rel_speeds = calculate_relative_speed_PGVIL(ego_speed, obj_speed)
     rel_speeds = calculate_relative_speed_PGVIL(ego_speed, obj_speed)
 
 
+    data_processed.warning_dist = distances
+    data_processed.warning_speed = rel_speeds
+
     with np.errstate(divide="ignore", invalid="ignore"):
     with np.errstate(divide="ignore", invalid="ignore"):
         ttc = np.where(rel_speeds != 0, distances / rel_speeds, np.inf)
         ttc = np.where(rel_speeds != 0, distances / rel_speeds, np.inf)
     if ttc.size == 0:
     if ttc.size == 0:
         print("没有找到数据!")
         print("没有找到数据!")
         return {"earliestWarningDistance_TTC_PGVIL": 2}  # 或返回其他默认值,如0.0
         return {"earliestWarningDistance_TTC_PGVIL": 2}  # 或返回其他默认值,如0.0
-
+    data_processed.ttc = ttc
     return {"earliestWarningDistance_TTC_PGVIL": float(np.nanmin(ttc))}
     return {"earliestWarningDistance_TTC_PGVIL": float(np.nanmin(ttc))}
 
 
 
 

+ 93 - 123
modules/metric/safety.py

@@ -8,7 +8,6 @@ import os
 import numpy as np
 import numpy as np
 import pandas as pd
 import pandas as pd
 import math
 import math
-import matplotlib.pyplot as plt
 import scipy.integrate as spi
 import scipy.integrate as spi
 from collections import defaultdict
 from collections import defaultdict
 from typing import Dict, Any, List, Optional
 from typing import Dict, Any, List, Optional
@@ -35,6 +34,7 @@ SAFETY_INFO = [
     "type"
     "type"
 ]
 ]
 
 
+
 # ----------------------
 # ----------------------
 # 独立指标计算函数
 # 独立指标计算函数
 # ----------------------
 # ----------------------
@@ -54,6 +54,7 @@ def calculate_ttc(data_processed) -> dict:
         LogManager().get_logger().error(f"TTC计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"TTC计算异常: {str(e)}", exc_info=True)
         return {"TTC": None}
         return {"TTC": None}
 
 
+
 def calculate_mttc(data_processed) -> dict:
 def calculate_mttc(data_processed) -> dict:
     """计算MTTC (Modified Time To Collision)"""
     """计算MTTC (Modified Time To Collision)"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -69,6 +70,7 @@ def calculate_mttc(data_processed) -> dict:
         LogManager().get_logger().error(f"MTTC计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"MTTC计算异常: {str(e)}", exc_info=True)
         return {"MTTC": None}
         return {"MTTC": None}
 
 
+
 def calculate_thw(data_processed) -> dict:
 def calculate_thw(data_processed) -> dict:
     """计算THW (Time Headway)"""
     """计算THW (Time Headway)"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -84,6 +86,7 @@ def calculate_thw(data_processed) -> dict:
         LogManager().get_logger().error(f"THW计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"THW计算异常: {str(e)}", exc_info=True)
         return {"THW": None}
         return {"THW": None}
 
 
+
 def calculate_tlc(data_processed) -> dict:
 def calculate_tlc(data_processed) -> dict:
     """计算TLC (Time to Line Crossing)"""
     """计算TLC (Time to Line Crossing)"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -99,6 +102,7 @@ def calculate_tlc(data_processed) -> dict:
         LogManager().get_logger().error(f"TLC计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"TLC计算异常: {str(e)}", exc_info=True)
         return {"TLC": None}
         return {"TLC": None}
 
 
+
 def calculate_ttb(data_processed) -> dict:
 def calculate_ttb(data_processed) -> dict:
     """计算TTB (Time to Brake)"""
     """计算TTB (Time to Brake)"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -114,6 +118,7 @@ def calculate_ttb(data_processed) -> dict:
         LogManager().get_logger().error(f"TTB计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"TTB计算异常: {str(e)}", exc_info=True)
         return {"TTB": None}
         return {"TTB": None}
 
 
+
 def calculate_tm(data_processed) -> dict:
 def calculate_tm(data_processed) -> dict:
     """计算TM (Time Margin)"""
     """计算TM (Time Margin)"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -129,6 +134,7 @@ def calculate_tm(data_processed) -> dict:
         LogManager().get_logger().error(f"TM计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"TM计算异常: {str(e)}", exc_info=True)
         return {"TM": None}
         return {"TM": None}
 
 
+
 def calculate_dtc(data_processed) -> dict:
 def calculate_dtc(data_processed) -> dict:
     """计算DTC (Distance to Collision)"""
     """计算DTC (Distance to Collision)"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -142,18 +148,6 @@ def calculate_dtc(data_processed) -> dict:
         LogManager().get_logger().error(f"DTC计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"DTC计算异常: {str(e)}", exc_info=True)
         return {"DTC": None}
         return {"DTC": None}
 
 
-def calculate_pet(data_processed) -> dict:
-    """计算PET (Post Encroachment Time)"""
-    if data_processed is None or not hasattr(data_processed, 'object_df'):
-        return {"PET": None}
-    try:
-        safety = SafetyCalculator(data_processed)
-        pet_value = safety.get_dtc_value()
-        LogManager().get_logger().info(f"安全指标[PET]计算结果: {pet_value}")
-        return {"PET": pet_value}
-    except Exception as e:
-        LogManager().get_logger().error(f"PET计算异常: {str(e)}", exc_info=True)
-        return {"PET": None}
 
 
 def calculate_psd(data_processed) -> dict:
 def calculate_psd(data_processed) -> dict:
     """计算PSD (Potential Safety Distance)"""
     """计算PSD (Potential Safety Distance)"""
@@ -169,7 +163,6 @@ def calculate_psd(data_processed) -> dict:
         return {"PSD": None}
         return {"PSD": None}
 
 
 
 
-
 def calculate_collisionrisk(data_processed) -> dict:
 def calculate_collisionrisk(data_processed) -> dict:
     """计算碰撞风险"""
     """计算碰撞风险"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -185,6 +178,7 @@ def calculate_collisionrisk(data_processed) -> dict:
         LogManager().get_logger().error(f"collisionRisk计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"collisionRisk计算异常: {str(e)}", exc_info=True)
         return {"collisionRisk": None}
         return {"collisionRisk": None}
 
 
+
 def calculate_lonsd(data_processed) -> dict:
 def calculate_lonsd(data_processed) -> dict:
     """计算纵向安全距离"""
     """计算纵向安全距离"""
     safety = SafetyCalculator(data_processed)
     safety = SafetyCalculator(data_processed)
@@ -194,6 +188,7 @@ def calculate_lonsd(data_processed) -> dict:
     LogManager().get_logger().info(f"安全指标[LonSD]计算结果: {lonsd_value}")
     LogManager().get_logger().info(f"安全指标[LonSD]计算结果: {lonsd_value}")
     return {"LonSD": lonsd_value}
     return {"LonSD": lonsd_value}
 
 
+
 def calculate_latsd(data_processed) -> dict:
 def calculate_latsd(data_processed) -> dict:
     """计算横向安全距离"""
     """计算横向安全距离"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -210,6 +205,7 @@ def calculate_latsd(data_processed) -> dict:
         LogManager().get_logger().error(f"LatSD计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"LatSD计算异常: {str(e)}", exc_info=True)
         return {"LatSD": None}
         return {"LatSD": None}
 
 
+
 def calculate_btn(data_processed) -> dict:
 def calculate_btn(data_processed) -> dict:
     """计算制动威胁数"""
     """计算制动威胁数"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -226,6 +222,7 @@ def calculate_btn(data_processed) -> dict:
         LogManager().get_logger().error(f"BTN计算异常: {str(e)}", exc_info=True)
         LogManager().get_logger().error(f"BTN计算异常: {str(e)}", exc_info=True)
         return {"BTN": None}
         return {"BTN": None}
 
 
+
 def calculate_collisionseverity(data_processed) -> dict:
 def calculate_collisionseverity(data_processed) -> dict:
     """计算碰撞严重性"""
     """计算碰撞严重性"""
     if data_processed is None or not hasattr(data_processed, 'object_df'):
     if data_processed is None or not hasattr(data_processed, 'object_df'):
@@ -245,38 +242,40 @@ def calculate_collisionseverity(data_processed) -> dict:
 
 
 class SafetyRegistry:
 class SafetyRegistry:
     """安全指标注册器"""
     """安全指标注册器"""
-    
+
     def __init__(self, data_processed):
     def __init__(self, data_processed):
         self.logger = LogManager().get_logger()
         self.logger = LogManager().get_logger()
         self.data = data_processed
         self.data = data_processed
         self.safety_config = data_processed.safety_config["safety"]
         self.safety_config = data_processed.safety_config["safety"]
         self.metrics = self._extract_metrics(self.safety_config)
         self.metrics = self._extract_metrics(self.safety_config)
         self._registry = self._build_registry()
         self._registry = self._build_registry()
-    
+
     def _extract_metrics(self, config_node: dict) -> list:
     def _extract_metrics(self, config_node: dict) -> list:
         """从配置中提取指标名称"""
         """从配置中提取指标名称"""
         metrics = []
         metrics = []
+
         def _recurse(node):
         def _recurse(node):
             if isinstance(node, dict):
             if isinstance(node, dict):
                 if 'name' in node and not any(isinstance(v, dict) for v in node.values()):
                 if 'name' in node and not any(isinstance(v, dict) for v in node.values()):
                     metrics.append(node['name'])
                     metrics.append(node['name'])
                 for v in node.values():
                 for v in node.values():
                     _recurse(v)
                     _recurse(v)
+
         _recurse(config_node)
         _recurse(config_node)
         self.logger.info(f'评比的安全指标列表:{metrics}')
         self.logger.info(f'评比的安全指标列表:{metrics}')
         return metrics
         return metrics
-    
+
     def _build_registry(self) -> dict:
     def _build_registry(self) -> dict:
         """构建指标函数注册表"""
         """构建指标函数注册表"""
         registry = {}
         registry = {}
         for metric_name in self.metrics:
         for metric_name in self.metrics:
             func_name = f"calculate_{metric_name.lower()}"
             func_name = f"calculate_{metric_name.lower()}"
-            if func_name in globals(): # global()会获取当前模块下所有全局变量、函数、类和其他对象的名称及其对应的值
+            if func_name in globals():
                 registry[metric_name] = globals()[func_name]
                 registry[metric_name] = globals()[func_name]
             else:
             else:
                 self.logger.warning(f"未实现安全指标函数: {func_name}")
                 self.logger.warning(f"未实现安全指标函数: {func_name}")
         return registry
         return registry
-    
+
     def batch_execute(self) -> dict:
     def batch_execute(self) -> dict:
         """批量执行指标计算"""
         """批量执行指标计算"""
         results = {}
         results = {}
@@ -293,17 +292,17 @@ class SafetyRegistry:
 
 
 class SafeManager:
 class SafeManager:
     """安全指标管理类"""
     """安全指标管理类"""
-    
+
     def __init__(self, data_processed):
     def __init__(self, data_processed):
         self.data = data_processed
         self.data = data_processed
         self.registry = SafetyRegistry(self.data)
         self.registry = SafetyRegistry(self.data)
-    
+
     def report_statistic(self):
     def report_statistic(self):
         """计算并报告安全指标结果"""
         """计算并报告安全指标结果"""
         safety_result = self.registry.batch_execute()
         safety_result = self.registry.batch_execute()
-        
+
         return safety_result
         return safety_result
-    
+
 
 
 class SafetyCalculator:
 class SafetyCalculator:
     """安全指标计算类 - 兼容Safe类风格"""
     """安全指标计算类 - 兼容Safe类风格"""
@@ -316,7 +315,8 @@ class SafetyCalculator:
         self.ego_df = data_processed.ego_data.copy()  # 使用copy()避免修改原始数据
         self.ego_df = data_processed.ego_data.copy()  # 使用copy()避免修改原始数据
         self.obj_id_list = data_processed.obj_id_list
         self.obj_id_list = data_processed.obj_id_list
         self.metric_list = [
         self.metric_list = [
-            'TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'TM', 'DTC', 'PET', 'PSD', 'LonSD', 'LatSD', 'BTN', 'collisionRisk', 'collisionSeverity'
+            'TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'TM', 'DTC', 'PSD', 'LonSD', 'LatSD', 'BTN', 'collisionRisk',
+            'collisionSeverity'
         ]
         ]
 
 
         # 初始化默认值
         # 初始化默认值
@@ -328,7 +328,6 @@ class SafetyCalculator:
             "TTB": 10.0,
             "TTB": 10.0,
             "TM": 10.0,
             "TM": 10.0,
             # "MPrTTC": 10.0,
             # "MPrTTC": 10.0,
-            "PET": 10.0,
             "DTC": 10.0,
             "DTC": 10.0,
             "PSD": 10.0,
             "PSD": 10.0,
             "LatSD": 3.0,
             "LatSD": 3.0,
@@ -341,7 +340,7 @@ class SafetyCalculator:
         self.frame_list = self.ego_df['simFrame'].values.tolist()
         self.frame_list = self.ego_df['simFrame'].values.tolist()
         self.collisionRisk = 0
         self.collisionRisk = 0
         self.empty_flag = True
         self.empty_flag = True
-        
+
         # 初始化数据存储列表
         # 初始化数据存储列表
         self.ttc_data = []
         self.ttc_data = []
         self.mttc_data = []
         self.mttc_data = []
@@ -354,10 +353,10 @@ class SafetyCalculator:
         self.btn_data = []
         self.btn_data = []
         self.collision_risk_data = []
         self.collision_risk_data = []
         self.collision_severity_data = []
         self.collision_severity_data = []
-        
+
         # 初始化安全事件记录表
         # 初始化安全事件记录表
         self.unsafe_events_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
         self.unsafe_events_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
-        
+
         # 设置输出目录
         # 设置输出目录
         self.output_dir = os.path.join(os.getcwd(), 'data')
         self.output_dir = os.path.join(os.getcwd(), 'data')
         os.makedirs(self.output_dir, exist_ok=True)
         os.makedirs(self.output_dir, exist_ok=True)
@@ -391,9 +390,9 @@ class SafetyCalculator:
         ego_decel_lon_max = self.data_processed.vehicle_config["EGO_DECEL_LON_MAX"]
         ego_decel_lon_max = self.data_processed.vehicle_config["EGO_DECEL_LON_MAX"]
         ego_decel_lat_max = self.data_processed.vehicle_config["EGO_DECEL_LAT_MAX"]
         ego_decel_lat_max = self.data_processed.vehicle_config["EGO_DECEL_LAT_MAX"]
         ego_decel_max = np.sqrt(ego_decel_lon_max ** 2 + ego_decel_lat_max ** 2)
         ego_decel_max = np.sqrt(ego_decel_lon_max ** 2 + ego_decel_lat_max ** 2)
-        #TEMP_COMMENT: x_relative_start_dist 注释开始
+        # TEMP_COMMENT: x_relative_start_dist 注释开始
         x_relative_start_dist = self.ego_df["x_relative_dist"]
         x_relative_start_dist = self.ego_df["x_relative_dist"]
-        
+
         # 设置安全指标阈值
         # 设置安全指标阈值
         self.safety_thresholds = {
         self.safety_thresholds = {
             'TTC': {'min': 1.5, 'max': None},  # TTC小于1.5秒视为危险
             'TTC': {'min': 1.5, 'max': None},  # TTC小于1.5秒视为危险
@@ -451,18 +450,27 @@ class SafetyCalculator:
                 a2 = np.sqrt(a_x2 ** 2 + a_y2 ** 2)
                 a2 = np.sqrt(a_x2 ** 2 + a_y2 ** 2)
 
 
                 dx, dy = x2 - x1, y2 - y1
                 dx, dy = x2 - x1, y2 - y1
-                
+
                 # 计算目标车相对于自车的方位角
                 # 计算目标车相对于自车的方位角
-                beta = math.atan2(dy, dx)
-                
+                # beta = math.atan2(dy, dx)
+
                 # 将全局坐标系下的相对位置向量转换到自车坐标系
                 # 将全局坐标系下的相对位置向量转换到自车坐标系
                 # 自车坐标系:车头方向为x轴正方向,车辆左侧为y轴正方向
                 # 自车坐标系:车头方向为x轴正方向,车辆左侧为y轴正方向
+                '''
+                你现在的 posH 是 正北为 0°,顺时针为正角度。
+                但是我们在做二维旋转时,Python/数学里默认是:
+
+                0° 是 X 轴(正东)
+
+                顺时针是负角,逆时针是正角
+
+                所以,要将你的 posH(正北为 0)转换成数学中以正东为 0° 的角度'''
                 h1_rad = math.radians(90 - h1)  # 转换为与x轴的夹角
                 h1_rad = math.radians(90 - h1)  # 转换为与x轴的夹角
-                
+
                 # 坐标变换
                 # 坐标变换
                 lon_d = dx * math.cos(h1_rad) + dy * math.sin(h1_rad)  # 纵向距离(前为正,后为负)
                 lon_d = dx * math.cos(h1_rad) + dy * math.sin(h1_rad)  # 纵向距离(前为正,后为负)
                 lat_d = abs(-dx * math.sin(h1_rad) + dy * math.cos(h1_rad))  # 横向距离(取绝对值)
                 lat_d = abs(-dx * math.sin(h1_rad) + dy * math.cos(h1_rad))  # 横向距离(取绝对值)
-                
+
                 obj_dict[frame_num][playerId]['lon_d'] = lon_d
                 obj_dict[frame_num][playerId]['lon_d'] = lon_d
                 obj_dict[frame_num][playerId]['lat_d'] = lat_d
                 obj_dict[frame_num][playerId]['lat_d'] = lat_d
 
 
@@ -495,31 +503,10 @@ class SafetyCalculator:
                 TTB = self._cal_TTB(x_relative_start_dist, relative_v, ego_decel_max)
                 TTB = self._cal_TTB(x_relative_start_dist, relative_v, ego_decel_max)
                 TM = self._cal_TM(x_relative_start_dist, v2, a2, v1, a1)
                 TM = self._cal_TM(x_relative_start_dist, v2, a2, v1, a1)
                 DTC = self._cal_DTC(vrel_projection_in_dist, arel_projection_in_dist, rho)
                 DTC = self._cal_DTC(vrel_projection_in_dist, arel_projection_in_dist, rho)
-                # MPrTTC = self._cal_MPrTTC(x_relative_start_dist)
-                # 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)
-                PET = None
-
-                for lane_pos in lane_poss:
-                    lane_posx1 = ast.literal_eval(lane_pos)[0][0]
-                    lane_posy1 = ast.literal_eval(lane_pos)[0][1]
-                    lane_posx2 = ast.literal_eval(lane_pos)[-1][0]
-                    lane_posy2 = ast.literal_eval(lane_pos)[-1][1]
-                    for ramp_pos in ramp_poss:
-                        ramp_posx1 = ast.literal_eval(ramp_pos)[0][0]
-                        ramp_posy1 = ast.literal_eval(ramp_pos)[0][1]
-                        ramp_posx2 = ast.literal_eval(ramp_pos)[-1][0]
-                        ramp_posy2 = ast.literal_eval(ramp_pos)[-1][1]
-                        ego_posx = x1
-                        ego_posy = y1
-                        obj_posx = x2
-                        obj_posy = y2
-                        delta_t = self._cal_reaction_time_to_avgspeed(self.ego_df)
-                        lane_width = self.ego_df["lane_width"].iloc[0]
-                        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)
                 PSD = self._cal_PSD(x_relative_start_dist, v1, ego_decel_lon_max)
                 PSD = self._cal_PSD(x_relative_start_dist, v1, ego_decel_lon_max)
 
 
-                LonSD = self._cal_longitudinal_safe_dist(v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min, obj_decel_max)
+                LonSD = self._cal_longitudinal_safe_dist(v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min,
+                                                         obj_decel_max)
 
 
                 lat_dist = 0.5
                 lat_dist = 0.5
                 v_right = v1
                 v_right = v1
@@ -545,7 +532,8 @@ class SafetyCalculator:
                 lat_a = abs(lat_a1 - lat_a2)
                 lat_a = abs(lat_a1 - lat_a2)
                 lat_v = -v_x1 * math.sin(h1_rad) + v_y1 * math.cos(h1_rad)
                 lat_v = -v_x1 * math.sin(h1_rad) + v_y1 * math.cos(h1_rad)
 
 
-                obj_dict[frame_num][playerId]['lat_v_rel'] = lat_v - (-v_x2 * math.sin(h1_rad) + v_y2 * math.cos(h1_rad))
+                obj_dict[frame_num][playerId]['lat_v_rel'] = lat_v - (
+                            -v_x2 * math.sin(h1_rad) + v_y2 * math.cos(h1_rad))
                 obj_dict[frame_num][playerId]['lon_v_rel'] = lon_v - (v_x2 * math.cos(h1_rad) + v_y2 * math.sin(h1_rad))
                 obj_dict[frame_num][playerId]['lon_v_rel'] = lon_v - (v_x2 * math.cos(h1_rad) + v_y2 * math.sin(h1_rad))
 
 
                 TTC = None if (TTC is None or TTC < 0) else TTC
                 TTC = None if (TTC is None or TTC < 0) else TTC
@@ -555,7 +543,6 @@ class SafetyCalculator:
                 TTB = None if (TTB is None or TTB < 0) else TTB
                 TTB = None if (TTB is None or TTB < 0) else TTB
                 TM = None if (TM is None or TM < 0) else TM
                 TM = None if (TM is None or TM < 0) else TM
                 DTC = None if (DTC is None or DTC < 0) else DTC
                 DTC = None if (DTC is None or DTC < 0) else DTC
-                PET = None if (PET is None or PET < 0) else PET
                 PSD = None if (PSD is None or PSD < 0) else PSD
                 PSD = None if (PSD is None or PSD < 0) else PSD
 
 
                 obj_dict[frame_num][playerId]['TTC'] = TTC
                 obj_dict[frame_num][playerId]['TTC'] = TTC
@@ -565,13 +552,12 @@ class SafetyCalculator:
                 obj_dict[frame_num][playerId]['TTB'] = TTB
                 obj_dict[frame_num][playerId]['TTB'] = TTB
                 obj_dict[frame_num][playerId]['TM'] = TM
                 obj_dict[frame_num][playerId]['TM'] = TM
                 obj_dict[frame_num][playerId]['DTC'] = DTC
                 obj_dict[frame_num][playerId]['DTC'] = DTC
-                obj_dict[frame_num][playerId]['PET'] = PET
                 obj_dict[frame_num][playerId]['PSD'] = PSD
                 obj_dict[frame_num][playerId]['PSD'] = PSD
                 obj_dict[frame_num][playerId]['LonSD'] = LonSD
                 obj_dict[frame_num][playerId]['LonSD'] = LonSD
                 obj_dict[frame_num][playerId]['LatSD'] = LatSD
                 obj_dict[frame_num][playerId]['LatSD'] = LatSD
                 obj_dict[frame_num][playerId]['BTN'] = abs(BTN)
                 obj_dict[frame_num][playerId]['BTN'] = abs(BTN)
 
 
-               # TTC要进行筛选,否则会出现nan或者TTC过大的情况
+                # TTC要进行筛选,否则会出现nan或者TTC过大的情况
                 if not TTC or TTC > 4000:  # threshold = 4258.41
                 if not TTC or TTC > 4000:  # threshold = 4258.41
                     collisionSeverity = 0
                     collisionSeverity = 0
                     pr_death = 0
                     pr_death = 0
@@ -591,7 +577,7 @@ class SafetyCalculator:
 
 
         df_safe = pd.concat(df_list)
         df_safe = pd.concat(df_list)
         col_list = ['simTime', 'simFrame', 'playerId',
         col_list = ['simTime', 'simFrame', 'playerId',
-                    'TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'TM', 'DTC', 'PET', 'PSD', 'LonSD', 'LatSD', 'BTN',
+                    'TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'TM', 'DTC', 'PSD', 'LonSD', 'LatSD', 'BTN',
                     'collisionSeverity', 'pr_death', 'collisionRisk']
                     'collisionSeverity', 'pr_death', 'collisionRisk']
         self.df_safe = df_safe[col_list].reset_index(drop=True)
         self.df_safe = df_safe[col_list].reset_index(drop=True)
 
 
@@ -706,11 +692,10 @@ class SafetyCalculator:
     def dist(self, x1, y1, x2, y2):
     def dist(self, x1, y1, x2, y2):
         dist = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
         dist = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
         return dist
         return dist
-        
-    
+
     def generate_metric_chart(self, metric_name: str) -> None:
     def generate_metric_chart(self, metric_name: str) -> None:
         """生成指标图表
         """生成指标图表
-        
+
         Args:
         Args:
             metric_name: 指标名称
             metric_name: 指标名称
         """
         """
@@ -719,14 +704,14 @@ class SafetyCalculator:
             if self.output_dir is None:
             if self.output_dir is None:
                 self.output_dir = os.path.join(os.getcwd(), 'data')
                 self.output_dir = os.path.join(os.getcwd(), 'data')
                 os.makedirs(self.output_dir, exist_ok=True)
                 os.makedirs(self.output_dir, exist_ok=True)
-            
+
             # 调用图表生成函数
             # 调用图表生成函数
             chart_path = generate_safety_chart_data(self, metric_name, self.output_dir)
             chart_path = generate_safety_chart_data(self, metric_name, self.output_dir)
             if chart_path:
             if chart_path:
                 self.logger.info(f"{metric_name}图表已生成: {chart_path}")
                 self.logger.info(f"{metric_name}图表已生成: {chart_path}")
             else:
             else:
                 self.logger.warning(f"{metric_name}图表生成失败")
                 self.logger.warning(f"{metric_name}图表生成失败")
-                
+
         except Exception as e:
         except Exception as e:
             self.logger.error(f"生成{metric_name}图表失败: {str(e)}", exc_info=True)
             self.logger.error(f"生成{metric_name}图表失败: {str(e)}", exc_info=True)
 
 
@@ -765,9 +750,10 @@ class SafetyCalculator:
         else:
         else:
             THW = dist / v_ego_projection_in_dist
             THW = dist / v_ego_projection_in_dist
         return THW
         return THW
+
     # TLC (time to line crossing)
     # TLC (time to line crossing)
     def _cal_TLC(self, ego_v, ego_yaw, laneOffset):
     def _cal_TLC(self, ego_v, ego_yaw, laneOffset):
-        TLC = laneOffset/ego_v/np.sin(ego_yaw) if ((ego_v != 0) and (np.sin(ego_yaw) != 0)) else 10.0
+        TLC = laneOffset / ego_v / np.sin(ego_yaw) if ((ego_v != 0) and (np.sin(ego_yaw) != 0)) else 10.0
         if TLC < 0:
         if TLC < 0:
             TLC = None
             TLC = None
         return TLC
         return TLC
@@ -775,11 +761,11 @@ class SafetyCalculator:
     def _cal_TTB(self, x_relative_start_dist, relative_v, ego_decel_max):
     def _cal_TTB(self, x_relative_start_dist, relative_v, ego_decel_max):
         if len(x_relative_start_dist):
         if len(x_relative_start_dist):
             return None
             return None
-        if (ego_decel_max  == 0) or (relative_v == 0):
+        if (ego_decel_max == 0) or (relative_v == 0):
             return self.calculated_value["TTB"]
             return self.calculated_value["TTB"]
         else:
         else:
             x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
             x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
-            TTB = (x_relative_start_dist0 + relative_v * relative_v/2/ego_decel_max)/relative_v
+            TTB = (x_relative_start_dist0 + relative_v * relative_v / 2 / ego_decel_max) / relative_v
             return TTB
             return TTB
 
 
     def _cal_TM(self, x_relative_start_dist, v2, a2, v1, a1):
     def _cal_TM(self, x_relative_start_dist, v2, a2, v1, a1):
@@ -790,7 +776,7 @@ class SafetyCalculator:
         if a1 == 0:
         if a1 == 0:
             return None
             return None
         x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
         x_relative_start_dist0 = x_relative_start_dist.tolist()[0]
-        TM = (x_relative_start_dist0 + v2**2/(2*a2) - v1**2/(2*a1)) / v1
+        TM = (x_relative_start_dist0 + v2 ** 2 / (2 * a2) - v1 ** 2 / (2 * a1)) / v1
         return TM
         return TM
 
 
     def velocity(self, v_x, v_y):
     def velocity(self, v_x, v_y):
@@ -807,35 +793,23 @@ class SafetyCalculator:
         # 检查除数是否为零
         # 检查除数是否为零
         if a_right_lat_brake_min == 0 or a_left_lat_brake_min == 0:
         if a_right_lat_brake_min == 0 or a_left_lat_brake_min == 0:
             return self._default_value('LatSD')  # 返回默认值
             return self._default_value('LatSD')  # 返回默认值
-            
+
         v_right_rho = v_right + rho * a_lat_max
         v_right_rho = v_right + rho * a_lat_max
         v_left_rho = v_left + rho * a_lat_max
         v_left_rho = v_left + rho * a_lat_max
         dist_min = lat_dist + (
         dist_min = lat_dist + (
-            (v_right + v_right_rho) * rho / 2
-            + v_right_rho**2 / a_right_lat_brake_min / 2
-            + ((v_left + v_right_rho) * rho / 2)
-            + v_left_rho**2 / a_left_lat_brake_min / 2
+                (v_right + v_right_rho) * rho / 2
+                + v_right_rho ** 2 / a_right_lat_brake_min / 2
+                + ((v_left + v_right_rho) * rho / 2)
+                + v_left_rho ** 2 / a_left_lat_brake_min / 2
         )
         )
         return dist_min
         return dist_min
+
     def _cal_DTC(self, v_on_dist, a_on_dist, t):
     def _cal_DTC(self, v_on_dist, a_on_dist, t):
         if a_on_dist == 0:
         if a_on_dist == 0:
             return None
             return None
         DTC = v_on_dist * t + v_on_dist ** 2 / a_on_dist
         DTC = v_on_dist * t + v_on_dist ** 2 / a_on_dist
         return DTC
         return DTC
 
 
-    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):
-        dist1 = self.horizontal_distance(lane_posx1, lane_posy1, lane_posx2, lane_posy2, ego_posx, ego_posy)
-        dist2 = self.horizontal_distance(ramp_posx1, ramp_posy1, ramp_posx2, ramp_posy2, obj_posx, obj_posy)
-        if ((dist1 <= lane_width/2) and (self._is_alone_the_road(lane_posx1, lane_posy1, lane_posx2, lane_posy2, ego_posx, ego_posy))
-                and (self._is_in_the_road(ramp_posx1, ramp_posy1, ramp_posx2, ramp_posy2, obj_posx, obj_posy))
-                and (dist2 <= lane_width/2) and (a1 != 0) and (a2 != 0)):
-            dist_ego = np.sqrt((ego_posx - lane_posx1)**2 + (ego_posy-lane_posy1)**2)
-            dist_obj = np.sqrt((obj_posx - ramp_posx2)**2 + (obj_posy-ramp_posy2)**2)
-            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
-            return PET
-        else:
-            return None
-
     def _cal_PSD(self, x_relative_start_dist, v1, ego_decel_lon_max):
     def _cal_PSD(self, x_relative_start_dist, v1, ego_decel_lon_max):
         if v1 == 0:
         if v1 == 0:
             return None
             return None
@@ -846,6 +820,7 @@ class SafetyCalculator:
                 return PSD
                 return PSD
             else:
             else:
                 return None
                 return None
+
     # DRAC (decelerate required avoid collision)
     # DRAC (decelerate required avoid collision)
     def _cal_DRAC(self, dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2):
     def _cal_DRAC(self, dist, vrel_projection_in_dist, len1, len2, width1, width2, o_x1, o_x2):
         dist_length = dist - (len2 / 2 - o_x2 + len1 / 2 + o_x1)  # 4.671
         dist_length = dist - (len2 / 2 - o_x2 + len1 / 2 + o_x1)  # 4.671
@@ -921,9 +896,9 @@ class SafetyCalculator:
         unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
         unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
         return unfunc_df
         return unfunc_df
         # 统计最危险的指标
         # 统计最危险的指标
-    
+
     def _safe_statistic_most_dangerous(self):
     def _safe_statistic_most_dangerous(self):
-        min_list = ['TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'LonSD', 'LatSD', 'TM', 'PET', 'PSD']
+        min_list = ['TTC', 'MTTC', 'THW', 'TLC', 'TTB', 'LonSD', 'LatSD', 'TM', 'PSD']
         max_list = ['DTC', 'BTN', 'collisionRisk', 'collisionSeverity']
         max_list = ['DTC', 'BTN', 'collisionRisk', 'collisionSeverity']
         result = {}
         result = {}
         for metric in min_list:
         for metric in min_list:
@@ -957,7 +932,6 @@ class SafetyCalculator:
             'TTB': 10.0,
             'TTB': 10.0,
             'TM': 10.0,
             'TM': 10.0,
             'DTC': 10.0,
             'DTC': 10.0,
-            'PET': 10.0,
             'PSD': 10.0,
             'PSD': 10.0,
             'LonSD': 10.0,
             'LonSD': 10.0,
             'LatSD': 2.0,
             'LatSD': 2.0,
@@ -982,15 +956,14 @@ class SafetyCalculator:
             return self._default_value('TTC')
             return self._default_value('TTC')
         ttc_values = self.df_safe['TTC'].dropna()
         ttc_values = self.df_safe['TTC'].dropna()
         ttc_value = float(ttc_values.min()) if not ttc_values.empty else self._default_value('TTC')
         ttc_value = float(ttc_values.min()) if not ttc_values.empty else self._default_value('TTC')
-        
+
         # 收集TTC数据
         # 收集TTC数据
         if not ttc_values.empty:
         if not ttc_values.empty:
             self.ttc_data = []
             self.ttc_data = []
             for time, frame, ttc in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TTC']):
             for time, frame, ttc in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TTC']):
                 if pd.notnull(ttc):
                 if pd.notnull(ttc):
                     self.ttc_data.append({'simTime': time, 'simFrame': frame, 'TTC': ttc})
                     self.ttc_data.append({'simTime': time, 'simFrame': frame, 'TTC': ttc})
-            
-        
+
         return ttc_value
         return ttc_value
 
 
     def get_mttc_value(self) -> float:
     def get_mttc_value(self) -> float:
@@ -998,14 +971,14 @@ class SafetyCalculator:
             return self._default_value('MTTC')
             return self._default_value('MTTC')
         mttc_values = self.df_safe['MTTC'].dropna()
         mttc_values = self.df_safe['MTTC'].dropna()
         mttc_value = float(mttc_values.min()) if not mttc_values.empty else self._default_value('MTTC')
         mttc_value = float(mttc_values.min()) if not mttc_values.empty else self._default_value('MTTC')
-        
+
         # 收集MTTC数据
         # 收集MTTC数据
         if not mttc_values.empty:
         if not mttc_values.empty:
             self.mttc_data = []
             self.mttc_data = []
             for time, frame, mttc in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['MTTC']):
             for time, frame, mttc in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['MTTC']):
                 if pd.notnull(mttc):
                 if pd.notnull(mttc):
                     self.mttc_data.append({'simTime': time, 'simFrame': frame, 'MTTC': mttc})
                     self.mttc_data.append({'simTime': time, 'simFrame': frame, 'MTTC': mttc})
-        
+
         return mttc_value
         return mttc_value
 
 
     def get_thw_value(self) -> float:
     def get_thw_value(self) -> float:
@@ -1013,14 +986,14 @@ class SafetyCalculator:
             return self._default_value('THW')
             return self._default_value('THW')
         thw_values = self.df_safe['THW'].dropna()
         thw_values = self.df_safe['THW'].dropna()
         thw_value = float(thw_values.min()) if not thw_values.empty else self._default_value('THW')
         thw_value = float(thw_values.min()) if not thw_values.empty else self._default_value('THW')
-        
+
         # 收集THW数据
         # 收集THW数据
         if not thw_values.empty:
         if not thw_values.empty:
             self.thw_data = []
             self.thw_data = []
             for time, frame, thw in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['THW']):
             for time, frame, thw in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['THW']):
                 if pd.notnull(thw):
                 if pd.notnull(thw):
                     self.thw_data.append({'simTime': time, 'simFrame': frame, 'THW': thw})
                     self.thw_data.append({'simTime': time, 'simFrame': frame, 'THW': thw})
-        
+
         return thw_value
         return thw_value
 
 
     def get_tlc_value(self) -> float:
     def get_tlc_value(self) -> float:
@@ -1028,14 +1001,14 @@ class SafetyCalculator:
             return self._default_value('TLC')
             return self._default_value('TLC')
         tlc_values = self.df_safe['TLC'].dropna()
         tlc_values = self.df_safe['TLC'].dropna()
         tlc_value = float(tlc_values.min()) if not tlc_values.empty else self._default_value('TLC')
         tlc_value = float(tlc_values.min()) if not tlc_values.empty else self._default_value('TLC')
-        
+
         # 收集TLC数据
         # 收集TLC数据
         if not tlc_values.empty:
         if not tlc_values.empty:
             self.tlc_data = []
             self.tlc_data = []
             for time, frame, tlc in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TLC']):
             for time, frame, tlc in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TLC']):
                 if pd.notnull(tlc):
                 if pd.notnull(tlc):
                     self.tlc_data.append({'simTime': time, 'simFrame': frame, 'TLC': tlc})
                     self.tlc_data.append({'simTime': time, 'simFrame': frame, 'TLC': tlc})
-        
+
         return tlc_value
         return tlc_value
 
 
     def get_ttb_value(self) -> float:
     def get_ttb_value(self) -> float:
@@ -1043,14 +1016,14 @@ class SafetyCalculator:
             return self._default_value('TTB')
             return self._default_value('TTB')
         ttb_values = self.df_safe['TTB'].dropna()
         ttb_values = self.df_safe['TTB'].dropna()
         ttb_value = float(ttb_values.min()) if not ttb_values.empty else self._default_value('TTB')
         ttb_value = float(ttb_values.min()) if not ttb_values.empty else self._default_value('TTB')
-        
+
         # 收集TTB数据
         # 收集TTB数据
         if not ttb_values.empty:
         if not ttb_values.empty:
             self.ttb_data = []
             self.ttb_data = []
             for time, frame, ttb in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TTB']):
             for time, frame, ttb in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TTB']):
                 if pd.notnull(ttb):
                 if pd.notnull(ttb):
                     self.ttb_data.append({'simTime': time, 'simFrame': frame, 'TTB': ttb})
                     self.ttb_data.append({'simTime': time, 'simFrame': frame, 'TTB': ttb})
-        
+
         return ttb_value
         return ttb_value
 
 
     def get_tm_value(self) -> float:
     def get_tm_value(self) -> float:
@@ -1058,14 +1031,14 @@ class SafetyCalculator:
             return self._default_value('TM')
             return self._default_value('TM')
         tm_values = self.df_safe['TM'].dropna()
         tm_values = self.df_safe['TM'].dropna()
         tm_value = float(tm_values.min()) if not tm_values.empty else self._default_value('TM')
         tm_value = float(tm_values.min()) if not tm_values.empty else self._default_value('TM')
-        
+
         # 收集TM数据
         # 收集TM数据
         if not tm_values.empty:
         if not tm_values.empty:
             self.tm_data = []
             self.tm_data = []
             for time, frame, tm in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TM']):
             for time, frame, tm in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['TM']):
                 if pd.notnull(tm):
                 if pd.notnull(tm):
                     self.tm_data.append({'simTime': time, 'simFrame': frame, 'TM': tm})
                     self.tm_data.append({'simTime': time, 'simFrame': frame, 'TM': tm})
-        
+
         return tm_value
         return tm_value
 
 
     def get_dtc_value(self) -> float:
     def get_dtc_value(self) -> float:
@@ -1074,12 +1047,6 @@ class SafetyCalculator:
         dtc_values = self.df_safe['DTC'].dropna()
         dtc_values = self.df_safe['DTC'].dropna()
         return float(dtc_values.min()) if not dtc_values.empty else self._default_value('DTC')
         return float(dtc_values.min()) if not dtc_values.empty else self._default_value('DTC')
 
 
-    def get_pet_value(self) -> float:
-        if self.empty_flag or self.df_safe is None:
-            return self._default_value('PET')
-        pet_values = self.df_safe['PET'].dropna()
-        return float(pet_values.min()) if not pet_values.empty else self._default_value('PET')
-
     def get_psd_value(self) -> float:
     def get_psd_value(self) -> float:
         if self.empty_flag or self.df_safe is None:
         if self.empty_flag or self.df_safe is None:
             return self._default_value('PSD')
             return self._default_value('PSD')
@@ -1091,14 +1058,14 @@ class SafetyCalculator:
             return self._default_value('LonSD')
             return self._default_value('LonSD')
         lonsd_values = self.df_safe['LonSD'].dropna()
         lonsd_values = self.df_safe['LonSD'].dropna()
         lonsd_value = float(lonsd_values.mean()) if not lonsd_values.empty else self._default_value('LonSD')
         lonsd_value = float(lonsd_values.mean()) if not lonsd_values.empty else self._default_value('LonSD')
-        
+
         # 收集LonSD数据
         # 收集LonSD数据
         if not lonsd_values.empty:
         if not lonsd_values.empty:
             self.lonsd_data = []
             self.lonsd_data = []
             for time, frame, lonsd in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['LonSD']):
             for time, frame, lonsd in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['LonSD']):
                 if pd.notnull(lonsd):
                 if pd.notnull(lonsd):
                     self.lonsd_data.append({'simTime': time, 'simFrame': frame, 'LonSD': lonsd})
                     self.lonsd_data.append({'simTime': time, 'simFrame': frame, 'LonSD': lonsd})
-        
+
         return lonsd_value
         return lonsd_value
 
 
     def get_latsd_value(self) -> float:
     def get_latsd_value(self) -> float:
@@ -1107,7 +1074,7 @@ class SafetyCalculator:
         latsd_values = self.df_safe['LatSD'].dropna()
         latsd_values = self.df_safe['LatSD'].dropna()
         # 使用最小值而非平均值,与safety1.py保持一致
         # 使用最小值而非平均值,与safety1.py保持一致
         latsd_value = float(latsd_values.min()) if not latsd_values.empty else self._default_value('LatSD')
         latsd_value = float(latsd_values.min()) if not latsd_values.empty else self._default_value('LatSD')
-        
+
         # 收集LatSD数据
         # 收集LatSD数据
         if not latsd_values.empty:
         if not latsd_values.empty:
             self.latsd_data = []
             self.latsd_data = []
@@ -1122,7 +1089,7 @@ class SafetyCalculator:
             return self._default_value('BTN')
             return self._default_value('BTN')
         btn_values = self.df_safe['BTN'].dropna()
         btn_values = self.df_safe['BTN'].dropna()
         btn_value = float(btn_values.max()) if not btn_values.empty else self._default_value('BTN')
         btn_value = float(btn_values.max()) if not btn_values.empty else self._default_value('BTN')
-        
+
         # 收集BTN数据
         # 收集BTN数据
         if not btn_values.empty:
         if not btn_values.empty:
             self.btn_data = []
             self.btn_data = []
@@ -1137,11 +1104,12 @@ class SafetyCalculator:
             return self._default_value('collisionRisk')
             return self._default_value('collisionRisk')
         risk_values = self.df_safe['collisionRisk'].dropna()
         risk_values = self.df_safe['collisionRisk'].dropna()
         risk_value = float(risk_values.max()) if not risk_values.empty else self._default_value('collisionRisk')
         risk_value = float(risk_values.max()) if not risk_values.empty else self._default_value('collisionRisk')
-        
+
         # 收集碰撞风险数据
         # 收集碰撞风险数据
         if not risk_values.empty:
         if not risk_values.empty:
             self.collision_risk_data = []
             self.collision_risk_data = []
-            for time, frame, risk in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['collisionRisk']):
+            for time, frame, risk in zip(self.df_safe['simTime'], self.df_safe['simFrame'],
+                                         self.df_safe['collisionRisk']):
                 if pd.notnull(risk):
                 if pd.notnull(risk):
                     self.collision_risk_data.append({'simTime': time, 'simFrame': frame, 'collisionRisk': risk})
                     self.collision_risk_data.append({'simTime': time, 'simFrame': frame, 'collisionRisk': risk})
 
 
@@ -1151,15 +1119,17 @@ class SafetyCalculator:
         if self.empty_flag or self.df_safe is None:
         if self.empty_flag or self.df_safe is None:
             return self._default_value('collisionSeverity')
             return self._default_value('collisionSeverity')
         severity_values = self.df_safe['collisionSeverity'].dropna()
         severity_values = self.df_safe['collisionSeverity'].dropna()
-        severity_value = float(severity_values.max()) if not severity_values.empty else self._default_value('collisionSeverity')
-        
+        severity_value = float(severity_values.max()) if not severity_values.empty else self._default_value(
+            'collisionSeverity')
+
         # 收集碰撞严重性数据
         # 收集碰撞严重性数据
         if not severity_values.empty:
         if not severity_values.empty:
             self.collision_severity_data = []
             self.collision_severity_data = []
-            for time, frame, severity in zip(self.df_safe['simTime'], self.df_safe['simFrame'], self.df_safe['collisionSeverity']):
+            for time, frame, severity in zip(self.df_safe['simTime'], self.df_safe['simFrame'],
+                                             self.df_safe['collisionSeverity']):
                 if pd.notnull(severity):
                 if pd.notnull(severity):
-                    self.collision_severity_data.append({'simTime': time, 'simFrame': frame, 'collisionSeverity': severity})
+                    self.collision_severity_data.append(
+                        {'simTime': time, 'simFrame': frame, 'collisionSeverity': severity})
 
 
-        
         return severity_value
         return severity_value
 
 

+ 5 - 5
scripts/evaluator_enhanced.py

@@ -601,27 +601,27 @@ def main():
     parser.add_argument(
     parser.add_argument(
         "--logPath",
         "--logPath",
         type=str,
         type=str,
-        default="logs/test.log",
+        default="test.log",
         help="Log file path",
         help="Log file path",
     )
     )
     parser.add_argument(
     parser.add_argument(
         "--dataPath",
         "--dataPath",
         type=str,
         type=str,
-        default=r"D:\Kevin\zhaoyuan\data\V2V_CSAE53-2020_ForwardCollision_LST_01-02",
+        default=r"D:\Cicv\招远\AD_GBT41798-2022_TrafficSignalRecognitionAndResponse_LST_01",
         help="Input data directory",
         help="Input data directory",
     )
     )
     
     
     parser.add_argument(
     parser.add_argument(
         "--allConfigPath",
         "--allConfigPath",
         type=str,
         type=str,
-        default="config/all_metrics_config.yaml",
+        default=r"D:\Cicv\招远\zhaoyuan\config\all_metrics_config.yaml",
         help="Full metrics config file path (built-in + custom)",
         help="Full metrics config file path (built-in + custom)",
     )
     )
     
     
     parser.add_argument(
     parser.add_argument(
         "--baseConfigPath",
         "--baseConfigPath",
         type=str,
         type=str,
-        default="config/builtin_metrics_config.yaml",
+        default=r"D:\Cicv\招远\zhaoyuan\config\builtin_metrics_config.yaml",
         help="Built-in metrics config file path",
         help="Built-in metrics config file path",
     )
     )
     parser.add_argument(
     parser.add_argument(
@@ -639,7 +639,7 @@ def main():
     parser.add_argument(
     parser.add_argument(
         "--customConfigPath",
         "--customConfigPath",
         type=str,
         type=str,
-        default="config/custom_metrics_config.yaml",
+        default=r"D:\Cicv\招远\zhaoyuan\config\custom_metrics_config.yaml",
         help="Custom metrics config path (optional)",
         help="Custom metrics config path (optional)",
     )
     )