瀏覽代碼

重构safety/comfort/efficient代码并调通,重构traffic代码部分调通

cicv 1 月之前
父節點
當前提交
042344a299

+ 0 - 1
README.md

@@ -72,7 +72,6 @@ python evaluator.py --configPath config.yaml --dataPath data_dir --reportPath re
 
 这种设计使系统更加灵活,既能满足选择性运行指标的需求,又能支持用户自定义指标,同时保持了原有代码结构的稳定性。
 
-d:\Kevin\zhaoyuan\zhaoyuan\
 ├── scripts/
 │   └── evaluator.py          # 评估引擎主程序
 ├── modules/

+ 27 - 17
config/all_metrics_config.yaml

@@ -157,19 +157,29 @@ efficient:
 function:
   name: function
   priority: 0
-  LKA:
-    name: LKA
+  scenario:
+    name: ForwardCollision
     priority: 0
-    latestWarningDistance_TTC:
-      name: latestWarningDistance_TTC
-      priority: 0
-      max: 5
-      min: 1.98
-    latestWarningDistance:
-      name: latestWarningDistance
-      priority: 0
-      max: 150
-      min: 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
 
 traffic:
   name: traffic
@@ -183,12 +193,12 @@ traffic:
       max: 0
       min: 0
     urbanExpresswayOrHighwayReverse:
-      name: higwayreverse
+      name: urbanExpresswayOrHighwayReverse
       priority: 0
       max: 0
       min: 0
     urbanExpresswayOrHighwayDrivingAgainst:
-      name: higwayDrivingAgainst
+      name: urbanExpresswayOrHighwayDrivingAgainst
       priority: 0
       max: 0
       min: 0
@@ -202,7 +212,7 @@ traffic:
       max: 0
       min: 0
     urbanExpresswayOrHighwayEmergencyLaneStopped:
-      name: highwayEmergencyLaneStopped
+      name: urbanExpresswayOrHighwayEmergencyLaneStopped
       priority: 0
       max: 0
       min: 0
@@ -309,8 +319,8 @@ traffic:
       priority: 0
       max: 0
       min: 0
-    aviod_pedestrian_when_turning:
-      name: aviod_pedestrian_when_turning
+    avoid_pedestrian_when_turning:
+      name: avoid_pedestrian_when_turning
       priority: 0
       max: 0
       min: 0

+ 38 - 0
config/custom_metrics_config.yaml

@@ -20,3 +20,41 @@ user:
       priority: 0
       max: 20.0
       min: 3.5
+comfort:
+  name: comfort
+  priority: 0
+  comfortLat:
+    name: comfortLat
+    priority: 0
+    Weaving:
+      name: Weaving
+      priority: 0
+      max: 0
+      min: 0
+function:
+  name: function
+  priority: 0
+  LKA:
+    name: LKA
+    priority: 0
+    latestWarningDistance_TTC:
+      name: latestWarningDistance_TTC
+      priority: 0
+      max: 5
+      min: 1.98
+    latestWarningDistance:
+      name: latestWarningDistance
+      priority: 0
+      max: 150
+      min: 0
+traffic:
+  name: traffic
+  priority: 0
+  generalViolation:
+    name: generalViolation
+    priority: 0
+    aviod_pedestrian_when_turning:
+      name: aviod_pedestrian_when_turning
+      priority: 0
+      max: 0
+      min: 0

+ 334 - 351
config/metrics_config.yaml

@@ -1,352 +1,335 @@
-vehicle:
-  CAR_WIDTH: 1.872       
-  CAR_LENGTH: 4.924      
-  CAR_HEIGHT: 1.3        
-  CAR_OFFX: 1.321        
-  RHO: 0.3               
-  EGO_ACCEL_MAX: 6       
-  OBJ_DECEL_MAX: 8       
-  EGO_DECEL_MIN: 1       
-  EGO_DECEL_LON_MAX: 8   
-  EGO_DECEL_LAT_MAX: 1   
-  EGO_WHEELBASS: 2.8     
-
-T_threshold:
-  T0_threshold: 0  
-  T1_threshold: 2  
-  T2_threshold: 5  
-
-safety:
-  name: safety
-  priority: 0
-  safeTime:
-    name: safetime
-    priority: 0
-    TTC:
-      name: TTC
-      priority: 0
-      max: 2000.0
-      min: 2.86
-    MTTC:
-      name: MTTC
-      priority: 0
-      max: 2000.0
-      min: 3.0
-    THW:
-      name: THW
-      priority: 0
-      max: 2000.0
-      min: 1.5
-  safeDistance:
-    name: safeDistance
-    priority: 0
-    LonSD:
-      name: LonSD
-      priority: 0
-      max: 2000.0
-      min: 10.0
-    LatSD:
-      name: LatSD 
-      priority: 0
-      max: 2000.0
-      min: 2.0
-  safeAcceleration:
-    name: safeAcceleration
-    priority: 0
-    BTN:
-      name: BTN
-      priority: 0
-      max: 1.0
-      min: -2000.0
-  safeProbability:
-    name: safeProbability
-    priority: 0
-    collisionRisk:
-      name: collisionRisk
-      priority: 0
-      max: 10.0
-      min: 0.0
-    collisionSeverity:
-      name: collisionSeverity
-      priority: 0
-      max: 10.0
-      min: 0.0
-
-comfort:
-  name: comfort
-  priority: 0
-  comfortLat:
-    name: comfortLat
-    priority: 0
-    weaving:
-      name: weaving
-      priority: 0
-      max: 0
-      min: 0
-    shake:
-      name: shake
-      priority: 0
-      max: 0
-      min: 0
-  comfortLon:
-    name: comfortLon
-    priority: 0
-    cadence:
-      name: cadence
-      priority: 0
-      max: 0
-      min: 0
-    slamBrake:
-      name: slamBrake 
-      priority: 0
-      max: 0
-      min: 0
-    slamAccelerate:
-      name: slamAccelerate
-      priority: 0
-      max: 0
-      min: 0
-
-efficient:
-  name: efficient
-  priority: 0
-  drivingMode:
-    name: drivingMode
-    priority: 0
-    max_speed:
-      name: maxSpeed
-      priority: 0
-      max: 0.0
-      min: 0.0
-    devation_speed:
-      name: deviationSpeed
-      priority: 0
-      max: 0.0
-      min: 0.0
-    averagedSpeed:
-      name: averagedSpeed
-      priority: 0
-      max: 80.0
-      min: 30.0
-  parkingMode:
-    name: parkingMode
-    priority: 0
-    stopDuration:
-      name: stopDuration
-      priority: 0
-      max: 1
-      min: 0
-
-function:
-  name: function
-  priority: 0
-  scenario:
-    name: ForwardCollision
-    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
-
-traffic:
-  name: traffic
-  priority: 0
-  majorViolation:
-    name: majorViolation
-    priority: 0
-    urbanExpresswayOrHighwaySpeedOverLimit50:
-      name: urbanExpresswayOrHighwaySpeedOverLimit50
-      priority: 0
-      max: 0
-      min: 0
-    urbanExpresswayOrHighwayReverse:
-      name: higwayreverse
-      priority: 0
-      max: 0
-      min: 0
-    urbanExpresswayOrHighwayDrivingAgainst:
-      name: higwayDrivingAgainst
-      priority: 0
-      max: 0
-      min: 0
-
-  seriousViolation:
-    name: seriousViolation
-    priority: 0
-    urbanExpresswayOrHighwayDrivingLaneStopped:
-      name: urbanExpresswayOrHighwayDrivingLaneStopped
-      priority: 0
-      max: 0
-      min: 0
-    urbanExpresswayOrHighwayEmergencyLaneStopped:
-      name: highwayEmergencyLaneStopped
-      priority: 0
-      max: 0
-      min: 0
-
-  dangerousViolation:
-    name: dangerousViolation
-    priority: 0
-    urbanExpresswayEmergencyLaneDriving:
-      name: urbanExpresswayEmergencyLaneDriving
-      priority: 0
-      max: 0
-      min: 0
-    trafficSignalViolation:
-      name: trafficSignalViolation
-      priority: 0
-      max: 0
-      min: 0
-    urbanExpresswayOrHighwaySpeedOverLimit20to50:
-      name: urbanExpresswayOrHighwaySpeedOverLimit20to50
-      priority: 0
-      max: 0
-      min: 0
-    generalRoadSpeedOverLimit50:
-      name: generalRoadSpeedOverLimit50
-      priority: 0
-      max: 0
-      min: 0
-
-  generalViolation:
-    name: generalViolation
-    priority: 0
-    generalRoadSpeedOverLimit20to50:
-      name: generalRoadSpeedOverLimit20to50
-      priority: 0
-      max: 0
-      min: 0
-    urbanExpresswayOrHighwaySpeedUnderLimit:
-      name: UrbanExpresswayOrHighwaySpeedUnderLimit
-      priority: 0
-      max: 0
-      min: 0
-    illegalDrivingOrParkingAtCrossroads:
-      name: illegalDrivingOrParkingAtCrossroads
-      priority: 0
-      max: 0
-      min: 0
-    overtake_on_right:
-      name: overtake_on_right
-      priority: 0
-      max: 0
-      min: 0
-    overtake_when_turn_around:
-      name: overtake_when_turn_around
-      priority: 0
-      max: 0
-      min: 0
-    overtake_when_passing_car:
-      name: overtake_when_passing_car
-      priority: 0
-      max: 0
-      min: 0
-    overtake_in_forbid_lane:
-      name: overtake_in_forbid_lane
-      priority: 0
-      max: 0
-      min: 0
-    overtake_in_ramp:
-      name: overtake_in_ramp
-      priority: 0
-      max: 0
-      min: 0
-    overtake_in_tunnel:
-      name: overtake_in_tunnel
-      priority: 0
-      max: 0
-      min: 0
-    overtake_on_accelerate_lane:
-      name: overtake_on_accelerate_lane
-      priority: 0
-      max: 0
-      min: 0
-    overtake_on_decelerate_lane:
-      name: overtake_on_decelerate_lane
-      priority: 0
-      max: 0
-      min: 0
-    overtake_in_different_senerios:
-      name: overtake_in_different_senerios
-      priority: 0
-      max: 0
-      min: 0
-    slow_down_in_crosswalk:
-      name: slow_down_in_crosswalk
-      priority: 0
-      max: 0
-      min: 0
-    avoid_pedestrian_in_crosswalk:
-      name: avoid_pedestrian_in_crosswalk
-      priority: 0
-      max: 0
-      min: 0
-    avoid_pedestrian_in_the_road:
-      name: avoid_pedestrian_in_the_road
-      priority: 0
-      max: 0
-      min: 0
-    avoid_pedestrian_when_turning:
-      name: avoid_pedestrian_when_turning
-      priority: 0
-      max: 0
-      min: 0
-    NoStraightThrough:
-      name: NoStraightThrough
-      priority: 0
-      max: 0
-      min: 0
-    SpeedLimitViolation:
-      name: SpeedLimitViolation
-      priority: 0
-      max: 0
-      min: 0
-    MinimumSpeedLimitViolation:
-      name: MinimumSpeedLimitViolation
-      priority: 0
-      max: 0
-      min: 0
-
-  minorViolation:
-    name: minorViolation
-    priority: 0
-    noUTurnViolation:
-      name: noUTurnViolation
-      priority: 0
-      max: 0
-      min: 0
-
-  warningViolation:
-    name: warningViolation
-    priority: 0
-    urbanExpresswayOrHighwaySpeedOverLimit0to20:
-      name: urbanExpresswayOrHighwaySpeedOverLimit0to20
-      priority: 0
-      max: 0
-      min: 0
-    urbanExpresswayOrHighwayRideLaneDivider:
-      name: urbanExpresswayOrHighwayRideLaneDivider
-      priority: 0
-      max: 0
-      min: 0
-    generalRoadIrregularLaneUse:
-      name: generalRoadIrregularLaneUse
-      priority: 0
-      max: 0
+
+safety:
+  name: safety
+  priority: 0
+  safeTime:
+    name: safetime
+    priority: 0
+    TTC:
+      name: TTC
+      priority: 0
+      max: 2000.0
+      min: 2.86
+    MTTC:
+      name: MTTC
+      priority: 0
+      max: 2000.0
+      min: 3.0
+    THW:
+      name: THW
+      priority: 0
+      max: 2000.0
+      min: 1.5
+  safeDistance:
+    name: safeDistance
+    priority: 0
+    LonSD:
+      name: LonSD
+      priority: 0
+      max: 2000.0
+      min: 10.0
+    LatSD:
+      name: LatSD 
+      priority: 0
+      max: 2000.0
+      min: 2.0
+  safeAcceleration:
+    name: safeAcceleration
+    priority: 0
+    BTN:
+      name: BTN
+      priority: 0
+      max: 1.0
+      min: -2000.0
+  safeProbability:
+    name: safeProbability
+    priority: 0
+    collisionRisk:
+      name: collisionRisk
+      priority: 0
+      max: 10.0
+      min: 0.0
+    collisionSeverity:
+      name: collisionSeverity
+      priority: 0
+      max: 10.0
+      min: 0.0
+
+comfort:
+  name: comfort
+  priority: 0
+  comfortLat:
+    name: comfortLat
+    priority: 0
+    weaving:
+      name: weaving
+      priority: 0
+      max: 0
+      min: 0
+    shake:
+      name: shake
+      priority: 0
+      max: 0
+      min: 0
+  comfortLon:
+    name: comfortLon
+    priority: 0
+    cadence:
+      name: cadence
+      priority: 0
+      max: 0
+      min: 0
+    slamBrake:
+      name: slamBrake 
+      priority: 0
+      max: 0
+      min: 0
+    slamAccelerate:
+      name: slamAccelerate
+      priority: 0
+      max: 0
+      min: 0
+
+efficient:
+  name: efficient
+  priority: 0
+  drivingMode:
+    name: drivingMode
+    priority: 0
+    max_speed:
+      name: maxSpeed
+      priority: 0
+      max: 0.0
+      min: 0.0
+    devation_speed:
+      name: deviationSpeed
+      priority: 0
+      max: 0.0
+      min: 0.0
+    averagedSpeed:
+      name: averagedSpeed
+      priority: 0
+      max: 80.0
+      min: 30.0
+  parkingMode:
+    name: parkingMode
+    priority: 0
+    stopDuration:
+      name: stopDuration
+      priority: 0
+      max: 1
+      min: 0
+
+function:
+  name: function
+  priority: 0
+  scenario:
+    name: ForwardCollision
+    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
+
+traffic:
+  name: traffic
+  priority: 0
+  majorViolation:
+    name: majorViolation
+    priority: 0
+    urbanExpresswayOrHighwaySpeedOverLimit50:
+      name: urbanExpresswayOrHighwaySpeedOverLimit50
+      priority: 0
+      max: 0
+      min: 0
+    urbanExpresswayOrHighwayReverse:
+      name: higwayreverse
+      priority: 0
+      max: 0
+      min: 0
+    urbanExpresswayOrHighwayDrivingAgainst:
+      name: higwayDrivingAgainst
+      priority: 0
+      max: 0
+      min: 0
+
+  seriousViolation:
+    name: seriousViolation
+    priority: 0
+    urbanExpresswayOrHighwayDrivingLaneStopped:
+      name: urbanExpresswayOrHighwayDrivingLaneStopped
+      priority: 0
+      max: 0
+      min: 0
+    urbanExpresswayOrHighwayEmergencyLaneStopped:
+      name: highwayEmergencyLaneStopped
+      priority: 0
+      max: 0
+      min: 0
+
+  dangerousViolation:
+    name: dangerousViolation
+    priority: 0
+    urbanExpresswayEmergencyLaneDriving:
+      name: urbanExpresswayEmergencyLaneDriving
+      priority: 0
+      max: 0
+      min: 0
+    trafficSignalViolation:
+      name: trafficSignalViolation
+      priority: 0
+      max: 0
+      min: 0
+    urbanExpresswayOrHighwaySpeedOverLimit20to50:
+      name: urbanExpresswayOrHighwaySpeedOverLimit20to50
+      priority: 0
+      max: 0
+      min: 0
+    generalRoadSpeedOverLimit50:
+      name: generalRoadSpeedOverLimit50
+      priority: 0
+      max: 0
+      min: 0
+
+  generalViolation:
+    name: generalViolation
+    priority: 0
+    generalRoadSpeedOverLimit20to50:
+      name: generalRoadSpeedOverLimit20to50
+      priority: 0
+      max: 0
+      min: 0
+    urbanExpresswayOrHighwaySpeedUnderLimit:
+      name: UrbanExpresswayOrHighwaySpeedUnderLimit
+      priority: 0
+      max: 0
+      min: 0
+    illegalDrivingOrParkingAtCrossroads:
+      name: illegalDrivingOrParkingAtCrossroads
+      priority: 0
+      max: 0
+      min: 0
+    overtake_on_right:
+      name: overtake_on_right
+      priority: 0
+      max: 0
+      min: 0
+    overtake_when_turn_around:
+      name: overtake_when_turn_around
+      priority: 0
+      max: 0
+      min: 0
+    overtake_when_passing_car:
+      name: overtake_when_passing_car
+      priority: 0
+      max: 0
+      min: 0
+    overtake_in_forbid_lane:
+      name: overtake_in_forbid_lane
+      priority: 0
+      max: 0
+      min: 0
+    overtake_in_ramp:
+      name: overtake_in_ramp
+      priority: 0
+      max: 0
+      min: 0
+    overtake_in_tunnel:
+      name: overtake_in_tunnel
+      priority: 0
+      max: 0
+      min: 0
+    overtake_on_accelerate_lane:
+      name: overtake_on_accelerate_lane
+      priority: 0
+      max: 0
+      min: 0
+    overtake_on_decelerate_lane:
+      name: overtake_on_decelerate_lane
+      priority: 0
+      max: 0
+      min: 0
+    overtake_in_different_senerios:
+      name: overtake_in_different_senerios
+      priority: 0
+      max: 0
+      min: 0
+    slow_down_in_crosswalk:
+      name: slow_down_in_crosswalk
+      priority: 0
+      max: 0
+      min: 0
+    avoid_pedestrian_in_crosswalk:
+      name: avoid_pedestrian_in_crosswalk
+      priority: 0
+      max: 0
+      min: 0
+    avoid_pedestrian_in_the_road:
+      name: avoid_pedestrian_in_the_road
+      priority: 0
+      max: 0
+      min: 0
+    avoid_pedestrian_when_turning:
+      name: avoid_pedestrian_when_turning
+      priority: 0
+      max: 0
+      min: 0
+    NoStraightThrough:
+      name: NoStraightThrough
+      priority: 0
+      max: 0
+      min: 0
+    SpeedLimitViolation:
+      name: SpeedLimitViolation
+      priority: 0
+      max: 0
+      min: 0
+    MinimumSpeedLimitViolation:
+      name: MinimumSpeedLimitViolation
+      priority: 0
+      max: 0
+      min: 0
+
+  minorViolation:
+    name: minorViolation
+    priority: 0
+    noUTurnViolation:
+      name: noUTurnViolation
+      priority: 0
+      max: 0
+      min: 0
+
+  warningViolation:
+    name: warningViolation
+    priority: 0
+    urbanExpresswayOrHighwaySpeedOverLimit0to20:
+      name: urbanExpresswayOrHighwaySpeedOverLimit0to20
+      priority: 0
+      max: 0
+      min: 0
+    urbanExpresswayOrHighwayRideLaneDivider:
+      name: urbanExpresswayOrHighwayRideLaneDivider
+      priority: 0
+      max: 0
+      min: 0
+    generalRoadIrregularLaneUse:
+      name: generalRoadIrregularLaneUse
+      priority: 0
+      max: 0
       min: 0

二進制
custom_metrics/__pycache__/metric_safety_safeTime_CustomTTC.cpython-313.pyc


二進制
custom_metrics/__pycache__/metric_user_safeTime_CustomTTC.cpython-313.pyc


File diff suppressed because it is too large
+ 0 - 30
logs/test.log


二進制
modules/lib/__pycache__/common.cpython-313.pyc


二進制
modules/lib/__pycache__/data_process.cpython-313.pyc


二進制
modules/lib/__pycache__/log_manager.cpython-310.pyc


二進制
modules/lib/__pycache__/log_manager.cpython-313.pyc


二進制
modules/lib/__pycache__/metric_registry.cpython-313.pyc


二進制
modules/lib/__pycache__/score.cpython-313.pyc


二進制
modules/metric/__pycache__/comfort.cpython-313.pyc


二進制
modules/metric/__pycache__/efficient.cpython-313.pyc


二進制
modules/metric/__pycache__/function.cpython-313.pyc


二進制
modules/metric/__pycache__/safety.cpython-310.pyc


二進制
modules/metric/__pycache__/safety.cpython-313.pyc


二進制
modules/metric/__pycache__/traffic.cpython-313.pyc


+ 11 - 10
modules/metric/comfort.py

@@ -47,31 +47,31 @@ COMFORT_INFO = [
 # ----------------------
 # 独立指标计算函数
 # ----------------------
-def weaving(data_processed) -> dict:
+def calculate_weaving(data_processed) -> dict:
     """计算蛇行指标"""
     comfort = ComfortCalculator(data_processed)
     zigzag_count = comfort.calculate_zigzag_count()
     return {"weaving": float(zigzag_count)}
 
-def shake(data_processed) -> dict:
+def calculate_shake(data_processed) -> dict:
     """计算晃动指标"""
     comfort = ComfortCalculator(data_processed)
     shake_count = comfort.calculate_shake_count()
     return {"shake": float(shake_count)}
 
-def cadence(data_processed) -> dict:
+def calculate_cadence(data_processed) -> dict:
     """计算顿挫指标"""
     comfort = ComfortCalculator(data_processed)
     cadence_count = comfort.calculate_cadence_count()
     return {"cadence": float(cadence_count)}
 
-def slamBrake(data_processed) -> dict:
+def calculate_slambrake(data_processed) -> dict:
     """计算急刹车指标"""
     comfort = ComfortCalculator(data_processed)
     slam_brake_count = comfort.calculate_slam_brake_count()
     return {"slamBrake": float(slam_brake_count)}
 
-def slamAccelerate(data_processed) -> dict:
+def calculate_slamaccelerate(data_processed) -> dict:
     """计算急加速指标"""
     comfort = ComfortCalculator(data_processed)
     slam_accel_count = comfort.calculate_slam_accel_count()
@@ -134,10 +134,11 @@ class ComfortRegistry:
         """自动注册指标函数"""
         registry = {}
         for metric_name in self.metrics:
+            func_name = f"calculate_{metric_name.lower()}"
             try:
-                registry[metric_name] = globals()[metric_name]
+                registry[metric_name] = globals()[func_name]
             except KeyError:
-                self.logger.error(f"未实现指标函数: {metric_name}")
+                self.logger.error(f"未实现指标函数: {func_name}")
         return registry
     
     def batch_execute(self) -> dict:
@@ -147,6 +148,8 @@ class ComfortRegistry:
             try:
                 result = func(self.data)
                 results.update(result)
+                # 新增:将每个指标的结果写入日志
+                self.logger.info(f'舒适性指标[{name}]计算结果: {result}')
             except Exception as e:
                 self.logger.error(f"{name} 执行失败: {str(e)}", exc_info=True)
                 results[name] = None
@@ -539,9 +542,7 @@ class ComfortManager:
     def report_statistic(self):
         """生成舒适性评分报告"""
         comfort_result = self.registry.batch_execute()
-        # evaluator = Score(self.data.comfort_config)
-        # result = evaluator.evaluate(comfort_result) 
-        # return result
+        
         return comfort_result
 
 

+ 607 - 17
modules/metric/safety.py

@@ -6,36 +6,111 @@
 
 import numpy as np
 import pandas as pd
+import math
+from collections import defaultdict
 from typing import Dict, Any, List, Optional
 
 from modules.lib.score import Score
 from modules.lib.log_manager import LogManager
 
+# 安全指标相关常量
+SAFETY_INFO = [
+    "simTime",
+    "simFrame",
+    "playerId",
+    "posX",
+    "posY",
+    "posH",
+    "speedX",
+    "speedY",
+    "accelX",
+    "accelY",
+    "v",
+    "type"
+]
 
-# 安全指标计算函数
+# ----------------------
+# SafetyCalculator单例管理
+# ----------------------
+# class SafetyCalculatorManager:
+#     """SafetyCalculator单例管理器"""
+#     _instance = None
+    
+#     @classmethod
+#     def get_instance(cls, data_processed):
+#         """获取SafetyCalculator实例,如果不存在则创建"""
+#         if cls._instance is None or cls._instance.data_processed != data_processed:
+#             cls._instance = SafetyCalculator(data_processed)
+#         return cls._instance
+
+# ----------------------
+# 独立指标计算函数
+# ----------------------
 def calculate_ttc(data_processed) -> dict:
     """计算TTC (Time To Collision)"""
-    # 实现TTC计算逻辑
-    # ...
-    return {"TTC": 3.5}  # 示例返回值
+    if data_processed is None or not hasattr(data_processed, 'object_df'):
+        return {"TTC": None}
+    try:
+        safety = SafetyCalculator(data_processed)
+        ttc_value = safety.get_ttc_value()
+        return {"TTC": ttc_value}
+    except Exception as e:
+        LogManager().get_logger().error(f"TTC计算异常: {str(e)}", exc_info=True)
+        return {"TTC": None}
 
 def calculate_mttc(data_processed) -> dict:
     """计算MTTC (Modified Time To Collision)"""
-    # 实现MTTC计算逻辑
-    # ...
-    return {"MTTC": 4.2}  # 示例返回值
+    if data_processed is None or not hasattr(data_processed, 'object_df'):
+        return {"MTTC": None}
+    try:
+        safety = SafetyCalculator(data_processed)
+        mttc_value = safety.get_mttc_value()
+        return {"MTTC": mttc_value}
+    except Exception as e:
+        LogManager().get_logger().error(f"MTTC计算异常: {str(e)}", exc_info=True)
+        return {"MTTC": None}
 
 def calculate_thw(data_processed) -> dict:
     """计算THW (Time Headway)"""
-    # 实现THW计算逻辑
-    # ...
-    return {"THW": 2.1}  # 示例返回值
+    if data_processed is None or not hasattr(data_processed, 'object_df'):
+        return {"THW": None}
+    try:
+        safety = SafetyCalculator(data_processed)
+        thw_value = safety.get_thw_value()
+        return {"THW": thw_value}
+    except Exception as e:
+        LogManager().get_logger().error(f"THW计算异常: {str(e)}", exc_info=True)
+        return {"THW": None}
 
-def calculate_collision_risk(data_processed) -> dict:
+def calculate_collisionrisk(data_processed) -> dict:
     """计算碰撞风险"""
-    # 实现碰撞风险计算逻辑
-    # ...
-    return {"collisionRisk": 0.15}  # 示例返回值
+    safety = SafetyCalculator(data_processed)
+    collision_risk_value = safety.get_collision_risk_value()
+    return {"collisionRisk": collision_risk_value}
+
+def calculate_lonsd(data_processed) -> dict:
+    """计算纵向安全距离"""
+    safety = SafetyCalculator(data_processed)
+    lonsd_value = safety.get_lonsd_value()
+    return {"LonSD": lonsd_value}
+
+def calculate_latsd(data_processed) -> dict:
+    """计算横向安全距离"""
+    safety = SafetyCalculator(data_processed)
+    latsd_value = safety.get_latsd_value()
+    return {"LatSD": latsd_value}
+
+def calculate_btn(data_processed) -> dict:
+    """计算制动威胁数"""
+    safety = SafetyCalculator(data_processed)
+    btn_value = safety.get_btn_value()
+    return {"BTN": btn_value}
+
+def calculate_collisionseverity(data_processed) -> dict:
+    """计算碰撞严重性"""
+    safety = SafetyCalculator(data_processed)
+    collision_severity_value = safety.get_collision_severity_value()
+    return {"collisionSeverity": collision_severity_value}
 
 
 class SafetyRegistry:
@@ -97,9 +172,524 @@ class SafeManager:
         """计算并报告安全指标结果"""
         safety_result = self.registry.batch_execute()
         
-        # evaluator = Score(self.data.safety_config)
-        # result = evaluator.evaluate(safety_result)
-        # return result
         return safety_result
     
+
+class SafetyCalculator:
+    """安全指标计算类 - 兼容Safe类风格"""
+
+    def __init__(self, data_processed):
+        self.logger = LogManager().get_logger()
+        self.data_processed = data_processed
+
+        self.df = data_processed.object_df.copy()
+        self.ego_df = data_processed.ego_data
+        self.obj_id_list = data_processed.obj_id_list
+        self.metric_list = [
+            'TTC', 'MTTC', 'THW', 'LonSD', 'LatSD', 'BTN', 'collisionRisk', 'collisionSeverity'
+        ]
+
+        self.time_list = self.ego_df['simTime'].values.tolist()
+        self.frame_list = self.ego_df['simFrame'].values.tolist()
+        self.collisionRisk = 0
+        self.empty_flag = True
+
+        self.logger.info("SafetyCalculator初始化完成,obj_id_list长度: %d", len(self.obj_id_list))
+
+        if len(self.obj_id_list) > 1:
+            self.unsafe_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+            self.unsafe_time_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+            self.unsafe_dist_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+            self.unsafe_acce_drac_df = pd.DataFrame(
+                columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+            self.unsafe_acce_xtn_df = pd.DataFrame(
+                columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+            self.unsafe_prob_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+            self.most_dangerous = {}
+            self.pass_percent = {}
+            self.logger.info("开始执行安全参数计算 _safe_param_cal_new")
+            self._safe_param_cal_new()
+            self.logger.info("安全参数计算完成")
+
+    def _safe_param_cal_new(self):
+        self.logger.debug("进入 _safe_param_cal_new 方法")
+        # 直接复用Safe类的实现
+        Tc = 0.3  # 安全距离
+
+        rho = self.data_processed.vehicle_config["RHO"]
+        ego_accel_max = self.data_processed.vehicle_config["EGO_ACCEL_MAX"]
+        obj_decel_max = self.data_processed.vehicle_config["OBJ_DECEL_MAX"]
+        ego_decel_min = self.data_processed.vehicle_config["EGO_DECEL_MIN"]
+        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"]
+
+        obj_dict = defaultdict(dict)
+        obj_data_dict = self.df.to_dict('records')
+        for item in obj_data_dict:
+            obj_dict[item['simFrame']][item['playerId']] = item
+
+        df_list = []
+        EGO_PLAYER_ID = 1
+
+        for frame_num in self.frame_list:
+            ego_data = obj_dict[frame_num][EGO_PLAYER_ID]
+            v1 = ego_data['v']
+            x1 = ego_data['posX']
+            y1 = ego_data['posY']
+            h1 = ego_data['posH']
+            v_x1 = ego_data['speedX']
+            v_y1 = ego_data['speedY']
+            a_x1 = ego_data['accelX']
+            a_y1 = ego_data['accelY']
+
+            for playerId in self.obj_id_list:
+                if playerId == EGO_PLAYER_ID:
+                    continue
+                try:
+                    obj_data = obj_dict[frame_num][playerId]
+                except KeyError:
+                    continue
+
+                x2 = obj_data['posX']
+                y2 = obj_data['posY']
+                dist = self.dist(x1, y1, x2, y2)
+                obj_data['dist'] = dist
+
+                v_x2 = obj_data['speedX']
+                v_y2 = obj_data['speedY']
+                v2 = obj_data['v']
+                a_x2 = obj_data['accelX']
+                a_y2 = obj_data['accelY']
+
+                dx, dy = x2 - x1, y2 - y1
+                A = np.array([dx, dy])
+                x = np.array([1, 0])
+                dot_product = np.dot(A, x)
+                vector_length_A = np.linalg.norm(A)
+                vector_length_x = np.linalg.norm(x)
+                cos_theta = dot_product / (vector_length_A * vector_length_x)
+                beta = np.arccos(cos_theta)
+                lon_d = dist * math.cos(beta - h1)
+                lat_d = abs(dist * math.sin(beta - h1))
+                obj_dict[frame_num][playerId]['lon_d'] = lon_d
+                obj_dict[frame_num][playerId]['lat_d'] = lat_d
+
+                if lon_d > 100 or lon_d < -5 or lat_d > 4:
+                    continue
+
+                self.empty_flag = False
+
+                vx, vy = v_x1 - v_x2, v_y1 - v_y2
+                ax, ay = a_x2 - a_x1, a_y2 - a_y1
+
+                v_ego_p = self._cal_v_ego_projection(dx, dy, v_x1, v_y1)
+                v_obj_p = self._cal_v_ego_projection(dx, dy, v_x2, v_y2)
+                vrel_projection_in_dist = self._cal_v_projection(dx, dy, vx, vy)
+                arel_projection_in_dist = self._cal_a_projection(dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1,
+                                                                 v_x2, v_y2)
+
+                obj_dict[frame_num][playerId]['vrel_projection_in_dist'] = vrel_projection_in_dist
+                obj_dict[frame_num][playerId]['arel_projection_in_dist'] = arel_projection_in_dist
+                obj_dict[frame_num][playerId]['v_ego_projection_in_dist'] = v_ego_p
+                obj_dict[frame_num][playerId]['v_obj_projection_in_dist'] = v_obj_p
+
+                obj_type = obj_data['type']
+
+                TTC = self._cal_TTC(dist, vrel_projection_in_dist) if abs(vrel_projection_in_dist) > 1e-6 else None
+                MTTC = self._cal_MTTC(dist, vrel_projection_in_dist, arel_projection_in_dist)
+                THW = self._cal_THW(dist, v_ego_p) if abs(v_ego_p) > 1e-6 else None
+
+                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
+                v_right = v1
+                v_left = v2
+                a_right_lat_brake_min = 1
+                a_left_lat_brake_min = 1
+                a_lat_max = 5
+
+                LatSD = self._cal_lateral_safe_dist(lat_dist, v_right, v_left, rho, a_right_lat_brake_min,
+                                                    a_left_lat_brake_min, a_lat_max)
+
+                lon_a1 = a_x1 * math.cos(h1) + a_y1 * math.sin(h1)
+                lon_a2 = a_x2 * math.cos(h1) + a_y2 * math.sin(h1)
+                lon_a = abs(lon_a1 - lon_a2)
+                lon_d = max(0.1, dist * abs(math.cos(beta - h1)))
+                lon_v = v_x1 * math.cos(h1) + v_y1 * math.sin(h1)
+                BTN = self._cal_BTN_new(lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max)
+
+                lat_a1 = a_x1 * math.sin(h1) * -1 + a_y1 * math.cos(h1)
+                lat_a2 = a_x2 * math.sin(h1) * -1 + a_y2 * math.cos(h1)
+                lat_a = abs(lat_a1 - lat_a2)
+                lat_d = dist * abs(math.sin(beta - h1))
+                lat_v = v_x1 * math.sin(h1) * -1 + v_y1 * math.cos(h1)
+
+                obj_dict[frame_num][playerId]['lat_v_rel'] = v_x1 - v_x2
+                obj_dict[frame_num][playerId]['lon_v_rel'] = v_y1 - v_y2
+
+                TTC = None if (TTC is None or TTC < 0) else TTC
+                MTTC = None if (MTTC is None or MTTC < 0) else MTTC
+                THW = None if (THW is None or THW < 0) else THW
+
+                obj_dict[frame_num][playerId]['TTC'] = TTC
+                obj_dict[frame_num][playerId]['MTTC'] = MTTC
+                obj_dict[frame_num][playerId]['THW'] = THW
+                obj_dict[frame_num][playerId]['LonSD'] = LonSD
+                obj_dict[frame_num][playerId]['LatSD'] = LatSD
+                obj_dict[frame_num][playerId]['BTN'] = abs(BTN)
+
+                collisionSeverity = 0
+                pr_death = 0
+                collisionRisk = 0
+
+                obj_dict[frame_num][playerId]['collisionSeverity'] = collisionSeverity * 100
+                obj_dict[frame_num][playerId]['pr_death'] = pr_death * 100
+                obj_dict[frame_num][playerId]['collisionRisk'] = collisionRisk * 100
+
+            df_fnum = pd.DataFrame(obj_dict[frame_num].values())
+            df_list.append(df_fnum)
+
+        df_safe = pd.concat(df_list)
+        col_list = ['simTime', 'simFrame', 'playerId',
+                    'TTC', 'MTTC', 'THW', 'LonSD', 'LatSD', 'BTN',
+                    'collisionSeverity', 'pr_death', 'collisionRisk']
+        self.df_safe = df_safe[col_list].reset_index(drop=True)
+
+    def _cal_v_ego_projection(self, dx, dy, v_x1, v_y1):
+        # 计算 AB 连线的向量 AB
+        # dx = x2 - x1
+        # dy = y2 - y1
+
+        # 计算 AB 连线的模长 |AB|
+        AB_mod = math.sqrt(dx ** 2 + dy ** 2)
+
+        # 计算 AB 连线的单位向量 U_AB
+        U_ABx = dx / AB_mod
+        U_ABy = dy / AB_mod
+
+        # 计算 A 在 AB 连线上的速度 V1_on_AB
+        V1_on_AB = v_x1 * U_ABx + v_y1 * U_ABy
+
+        return V1_on_AB
+
+    def _cal_v_projection(self, dx, dy, vx, vy):
+        # 计算 AB 连线的向量 AB
+        # dx = x2 - x1
+        # dy = y2 - y1
+
+        # 计算 AB 连线的模长 |AB|
+        AB_mod = math.sqrt(dx ** 2 + dy ** 2)
+
+        # 计算 AB 连线的单位向量 U_AB
+        U_ABx = dx / AB_mod
+        U_ABy = dy / AB_mod
+
+        # 计算 A 相对于 B 的速度 V_relative
+        # vx = vx1 - vx2
+        # vy = vy1 - vy2
+
+        # 计算 A 相对于 B 在 AB 连线上的速度 V_on_AB
+        V_on_AB = vx * U_ABx + vy * U_ABy
+
+        return V_on_AB
+
+    def _cal_a_projection(self, dx, dy, vx, vy, ax, ay, x1, y1, x2, y2, v_x1, v_y1, v_x2, v_y2):
+        # 计算 AB 连线的向量 AB
+        # dx = x2 - x1
+        # dy = y2 - y1
+
+        # 计算 θ
+        V_mod = math.sqrt(vx ** 2 + vy ** 2)
+        AB_mod = math.sqrt(dx ** 2 + dy ** 2)
+        if V_mod == 0 or AB_mod == 0:
+            return 0
+
+        cos_theta = (vx * dx + vy * dy) / (V_mod * AB_mod)
+        theta = math.acos(cos_theta)
+
+        # 计算 AB 连线的模长 |AB|
+        AB_mod = math.sqrt(dx ** 2 + dy ** 2)
+
+        # 计算 AB 连线的单位向量 U_AB
+        U_ABx = dx / AB_mod
+        U_ABy = dy / AB_mod
+
+        # 计算 A 相对于 B 的加速度 a_relative
+        # ax = ax1 - ax2
+        # ay = ay1 - ay2
+
+        # 计算 A 相对于 B 在 AB 连线上的加速度 a_on_AB
+        a_on_AB = ax * U_ABx + ay * U_ABy
+
+        VA = np.array([v_x1, v_y1])
+        VB = np.array([v_x2, v_y2])
+        D_A = np.array([x1, y1])
+        D_B = np.array([x2, y2])
+        V_r = VA - VB
+        V = np.linalg.norm(V_r)
+        w = self._cal_relative_angular_v(theta, D_A, D_B, VA, VB)
+        a_on_AB_back = self._calculate_derivative(a_on_AB, w, V, theta)
+        return a_on_AB_back
+
+    # 计算相对加速度
+    def _calculate_derivative(self, a, w, V, theta):
+        # 计算(V×cos(θ))'的值
+        # derivative = a * math.cos(theta) - w * V * math.sin(theta)theta
+        derivative = a - w * V * math.sin(theta)
+        return derivative
+
+    def _cal_relative_angular_v(self, theta, A, B, VA, VB):
+        dx = A[0] - B[0]
+        dy = A[1] - B[1]
+        dvx = VA[0] - VB[0]
+        dvy = VA[1] - VB[1]
+        # (dx * dvy - dy * dvx)
+        angular_velocity = math.sqrt(dvx ** 2 + dvy ** 2) * math.sin(theta) / math.sqrt(dx ** 2 + dy ** 2)
+        return angular_velocity
+
+    def _death_pr(self, obj_type, v_relative):
+        if obj_type == 5:
+            p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
+        else:
+            p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
+        return p_death
+
+    def _cal_collisionRisk_level(self, obj_type, v_relative, collisionSeverity):
+        if obj_type == 5:
+            p_death = 1 / (1 + np.exp(7.723 - 0.15 * v_relative))
+        else:
+            p_death = 1 / (1 + np.exp(8.192 - 0.12 * v_relative))
+        collisionRisk = 0.4 * p_death + 0.6 * collisionSeverity
+        return collisionRisk
+
+    # 求两车之间当前距离
+    def dist(self, x1, y1, x2, y2):
+        dist = np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dist
+
+    # TTC (time to collision)
+    def _cal_TTC(self, dist, vrel_projection_in_dist):
+        if vrel_projection_in_dist == 0:
+            return math.inf
+        TTC = dist / vrel_projection_in_dist
+        return TTC
+
+    def _cal_MTTC(self, dist, vrel_projection_in_dist, arel_projection_in_dist):
+        MTTC = math.nan
+        if arel_projection_in_dist != 0:
+            tmp = vrel_projection_in_dist ** 2 + 2 * arel_projection_in_dist * dist
+            if tmp < 0:
+                return math.nan
+            t1 = (-1 * vrel_projection_in_dist - math.sqrt(tmp)) / arel_projection_in_dist
+            t2 = (-1 * vrel_projection_in_dist + math.sqrt(tmp)) / arel_projection_in_dist
+            if t1 > 0 and t2 > 0:
+                if t1 >= t2:
+                    MTTC = t2
+                elif t1 < t2:
+                    MTTC = t1
+            elif t1 > 0 and t2 <= 0:
+                MTTC = t1
+            elif t1 <= 0 and t2 > 0:
+                MTTC = t2
+        if arel_projection_in_dist == 0 and vrel_projection_in_dist > 0:
+            MTTC = dist / vrel_projection_in_dist
+        return MTTC
+
+    # THW (time headway)
+    def _cal_THW(self, dist, v_ego_projection_in_dist):
+        if not v_ego_projection_in_dist:
+            THW = None
+        else:
+            THW = dist / v_ego_projection_in_dist
+        return THW
+
+    def velocity(self, v_x, v_y):
+        v = math.sqrt(v_x ** 2 + v_y ** 2) * 3.6
+        return v
+
+    def _cal_longitudinal_safe_dist(self, v_ego_p, v_obj_p, rho, ego_accel_max, ego_decel_min, ego_decel_max):
+        lon_dist_min = v_ego_p * rho + ego_accel_max * (rho ** 2) / 2 + (v_ego_p + rho * ego_accel_max) ** 2 / (
+                2 * ego_decel_min) - v_obj_p ** 2 / (2 * ego_decel_max)
+        return lon_dist_min
+
+    def _cal_lateral_safe_dist(self, lat_dist, v_right, v_left, rho, a_right_lat_brake_min, a_left_lat_brake_min,
+                               a_lat_max):
+        v_right_rho = v_right + rho * a_lat_max
+        v_left_rho = v_left + rho * a_lat_max
+        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)
+        return dist_min
+
+    # DRAC (decelerate required avoid collision)
+    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
+        if dist_length < 0:
+            dist_width = dist - (width2 / 2 + width1 / 2)
+            if dist_width < 0:
+                return math.inf
+            else:
+                d = dist_width
+        else:
+            d = dist_length
+        DRAC = vrel_projection_in_dist ** 2 / (2 * d)
+        return DRAC
+
+    # BTN (brake threat number)
+    def _cal_BTN_new(self, lon_a1, lon_a, lon_d, lon_v, ego_decel_lon_max):
+        BTN = (lon_a1 + lon_a - lon_v ** 2 / (2 * lon_d)) / ego_decel_lon_max  # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
+        return BTN
+
+    # STN (steer threat number)
+    def _cal_STN_new(self, ttc, lat_a1, lat_a, lat_d, lat_v, ego_decel_lat_max, width1, width2):
+        STN = (lat_a1 + lat_a + 2 / ttc ** 2 * (lat_d + abs(ego_decel_lat_max * lat_v) * (
+                width1 + width2) / 2 + abs(lat_v * ttc))) / ego_decel_lat_max
+        return STN
+
+    # BTN (brake threat number)
+    def cal_BTN(self, a_y1, ay, dy, vy, max_ay):
+        BTN = (a_y1 + ay - vy ** 2 / (2 * dy)) / max_ay  # max_ay为此车可实现的最大纵向加速度,目前为本次实例里的最大值
+        return BTN
+
+    # STN (steer threat number)
+    def cal_STN(self, ttc, a_x1, ax, dx, vx, max_ax, width1, width2):
+        STN = (a_x1 + ax + 2 / ttc ** 2 * (dx + np.sign(max_ax * vx) * (width1 + width2) / 2 + vx * ttc)) / max_ax
+        return STN
+
+    # 追尾碰撞风险
+    def _normal_distribution(self, x):
+        mean = 1.32
+        std_dev = 0.26
+        return (1 / (math.sqrt(std_dev * 2 * math.pi))) * math.exp(-0.5 * (x - mean) ** 2 / std_dev)
+
+    def continuous_group(self, df):
+        time_list = df['simTime'].values.tolist()
+        frame_list = df['simFrame'].values.tolist()
+
+        group_time = []
+        group_frame = []
+        sub_group_time = []
+        sub_group_frame = []
+
+        for i in range(len(frame_list)):
+            if not sub_group_time or frame_list[i] - frame_list[i - 1] <= 1:
+                sub_group_time.append(time_list[i])
+                sub_group_frame.append(frame_list[i])
+            else:
+                group_time.append(sub_group_time)
+                group_frame.append(sub_group_frame)
+                sub_group_time = [time_list[i]]
+                sub_group_frame = [frame_list[i]]
+
+        group_time.append(sub_group_time)
+        group_frame.append(sub_group_frame)
+        group_time = [g for g in group_time if len(g) >= 2]
+        group_frame = [g for g in group_frame if len(g) >= 2]
+
+        # 输出图表值
+        time = [[g[0], g[-1]] for g in group_time]
+        frame = [[g[0], g[-1]] for g in group_frame]
+
+        unfunc_time_df = pd.DataFrame(time, columns=['start_time', 'end_time'])
+        unfunc_frame_df = pd.DataFrame(frame, columns=['start_frame', 'end_frame'])
+
+        unfunc_df = pd.concat([unfunc_time_df, unfunc_frame_df], axis=1)
+        return unfunc_df
+        # 统计最危险的指标
     
+    def _safe_statistic_most_dangerous(self):
+        min_list = ['TTC', 'MTTC', 'THW', 'LonSD', 'LatSD']
+        max_list = ['BTN', 'collisionRisk', 'collisionSeverity']
+        result = {}
+        for metric in min_list:
+            if metric in self.metric_list:
+                if metric in self.df.columns:
+                    val = self.df[metric].min()
+                    result[metric] = float(val) if pd.notnull(val) else self._default_value(metric)
+                else:
+                    result[metric] = self._default_value(metric)
+        for metric in max_list:
+            if metric in self.metric_list:
+                if metric in self.df.columns:
+                    val = self.df[metric].max()
+                    result[metric] = float(val) if pd.notnull(val) else self._default_value(metric)
+                else:
+                    result[metric] = self._default_value(metric)
+        return result
+
+    def _safe_no_obj_statistic(self):
+        # 仅有自车时的默认值
+        result = {metric: self._default_value(metric) for metric in self.metric_list}
+        return result
+
+    def _default_value(self, metric):
+        # 统一默认值
+        defaults = {
+            'TTC': 10.0,
+            'MTTC': 4.2,
+            'THW': 2.1,
+            'LonSD': 10.0,
+            'LatSD': 2.0,
+            'BTN': 1.0,
+            'collisionRisk': 0.0,
+            'collisionSeverity': 0.0
+        }
+        return defaults.get(metric, None)
+
+    def report_statistic(self):
+        if len(self.obj_id_list) == 1:
+            safety_result = self._safe_no_obj_statistic()
+        else:
+            safety_result = self._safe_statistic_most_dangerous()
+        evaluator = Score(self.data_processed.safety_config)
+        result = evaluator.evaluate(safety_result)
+        print("\n[安全性表现及得分情况]")
+        return result
+
+    def get_ttc_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('TTC')
+        ttc_values = self.df_safe['TTC'].dropna()
+        return float(ttc_values.min()) if not ttc_values.empty else self._default_value('TTC')
+
+    def get_mttc_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('MTTC')
+        mttc_values = self.df_safe['MTTC'].dropna()
+        return float(mttc_values.min()) if not mttc_values.empty else self._default_value('MTTC')
+
+    def get_thw_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('THW')
+        thw_values = self.df_safe['THW'].dropna()
+        return float(thw_values.min()) if not thw_values.empty else self._default_value('THW')
+
+    def get_lonsd_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('LonSD')
+        lonsd_values = self.df_safe['LonSD'].dropna()
+        return float(lonsd_values.mean()) if not lonsd_values.empty else self._default_value('LonSD')
+
+    def get_latsd_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('LatSD')
+        latsd_values = self.df_safe['LatSD'].dropna()
+        return float(latsd_values.mean()) if not latsd_values.empty else self._default_value('LatSD')
+
+    def get_btn_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('BTN')
+        btn_values = self.df_safe['BTN'].dropna()
+        return float(btn_values.max()) if not btn_values.empty else self._default_value('BTN')
+
+    def get_collision_risk_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('collisionRisk')
+        risk_values = self.df_safe['collisionRisk'].dropna()
+        return float(risk_values.max()) if not risk_values.empty else self._default_value('collisionRisk')
+
+    def get_collision_severity_value(self) -> float:
+        if self.empty_flag or self.df_safe is None:
+            return self._default_value('collisionSeverity')
+        severity_values = self.df_safe['collisionSeverity'].dropna()
+        return float(severity_values.max()) if not severity_values.empty else self._default_value('collisionSeverity')
+

+ 327 - 297
modules/metric/traffic.py

@@ -1,6 +1,9 @@
+# ... 保留原有导入和常量定义 ...
 import math
+import operator
 import numpy as np
 import pandas as pd
+from typing import Dict, Any, List, Optional
 from modules.lib import log_manager
 from modules.lib.score import Score
 from modules.lib.log_manager import LogManager
@@ -58,62 +61,296 @@ TRFFICSIGN_INFO = [
     "sign_x",
     "sign_y",
 ]
-
-
-def overtake_when_passing_car(data_processed):
+# 修改指标函数名称为 calculate_xxx 格式
+def calculate_overtake_when_passing_car(data_processed):
+    """计算会车时超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_when_passing_car_count = overtakingviolation.calculate_overtake_when_passing_car_count()
     return {"overtake_when_passing_car": overtake_when_passing_car_count}
 
 
-def overtake_on_right(data_processed):
+def calculate_overtake_on_right(data_processed):
+    """计算右侧超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_on_right_count = overtakingviolation.calculate_overtake_on_right_count()
     return {"overtake_on_right": overtake_on_right_count}
 
 
-def overtake_when_turn_around(data_processed):
+def calculate_overtake_when_turn_around(data_processed):
+    """计算掉头时超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_when_turn_around_count = overtakingviolation.calculate_overtake_when_turn_around_count()
     return {"overtake_when_turn_around": overtake_when_turn_around_count}
 
 
-def overtake_in_forbid_lane(data_processed):
+def calculate_overtake_in_forbid_lane(data_processed):
+    """计算在禁止车道超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_in_forbid_lane_count = overtakingviolation.calculate_overtake_in_forbid_lane_count()
     return {"overtake_in_forbid_lane": overtake_in_forbid_lane_count}
 
 
-def overtake_in_ramp(data_processed):
+def calculate_overtake_in_ramp(data_processed):
+    """计算在匝道超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_in_ramp_area_count = overtakingviolation.calculate_overtake_in_ramp_area_count()
     return {"overtake_in_ramp": overtake_in_ramp_area_count}
 
 
-def overtake_in_tunnel(data_processed):
+def calculate_overtake_in_tunnel(data_processed):
+    """计算在隧道超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_in_tunnel_area_count = overtakingviolation.calculate_overtake_in_tunnel_area_count()
     return {"overtake_in_tunnel": overtake_in_tunnel_area_count}
 
 
-def overtake_on_accelerate_lane(data_processed):
+def calculate_overtake_on_accelerate_lane(data_processed):
+    """计算在加速车道超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_on_accelerate_lane_count = overtakingviolation.calculate_overtake_on_accelerate_lane_count()
     return {"overtake_on_accelerate_lane": overtake_on_accelerate_lane_count}
 
 
-def overtake_on_decelerate_lane(data_processed):
+def calculate_overtake_on_decelerate_lane(data_processed):
+    """计算在减速车道超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_on_decelerate_lane_count = overtakingviolation.calculate_overtake_on_decelerate_lane_count()
     return {"overtake_on_decelerate_lane": overtake_on_decelerate_lane_count}
 
 
-def overtake_in_different_senerios(data_processed):
+def calculate_overtake_in_different_senerios(data_processed):
+    """计算在不同场景超车指标"""
     overtakingviolation = OvertakingViolation(data_processed)
     overtake_in_different_senerios_count = overtakingviolation.calculate_overtake_in_different_senerios_count()
     return {"overtake_in_different_senerios": overtake_in_different_senerios_count}
 
 
+def calculate_slow_down_in_crosswalk(data_processed):
+    """计算在人行横道减速指标"""
+    slowdownviolation = SlowdownViolation(data_processed)
+    slow_down_in_crosswalk_count = slowdownviolation.calculate_slow_down_in_crosswalk_count()
+    return {"slowdown_down_in_crosswalk": slow_down_in_crosswalk_count}
+
+
+def calculate_avoid_pedestrian_in_crosswalk(data_processed):
+    """计算在人行横道避让行人指标"""
+    avoidpedestrianincrosswalk = SlowdownViolation(data_processed)
+    avoid_pedestrian_in_crosswalk_count = avoidpedestrianincrosswalk.calculate_avoid_pedestrian_in_the_crosswalk_count()
+    return {"avoid_pedestrian_in_crosswalk": avoid_pedestrian_in_crosswalk_count}
+
+
+def calculate_avoid_pedestrian_in_the_road(data_processed):
+    """计算在道路上避让行人指标"""
+    avoidpedestrianintheroad = SlowdownViolation(data_processed)
+    avoid_pedestrian_in_the_road_count = avoidpedestrianintheroad.calculate_avoid_pedestrian_in_the_road_count()
+    return {"avoid_pedestrian_in_the_road": avoid_pedestrian_in_the_road_count}
+
+
+def calculate_avoid_pedestrian_when_turning(data_processed):
+    """计算转弯时避让行人指标"""
+    avoidpedestrianwhenturning = SlowdownViolation(data_processed)
+    avoid_pedestrian_when_turning_count = avoidpedestrianwhenturning.calculate_avoid_pedestrian_when_turning_count()
+    return {"avoid_pedestrian_when_turning_count": avoid_pedestrian_when_turning_count}
+
+
+def calculate_turn_in_forbiden_turn_left_sign(data_processed):
+    """计算在禁止左转标志处左转指标"""
+    turnaroundviolation = TurnaroundViolation(data_processed)
+    turn_in_forbiden_turn_left_sign_count = turnaroundviolation.calculate_turn_in_forbiden_turn_left_sign_count()
+    return {"turn_in_forbiden_turn_left_sign": turn_in_forbiden_turn_left_sign_count}
+
+
+def calculate_turn_in_forbiden_turn_back_sign(data_processed):
+    """计算在禁止掉头标志处掉头指标"""
+    turnaroundviolation = TurnaroundViolation(data_processed)
+    turn_in_forbiden_turn_back_sign_count = turnaroundviolation.calculate_turn_in_forbiden_turn_back_sign_count()
+    return {"turn_in_forbiden_turn_back_sign": turn_in_forbiden_turn_back_sign_count}
+
+
+def calculate_avoid_pedestrian_when_turn_back(data_processed):
+    """计算掉头时避让行人指标"""
+    turnaroundviolation = TurnaroundViolation(data_processed)
+    avoid_pedestrian_when_turn_back_count = turnaroundviolation.calaulate_avoid_pedestrian_when_turn_back_count()
+    return {"avoid_pedestrian_when_turn_back": avoid_pedestrian_when_turn_back_count}
+
+
+def calculate_urbanexpresswayorhighwaydrivinglanestopped(data_processed):
+    """计算城市快速路或高速公路行车道停车指标"""
+    wrongwayviolation = WrongWayViolation(data_processed)
+    urbanExpresswayOrHighwayDrivingLaneStopped_count = wrongwayviolation.calculate_urbanExpresswayOrHighwayDrivingLaneStopped_count()
+    return {"urbanExpresswayOrHighwayDrivingLaneStopped": urbanExpresswayOrHighwayDrivingLaneStopped_count}
+
+
+def calculate_urbanexpresswayorhighwayemergencylanestopped(data_processed):
+    """计算城市快速路或高速公路应急车道停车指标"""
+    wrongwayviolation = WrongWayViolation(data_processed)
+    urbanExpresswayOrHighwayEmergencyLaneStopped_count = wrongwayviolation.calculate_urbanExpresswayOrHighwayDrivingLaneStopped_count()
+    return {"urbanExpresswayOrHighwayEmergencyLaneStopped": urbanExpresswayOrHighwayEmergencyLaneStopped_count}
+
+
+def calculate_urbanexpresswayemergencylanedriving(data_processed):
+    """计算城市快速路应急车道行驶指标"""
+    wrongwayviolation = WrongWayViolation(data_processed)
+    urbanExpresswayEmergencyLaneDriving_count = wrongwayviolation.calculate_urbanExpresswayEmergencyLaneDriving()
+    return {"urbanExpresswayEmergencyLaneDriving": urbanExpresswayEmergencyLaneDriving_count}
+
+
+def calculate_urbanexpresswayorhighwayspeedoverlimit50(data_processed):
+    """计算城市快速路或高速公路超速50%以上指标"""
+    speedingviolation = SpeedingViolation(data_processed)
+    urbanExpresswayOrHighwaySpeedOverLimit50_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedOverLimit50_count()
+    return {"urbanExpresswayOrHighwaySpeedOverLimit50": urbanExpresswayOrHighwaySpeedOverLimit50_count}
+
+
+def calculate_urbanexpresswayorhighwayspeedoverlimit20to50(data_processed):
+    """计算城市快速路或高速公路超速20%-50%指标"""
+    speedingviolation = SpeedingViolation(data_processed)
+    urbanExpresswayOrHighwaySpeedOverLimit20to50_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedOverLimit20to50_count()
+    return {"urbanExpresswayOrHighwaySpeedOverLimit20to50": urbanExpresswayOrHighwaySpeedOverLimit20to50_count}
+
+
+def calculate_urbanexpresswayorhighwayspeedoverlimit0to20(data_processed):
+    """计算城市快速路或高速公路超速0-20%指标"""
+    speedingviolation = SpeedingViolation(data_processed)
+    urbanExpresswayOrHighwaySpeedOverLimit0to20_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedOverLimit0to20_count()
+    return {"urbanExpresswayOrHighwaySpeedOverLimit0to20": urbanExpresswayOrHighwaySpeedOverLimit0to20_count}
+
+
+def calculate_urbanexpresswayorhighwayspeedunderlimit(data_processed):
+    """计算城市快速路或高速公路低于最低限速指标"""
+    speedingviolation = SpeedingViolation(data_processed)
+    urbanExpresswayOrHighwaySpeedUnderLimit_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedUnderLimit_count()
+    return {"urbanExpresswayOrHighwaySpeedUnderLimit": urbanExpresswayOrHighwaySpeedUnderLimit_count}
+
+
+def calculate_generalroadspeedoverlimit50(data_processed):
+    """计算一般道路超速50%以上指标"""
+    speedingviolation = SpeedingViolation(data_processed)
+    generalRoadSpeedOverLimit50_count = speedingviolation.calculate_generalRoadSpeedOverLimit50()
+    return {"generalRoadSpeedOverLimit50": generalRoadSpeedOverLimit50_count}
+
+
+def calculate_generalroadspeedoverlimit20to50(data_processed):
+    """计算一般道路超速20%-50%指标"""
+    speedingviolation = SpeedingViolation(data_processed)
+    generalRoadSpeedOverLimit20to50_count = speedingviolation.calculate_generalRoadSpeedOverLimit20to50_count()
+    return {"generalRoadSpeedOverLimit20to50": generalRoadSpeedOverLimit20to50_count}
+
+
+def calculate_trafficsignalviolation(data_processed):
+    """计算交通信号违规指标"""
+    trafficlightviolation = TrafficLightViolation(data_processed)
+    trafficSignalViolation_count = trafficlightviolation.calculate_trafficSignalViolation_count()
+    return {"trafficSignalViolation": trafficSignalViolation_count}
+
+
+def calculate_illegaldrivingorparkingatcrossroads(data_processed):
+    """计算交叉路口违法行驶或停车指标"""
+    trafficlightviolation = TrafficLightViolation(data_processed)
+    illegalDrivingOrParkingAtCrossroads_count = trafficlightviolation.calculate_illegalDrivingOrParkingAtCrossroads()
+    return {"illegalDrivingOrParkingAtCrossroads": illegalDrivingOrParkingAtCrossroads_count}
+
+
+def calculate_generalroadirregularlaneuse(data_processed):
+    """计算一般道路不按规定车道行驶指标"""
+    warningviolation = WarningViolation(data_processed)
+    generalRoadIrregularLaneUse_count = warningviolation.calculate_generalRoadIrregularLaneUse_count()
+    return {"generalRoadIrregularLaneUse": generalRoadIrregularLaneUse_count}
+
+
+def calculate_urbanexpresswayorhighwayridelanedivider(data_processed):
+    """计算城市快速路或高速公路骑车道线行驶指标"""
+    warningviolation = WarningViolation(data_processed)
+    urbanExpresswayOrHighwayRideLaneDivider_count = warningviolation.calculate_urbanExpresswayOrHighwayRideLaneDivider()
+    return {"urbanExpresswayOrHighwayRideLaneDivider": urbanExpresswayOrHighwayRideLaneDivider_count}
+
+def calculate_nostraightthrough(data_processed):
+    """计算禁止直行标志牌处直行指标"""
+    trafficsignviolation = TrafficSignViolation(data_processed)
+    noStraightThrough_count = trafficsignviolation.calculate_NoStraightThrough_count()
+    return {"NoStraightThrough": noStraightThrough_count}
+
+
+def calculate_speedlimitviolation(data_processed):
+    """计算违反限速规定指标"""
+    trafficsignviolation = TrafficSignViolation(data_processed)
+    SpeedLimitViolation_count = trafficsignviolation.calculate_SpeedLimitViolation_count()
+    return {"SpeedLimitViolation": SpeedLimitViolation_count}
+
+
+def calculate_minimumspeedlimitviolation(data_processed):
+    """计算违反最低限速规定指标"""
+    trafficsignviolation = TrafficSignViolation(data_processed)
+    calculate_MinimumSpeedLimitViolation_count = trafficsignviolation.calculate_MinimumSpeedLimitViolation_count()
+    return {"MinimumSpeedLimitViolation": calculate_MinimumSpeedLimitViolation_count}
+# ... 保留原有类定义 ...
+
+# 修改 TrafficRegistry 类的 _build_registry 方法
+class TrafficRegistry:
+    """交通违规指标注册器"""
+    
+    def __init__(self, data_processed):
+        self.logger = LogManager().get_logger()
+        self.data = data_processed
+        self.traffic_config = data_processed.traffic_config["traffic"]
+        self.metrics = self._extract_metrics(self.traffic_config)
+        self._registry = self._build_registry()
+    
+    def _extract_metrics(self, config_node: dict) -> list:
+        """从配置中提取指标名称"""
+        metrics = []
+        def _recurse(node):
+            if isinstance(node, dict):
+                if 'name' in node and not any(isinstance(v, dict) for v in node.values()):
+                    metrics.append(node['name'])
+                for v in node.values():
+                    _recurse(v)
+        _recurse(config_node)
+        self.logger.info(f'评比的交通违规指标列表:{metrics}')
+        return metrics
+    
+    def _build_registry(self) -> dict:
+        """构建指标函数注册表"""
+        registry = {}
+        for metric_name in self.metrics:
+            func_name = f"calculate_{metric_name.lower()}"
+            try:
+                registry[metric_name] = globals()[func_name]
+            except KeyError:
+                self.logger.error(f"未实现交通违规指标函数: {func_name}")
+        return registry
+    
+    def batch_execute(self) -> dict:
+        """批量执行指标计算"""
+        results = {}
+        for name, func in self._registry.items():
+            try:
+                result = func(self.data)
+                results.update(result)
+                # 新增:将每个指标的结果写入日志
+                self.logger.info(f'交通违规指标[{name}]计算结果: {result}')
+            except Exception as e:
+                self.logger.error(f"{name} 执行失败: {str(e)}", exc_info=True)
+                results[name] = None
+        self.logger.info(f'交通违规指标计算结果:{results}')
+        return results
+
+
+class TrafficManager:
+    """交通违规指标管理类"""
+    
+    def __init__(self, data_processed):
+        self.data = data_processed
+        self.logger = LogManager().get_logger()
+        self.registry = TrafficRegistry(self.data)
+    
+    def report_statistic(self):
+        """计算并报告交通违规指标结果"""
+        traffic_result = self.registry.batch_execute()
+        return traffic_result
+
+# ... 保留原有类定义和实现 ...
+
 class OvertakingViolation(object):
     """超车违规类"""
 
@@ -397,7 +634,6 @@ class OvertakingViolation(object):
             )
         else:
             pass
-
     def calculate_overtake_when_passing_car_count(self):
         self.illegal_overtake_with_car_detector()
         return self.overtake_when_passing_car_count
@@ -435,29 +671,6 @@ class OvertakingViolation(object):
         return self.overtake_in_different_senerios_count
 
 
-def slow_down_in_crosswalk(data_processed):
-    slowdownviolation = SlowdownViolation(data_processed)
-    slow_down_in_crosswalk_count = slowdownviolation.calculate_slow_down_in_crosswalk_count()
-    return {"slowdown_down_in_crosswalk": slow_down_in_crosswalk_count}
-
-
-def avoid_pedestrian_in_crosswalk(data_processed):
-    avoidpedestrianincrosswalk = SlowdownViolation(data_processed)
-    avoid_pedestrian_in_crosswalk_count = avoidpedestrianincrosswalk.calculate_avoid_pedestrian_in_the_crosswalk_count()
-    return {"avoid_pedestrian_in_crosswalk": avoid_pedestrian_in_crosswalk_count}
-
-
-def avoid_pedestrian_in_the_road(data_processed):
-    avoidpedestrianintheroad = SlowdownViolation(data_processed)
-    avoid_pedestrian_in_the_road_count = avoidpedestrianintheroad.calculate_avoid_pedestrian_in_the_road_count()
-    return {"avoid_pedestrian_in_the_road": avoid_pedestrian_in_the_road_count}
-
-
-def aviod_pedestrian_when_turning(data_processed):
-    avoidpedestrianwhenturning = SlowdownViolation(data_processed)
-    avoid_pedestrian_when_turning_count = avoidpedestrianwhenturning.calculate_avoid_pedestrian_when_turning_count()
-    return {"avoid_pedestrian_when_turning_count": avoid_pedestrian_when_turning_count}
-
 
 class SlowdownViolation(object):
     """减速让行违规类"""
@@ -656,24 +869,6 @@ class SlowdownViolation(object):
         return self.aviod_pedestrian_when_turning_count
 
 
-def turn_in_forbiden_turn_left_sign(data_processed):
-    turnaroundviolation = TurnaroundViolation(data_processed)
-    turn_in_forbiden_turn_left_sign_count = turnaroundviolation.calculate_turn_in_forbiden_turn_left_sign_count()
-    return turn_in_forbiden_turn_left_sign_count
-
-
-def turn_in_forbiden_turn_back_sign(data_processed):
-    turnaroundviolation = TurnaroundViolation(data_processed)
-    turn_in_forbiden_turn_back_sign_count = turnaroundviolation.calculate_turn_in_forbiden_turn_back_sign_count()
-    return turn_in_forbiden_turn_back_sign_count
-
-
-def avoid_pedestrian_when_turn_back(data_processed):
-    turnaroundviolation = TurnaroundViolation(data_processed)
-    avoid_pedestrian_when_turn_back_count = turnaroundviolation.calaulate_avoid_pedestrian_when_turn_back_count()
-    return avoid_pedestrian_when_turn_back_count
-
-
 class TurnaroundViolation(object):
 
     def __init__(self, df_data):
@@ -827,24 +1022,6 @@ class TurnaroundViolation(object):
         return self.avoid_pedestrian_when_turn_back_count
 
 
-def urbanExpresswayOrHighwayDrivingLaneStopped(data_processed):
-    wrongwayviolation = WrongWayViolation(data_processed)
-    urbanExpresswayOrHighwayDrivingLaneStopped_count = wrongwayviolation.calculate_urbanExpresswayOrHighwayDrivingLaneStopped_count()
-    return {"urbanExpresswayOrHighwayDrivingLaneStopped": urbanExpresswayOrHighwayDrivingLaneStopped_count}
-
-
-def urbanExpresswayOrHighwayEmergencyLaneStopped(data_processed):
-    wrongwayviolation = WrongWayViolation(data_processed)
-    urbanExpresswayOrHighwayEmergencyLaneStopped_count = wrongwayviolation.calculate_urbanExpresswayOrHighwayDrivingLaneStopped_count()
-    return {"urbanExpresswayOrHighwayEmergencyLaneStopped": urbanExpresswayOrHighwayEmergencyLaneStopped_count}
-
-
-def urbanExpresswayEmergencyLaneDriving(data_processed):
-    wrongwayviolation = WrongWayViolation(data_processed)
-    urbanExpresswayEmergencyLaneDriving_count = wrongwayviolation.calculate_urbanExpresswayEmergencyLaneDriving()
-    return {"urbanExpresswayEmergencyLaneDriving": urbanExpresswayEmergencyLaneDriving_count}
-
-
 class WrongWayViolation:
     """停车违规类"""
 
@@ -917,43 +1094,6 @@ class WrongWayViolation:
         self.process_violations()
         return self.violation_count["urbanExpresswayEmergencyLaneDriving"]
 
-
-def urbanExpresswayOrHighwaySpeedOverLimit50(data_processed):
-    speedingviolation = SpeedingViolation(data_processed)
-    urbanExpresswayOrHighwaySpeedOverLimit50_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedOverLimit50_count()
-    return {"urbanExpresswayOrHighwaySpeedOverLimit50": urbanExpresswayOrHighwaySpeedOverLimit50_count}
-
-
-def urbanExpresswayOrHighwaySpeedOverLimit20to50(data_processed):
-    speedingviolation = SpeedingViolation(data_processed)
-    urbanExpresswayOrHighwaySpeedOverLimit20to50_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedOverLimit20to50_count()
-    return {"urbanExpresswayOrHighwaySpeedOverLimit20to50": urbanExpresswayOrHighwaySpeedOverLimit20to50_count}
-
-
-def urbanExpresswayOrHighwaySpeedOverLimit0to20(data_processed):
-    speedingviolation = SpeedingViolation(data_processed)
-    urbanExpresswayOrHighwaySpeedOverLimit0to20_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedOverLimit0to20_count()
-    return {"urbanExpresswayOrHighwaySpeedOverLimit0to20": urbanExpresswayOrHighwaySpeedOverLimit0to20_count}
-
-
-def urbanExpresswayOrHighwaySpeedUnderLimit(data_processed):
-    speedingviolation = SpeedingViolation(data_processed)
-    urbanExpresswayOrHighwaySpeedUnderLimit_count = speedingviolation.calculate_urbanExpresswayOrHighwaySpeedUnderLimit_count()
-    return {"urbanExpresswayOrHighwaySpeedUnderLimit": urbanExpresswayOrHighwaySpeedUnderLimit_count}
-
-
-def generalRoadSpeedOverLimit50(data_processed):
-    speedingviolation = SpeedingViolation(data_processed)
-    generalRoadSpeedOverLimit50_count = speedingviolation.calculate_generalRoadSpeedOverLimit50()
-    return {"generalRoadSpeedOverLimit50": generalRoadSpeedOverLimit50_count}
-
-
-def generalRoadSpeedOverLimit20to50(data_processed):
-    speedingviolation = SpeedingViolation(data_processed)
-    generalRoadSpeedOverLimit20to50_count = speedingviolation.calculate_generalRoadSpeedOverLimit20to50_count()
-    return {"generalRoadSpeedOverLimit20to50": generalRoadSpeedOverLimit20to50_count}
-
-
 class SpeedingViolation(object):
     """超速违规类"""
 
@@ -1060,19 +1200,6 @@ class SpeedingViolation(object):
         return self.violation_counts["generalRoadSpeedOverLimit20to50"] if self.violation_counts.get(
             "generalRoadSpeedOverLimit20to50") else 0
 
-
-def trafficSignalViolation(data_processed):
-    trafficlightviolation = TrafficLightViolation(data_processed)
-    trafficSignalViolation_count = trafficlightviolation.calculate_trafficSignalViolation_count()
-    return {"trafficSignalViolation": trafficSignalViolation_count}
-
-
-def illegalDrivingOrParkingAtCrossroads(data_processed):
-    trafficlightviolation = TrafficLightViolation(data_processed)
-    illegalDrivingOrParkingAtCrossroads_count = trafficlightviolation.calculate_illegalDrivingOrParkingAtCrossroads()
-    return {"illegalDrivingOrParkingAtCrossroads": illegalDrivingOrParkingAtCrossroads_count}
-
-
 class TrafficLightViolation(object):
     """违反交通灯类"""
 
@@ -1234,19 +1361,6 @@ class TrafficLightViolation(object):
         self.process_violations()
         return self.violation_counts["illegalDrivingOrParkingAtCrossroads"]
 
-
-def generalRoadIrregularLaneUse(data_processed):
-    warningviolation = WarningViolation(data_processed)
-    generalRoadIrregularLaneUse_count = warningviolation.calculate_generalRoadIrregularLaneUse_count()
-    return {"generalRoadIrregularLaneUse": generalRoadIrregularLaneUse_count}
-
-
-def urbanExpresswayOrHighwayRideLaneDivider(data_processed):
-    warningviolation = WarningViolation(data_processed)
-    urbanExpresswayOrHighwayRideLaneDivider_count = warningviolation.calculate_urbanExpresswayOrHighwayRideLaneDivider()
-    return {"urbanExpresswayOrHighwayRideLaneDivider": urbanExpresswayOrHighwayRideLaneDivider_count}
-
-
 class WarningViolation(object):
     """警告性违规类"""
 
@@ -1334,183 +1448,99 @@ class WarningViolation(object):
         return self.violation_counts["urbanExpresswayOrHighwayRideLaneDivider"]
 
 
-class TrafficSignViolation(object):
+class TrafficSignViolation:
     """交通标志违规类"""
+    
+    PROHIBITED_STRAIGHT_THRESHOLD = 5
+    SIGN_TYPE_STRAIGHT_PROHIBITED = 7
+    SIGN_TYPE_SPEED_LIMIT = 12
+    SIGN_TYPE_MIN_SPEED_LIMIT = 13
 
     def __init__(self, df_data):
         self.traffic_violations_type = "交通标志违规类"
-        print("交通标志违规类 类初始化中...")
-        self.data_ego = df_data.obj_data[1]
-        self.ego_data = (
-            self.data_ego[TRFFICSIGN_INFO].copy().reset_index(drop=True)
-        )
-        self.data_ego = self.data_ego.copy()  # 避免修改原始 DataFrame
-        self.violation_counts = {
-            "NoStraightThrough": 0,  # 禁止直行标志地方直行
-            "SpeedLimitViolation": 0,  # 违反限速规定
-            "MinimumSpeedLimitViolation": 0,  # 违反最低限速规定
+        print("交通标志违规类 初始化中...")
+        
+        # 数据预处理
+        self._raw_data = df_data.obj_data[1].copy()
+        self.data_ego = self._raw_data.sort_values('simTime').reset_index(drop=True)
+        
+        # 延迟计算标志
+        self._calculated = False
+        self._violation_counts = {
+            "NoStraightThrough": 0,
+            "SpeedLimitViolation": 0,
+            "MinimumSpeedLimitViolation": 0
         }
 
-        # def checkForProhibitionViolation(self):
-
-    #     """禁令标志判断违规:7 禁止直行,12:限制速度"""
-    #     # 筛选出sign_type1为7(禁止直行)
-    #     violation_straight_df = self.data_ego[self.data_ego["sign_type1"] == 7]
-    #     violation_speed_limit_df = self.data_ego[self.data_ego["sign_type1"] == 12]
-
-    def checkForProhibitionViolation(self):
-        """禁令标志判断违规:7 禁止直行,12:限制速度"""
-        # 筛选出 sign_type1 为7(禁止直行)的数据
-        violation_straight_df = self.data_ego[self.data_ego["sign_type1"] == 7].copy()
-
-        # 判断车辆是否在禁止直行路段直行
-        if not violation_straight_df.empty:
-            # 按时间戳排序(假设数据按时间顺序处理)
-            violation_straight_df = violation_straight_df.sort_values('simTime')
-
-            # 计算航向角变化(前后时间点的差值绝对值)
-            violation_straight_df['posH_diff'] = violation_straight_df['posH'].diff().abs()
-
-            # 筛选条件:航向角变化小于阈值(例如5度)且速度不为0
-            threshold = 5  # 单位:度(根据场景调整)
-            mask = (violation_straight_df['posH_diff'] <= threshold) & (violation_straight_df['v'] > 0)
-            straight_violations = violation_straight_df[mask]
-
-            # 统计违规次数或记录违规数据
-            self.violation_counts["prohibition_straight"] = len(straight_violations)
-
-        # 限制速度判断(原代码)
-        violation_speed_limit_df = self.data_ego[self.data_ego["sign_type1"] == 12]
-        if violation_speed_limit_df.empty:
-            mask = self.data_ego["v"] > self.data_ego["sign_speed"]
-            self.violation_counts["SpeedLimitViolation"] = len(self.data_ego[mask])
-
-    def checkForInstructionViolation(self):
-        """限速标志属于指示性标志:13:最低限速"""
-        violation_minimum_speed_limit_df = self.data_ego[self.data_ego["sign_type1"] == 13]
-        if violation_minimum_speed_limit_df.empty:
-            mask = self.data_ego["v"] < self.data_ego["sign_speed"]
-            self.violation_counts["MinimumSpeedLimitViolation"] = len(self.data_ego[mask])
-
-    def statistic(self):
-        self.checkForProhibitionViolation()
-        self.checkForInstructionViolation()
-        # self.logger.info(f"交通标志违规类指标统计完成,统计结果:{self.violation_counts}")
-        return self.violation_counts
-
-
-class TrafficRegistry:
-    """舒适性指标注册器"""
-
-    def __init__(self, data_processed):
-        self.logger = LogManager().get_logger()  # 获取全局日志实例
-        self.data = data_processed
-        self.traffic_config = data_processed.traffic_config["traffic"]
-        self.metrics = self._extract_metrics(self.traffic_config)
-        self._registry = self._build_registry()
-
-    def _extract_metrics(self, config_node: dict) -> list:
-        """DFS遍历提取指标"""
-        metrics = []
-
-        def _recurse(node):
-            if isinstance(node, dict):
-                if 'name' in node and not any(isinstance(v, dict) for v in node.values()):
-                    metrics.append(node['name'])
-                for v in node.values():
-                    _recurse(v)
-
-        _recurse(config_node)
-        self.logger.info(f'评比的合规性指标列表:{metrics}')
-        return metrics
-
-    def _build_registry(self) -> dict:
-        """自动注册指标函数"""
-        registry = {}
-        for metric_name in self.metrics:
-            try:
-                registry[metric_name] = globals()[metric_name]
-            except KeyError:
-                self.logger.error(f"未实现指标函数: {metric_name}")
-        return registry
-
-    def batch_execute(self) -> dict:
-        """批量执行指标计算"""
-        results = {}
-        for name, func in self._registry.items():
-            try:
-                result = func(self.data)
-                results.update(result)
-            except Exception as e:
-                self.logger.error(f"{name} 执行失败: {str(e)}", exc_info=True)
-                results[name] = None
-        self.logger.info(f'合规性指标计算结果:{results}')
-        return results
-
-
-class TrafficManager:
-    """合规性指标计算主类"""
-
-    def __init__(self, data_processed):
-        self.data = data_processed
-        self.logger = LogManager().get_logger()
-        self.registry = TrafficRegistry(self.data)
-
-    def report_statistic(self):
-        """生成合规性评分报告"""
-        traffic_result = self.registry.batch_execute()
-        return traffic_result
+    def _ensure_calculated(self):
+        """保证计算只执行一次"""
+        if not self._calculated:
+            self._check_prohibition_violations()
+            self._check_instruction_violations()
+            self._calculated = True
+
+    def calculate_NoStraightThrough_count(self):
+        """计算禁止直行违规次数"""
+        self._ensure_calculated()
+        return self._violation_counts["NoStraightThrough"]
+
+    def calculate_SpeedLimitViolation_count(self):
+        """计算超速违规次数"""
+        self._ensure_calculated()
+        return self._violation_counts["SpeedLimitViolation"]
+
+    def calculate_MinimumSpeedLimitViolation_count(self):
+        """计算最低限速违规次数"""
+        self._ensure_calculated()
+        return self._violation_counts["MinimumSpeedLimitViolation"]
+
+    def _check_prohibition_violations(self):
+        """处理禁令标志违规(禁止直行和限速)"""
+        self._check_straight_violation()
+        self._check_speed_violation(
+            self.SIGN_TYPE_SPEED_LIMIT,
+            operator.gt,
+            "SpeedLimitViolation"
+        )
 
+    def _check_instruction_violations(self):
+        """处理指示标志违规(最低限速)"""
+        self._check_speed_violation(
+            self.SIGN_TYPE_MIN_SPEED_LIMIT,
+            operator.lt,
+            "MinimumSpeedLimitViolation"
+        )
 
-'''
-class ViolationManager:
-    """违规管理类,用于管理所有违规行为"""
+    def _check_straight_violation(self):
+        """检查禁止直行违规"""
+        straight_df = self.data_ego[self.data_ego["sign_type1"] == self.SIGN_TYPE_STRAIGHT_PROHIBITED]
+        
+        if not straight_df.empty:
+            # 计算航向角变化并填充缺失值
+            straight_df = straight_df.copy()
+            straight_df['posH_diff'] = straight_df['posH'].diff().abs().fillna(0)
+            
+            # 创建筛选条件
+            mask = (
+                (straight_df['posH_diff'] <= self.PROHIBITED_STRAIGHT_THRESHOLD) &
+                (straight_df['v'] > 0)
+            )
+            
+            self.violation_counts["NoStraightThrough"] = mask.sum()
 
-    def __init__(self, data_processed):
+    def _check_speed_violation(self, sign_type, compare_op, count_key):
+        """通用速度违规检查方法"""
+        violation_df = self.data_ego[self.data_ego["sign_type1"] == sign_type]
+        
+        if not violation_df.empty:
+            mask = compare_op(violation_df['v'], violation_df['sign_speed'])
+            self.violation_counts[count_key] = mask.sum()
 
-        self.violations = []
-        self.data = data_processed
-        self.config = data_processed.traffic_config
 
-        self.over_take_violation = OvertakingViolation(self.data)
-        self.slow_down_violation = SlowdownViolation(self.data)
-        self.wrong_way_violation = WrongWayViolation(self.data)
-        self.speeding_violation = SpeedingViolation(self.data)
-        self.traffic_light_violation = TrafficLightViolation(self.data)
-        self.warning_violation = WarningViolation(self.data)
 
-        # self.report_statistic()
 
-    def report_statistic(self):
 
-        traffic_result = self.over_take_violation.statistic()
-        traffic_result.update(self.slow_down_violation.statistic())
-        traffic_result.update(self.traffic_light_violation.statistic())
-        traffic_result.update(self.wrong_way_violation.statistic())
-        traffic_result.update(self.speeding_violation.statistic())
-        traffic_result.update(self.warning_violation.statistic())
 
 
-        # evaluator = Score(self.config)
-        # result = evaluator.evaluate(traffic_result)
 
-        # print("\n[交规类表现及得分情况]")
-        # # self.logger.info(f"Traffic Result:{traffic_result}")
-        # return result
-        return traffic_result
-'''
-
-# 示例使用
-if __name__ == "__main__":
-    case_name = 'D:\Cicv\招远\V2V_CSAE53-2020_ForwardCollision_LST_02-03'
-    mode_label = 'D:\Cicv\招远\zhaoyuan0410\config\metrics_config.yaml'
-
-    data = data_process.DataPreprocessing(case_name, mode_label)
-    traffic_instance = TrafficManager(data)
-
-    try:
-        traffic_result = traffic_instance.report_statistic()
-        result = {'traffic': traffic_result}
-        print(result)
-    except Exception as e:
-        print(f"An error occurred in Traffict.report_statistic: {e}")
+ 

+ 4 - 3
scripts/evaluator_enhanced.py

@@ -17,6 +17,7 @@ import traceback
 import json
 import inspect
 
+
 # 常量定义
 DEFAULT_WORKERS = 4
 CUSTOM_METRIC_PREFIX = "metric_"
@@ -190,7 +191,7 @@ class MetricLoader:
         module_mapping = {
             "safety": ("modules.metric.safety", "SafeManager"),
             "comfort": ("modules.metric.comfort", "ComfortManager"),
-            "traffic": ("modules.metric.traffic", "ViolationManager"),
+            "traffic": ("modules.metric.traffic", "TrafficManager"),
             "efficient": ("modules.metric.efficient", "EfficientManager"),
             "function": ("modules.metric.function", "FunctionManager"),
         }
@@ -559,13 +560,13 @@ def main():
     parser.add_argument(
         "--dataPath",
         type=str,
-        default="data/zhaoyuan1",
+        default="/home/kevin/kevin/zhaoyuan/sqlite3_demo/docker_build/data/V2V_CSAE53-2020_ForwardCollision_LST_02-03",
         help="Input data directory",
     )
     parser.add_argument(
         "--configPath",
         type=str,
-        default="config/metrics_config.yaml",
+        default="config/all_metrics_config.yaml",
         help="Metrics config file path",
     )
     parser.add_argument(

Some files were not shown because too many files changed in this diff