瀏覽代碼

0927 commit

ZihaoYANG 8 月之前
父節點
當前提交
462ce1c844
共有 100 個文件被更改,包括 8456 次插入0 次删除
  1. 0 0
      close_beta_test/config_test/builtin+all.json
  2. 0 0
      close_beta_test/config_test/builtin+ica0.json
  3. 1196 0
      close_beta_test/config_test/builtin+ica1.json
  4. 1172 0
      close_beta_test/config_test/builtin+ica2.json
  5. 0 0
      custom/voyah/0926/ACC/cicv_acc_01_delay_time_cruise.json
  6. 196 0
      custom/voyah/0926/ACC/cicv_acc_01_delay_time_cruise.py
  7. 0 0
      custom/voyah/0926/ACC/cicv_acc_02_rise_time_cruise.json
  8. 226 0
      custom/voyah/0926/ACC/cicv_acc_02_rise_time_cruise.py
  9. 0 0
      custom/voyah/0926/ACC/cicv_acc_03_peak_time_cruise.json
  10. 153 0
      custom/voyah/0926/ACC/cicv_acc_03_peak_time_cruise.py
  11. 0 0
      custom/voyah/0926/ACC/cicv_acc_04_overshoot_cruise.json
  12. 208 0
      custom/voyah/0926/ACC/cicv_acc_04_overshoot_cruise.py
  13. 0 0
      custom/voyah/0926/ACC/cicv_acc_05_steady_error_cruise.json
  14. 205 0
      custom/voyah/0926/ACC/cicv_acc_05_steady_error_cruise.py
  15. 21 0
      custom/voyah/0926/ACC/cicv_acc_06_delay_time_THW.json
  16. 0 0
      custom/voyah/0926/ACC/cicv_acc_06_delay_time_THW.py
  17. 21 0
      custom/voyah/0926/ACC/cicv_acc_07_rise_time_THW.json
  18. 0 0
      custom/voyah/0926/ACC/cicv_acc_07_rise_time_THW.py
  19. 21 0
      custom/voyah/0926/ACC/cicv_acc_08_peak_time_THW.json
  20. 0 0
      custom/voyah/0926/ACC/cicv_acc_08_peak_time_THW.py
  21. 21 0
      custom/voyah/0926/ACC/cicv_acc_09_overshoot_THW.json
  22. 0 0
      custom/voyah/0926/ACC/cicv_acc_09_overshoot_THW.py
  23. 21 0
      custom/voyah/0926/ACC/cicv_acc_10_steady_error_THW.json
  24. 0 0
      custom/voyah/0926/ACC/cicv_acc_10_steady_error_THW.py
  25. 0 0
      custom/voyah/0926/ACC/cicv_acc_11_reasonable_acceleration_percentage.json
  26. 0 0
      custom/voyah/0926/ACC/cicv_acc_11_reasonable_acceleration_percentage.py
  27. 0 0
      custom/voyah/0926/ACC/cicv_acc_12_reasonable_acceleration_change_rate_percentage.json
  28. 0 0
      custom/voyah/0926/ACC/cicv_acc_12_reasonable_acceleration_change_rate_percentage.py
  29. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control01_distance_nearby_lane.json
  30. 161 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control01_distance_nearby_lane.py
  31. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control02_lateral_offset.json
  32. 164 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control02_lateral_offset.py
  33. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control03_relative_center_distance_expectation.json
  34. 158 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control03_relative_center_distance_expectation.py
  35. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control04_relative_center_distance_standard_deviation.json
  36. 155 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control04_relative_center_distance_standard_deviation.py
  37. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control05_absolute_center_distance_expectation.json
  38. 161 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control05_absolute_center_distance_expectation.py
  39. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control06_absolute_center_distance_standard_deviation.json
  40. 158 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control06_absolute_center_distance_standard_deviation.py
  41. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control07_center_distance_max.json
  42. 160 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control07_center_distance_max.py
  43. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control08_center_distance_min.json
  44. 160 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control08_center_distance_min.py
  45. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control09_absolute_position_oscillation_frequency.json
  46. 179 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control09_absolute_position_oscillation_frequency.py
  47. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control10_absolute_position_oscillation_difference.json
  48. 211 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control10_absolute_position_oscillation_difference.py
  49. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control11_heading_deviation_max.json
  50. 164 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control11_heading_deviation_max.py
  51. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control12_relative_position_oscillation_frequency.json
  52. 236 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control12_relative_position_oscillation_frequency.py
  53. 22 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control13_relative_position_oscillation_difference.json
  54. 186 0
      custom/voyah/0926/ICA/cicv_ica_lateral_control13_relative_position_oscillation_difference.py
  55. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control01_delay_time_cruise.json
  56. 192 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control01_delay_time_cruise.py
  57. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control02_rise_time_cruise.json
  58. 222 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control02_rise_time_cruise.py
  59. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control03_peak_time_cruise.json
  60. 149 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control03_peak_time_cruise.py
  61. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control04_overshoot_cruise.json
  62. 205 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control04_overshoot_cruise.py
  63. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control05_steady_error_cruise.json
  64. 202 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control05_steady_error_cruise.py
  65. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control06_delay_time_THW.json
  66. 191 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control06_delay_time_THW.py
  67. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control07_rise_time_THW.json
  68. 231 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control07_rise_time_THW.py
  69. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control08_peak_time_THW.json
  70. 148 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control08_peak_time_THW.py
  71. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control09_overshoot_THW.json
  72. 201 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control09_overshoot_THW.py
  73. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control10_steady_error_THW.json
  74. 201 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control10_steady_error_THW.py
  75. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control11_reasonable_acceleration_percentage.json
  76. 129 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control11_reasonable_acceleration_percentage.py
  77. 21 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control12_reasonable_acceleration_change_rate_percentage.json
  78. 133 0
      custom/voyah/0926/ICA/cicv_ica_longitudinal_control12_reasonable_acceleration_change_rate_percentage.py
  79. 0 0
      custom/voyah/0926/LKA/cicv_LKA_01_distance_nearby_lane.json
  80. 0 0
      custom/voyah/0926/LKA/cicv_LKA_01_distance_nearby_lane.py
  81. 0 0
      custom/voyah/0926/LKA/cicv_LKA_02_lateral_offset.json
  82. 0 0
      custom/voyah/0926/LKA/cicv_LKA_02_lateral_offset.py
  83. 0 0
      custom/voyah/0926/LKA/cicv_LKA_03_heading_deviation_max.json
  84. 0 0
      custom/voyah/0926/LKA/cicv_LKA_03_heading_deviation_max.py
  85. 0 0
      custom/voyah/0926/LKA/cicv_LKA_04_relative_position_oscillation_frequency.json
  86. 0 0
      custom/voyah/0926/LKA/cicv_LKA_04_relative_position_oscillation_frequency.py
  87. 0 0
      custom/voyah/0926/LKA/cicv_LKA_05_relative_position_oscillation_difference.json
  88. 0 0
      custom/voyah/0926/LKA/cicv_LKA_05_relative_position_oscillation_difference.py
  89. 0 0
      custom/voyah/0926/LKA/cicv_LKA_06_absolute_center_distance_expectation.json
  90. 0 0
      custom/voyah/0926/LKA/cicv_LKA_06_absolute_center_distance_expectation.py
  91. 0 0
      custom/voyah/0926/LKA/cicv_LKA_07_absolute_center_distance_standard_deviation.json
  92. 0 0
      custom/voyah/0926/LKA/cicv_LKA_07_absolute_center_distance_standard_deviation.py
  93. 0 0
      custom/voyah/0926/LKA/cicv_LKA_08_fixed_driving_direction_TLC.json
  94. 0 0
      custom/voyah/0926/LKA/cicv_LKA_08_fixed_driving_direction_TLC.py
  95. 0 0
      custom/voyah/0926/LKA/cicv_LKA_09_fixed_steering_wheel_angle_TLC.json
  96. 0 0
      custom/voyah/0926/LKA/cicv_LKA_09_fixed_steering_wheel_angle_TLC.py
  97. 0 0
      custom/voyah/0926/LKA/cicv_LKA_10_maximum_lateral_deviation.json
  98. 0 0
      custom/voyah/0926/LKA/cicv_LKA_10_maximum_lateral_deviation.py
  99. 0 0
      custom/voyah/0926/LKA/cicv_LKA_11_minimum_lateral_deviation.json
  100. 0 0
      custom/voyah/0926/LKA/cicv_LKA_11_minimum_lateral_deviation.py

File diff suppressed because it is too large
+ 0 - 0
close_beta_test/config_test/builtin+all.json


File diff suppressed because it is too large
+ 0 - 0
close_beta_test/config_test/builtin+ica0.json


+ 1196 - 0
close_beta_test/config_test/builtin+ica1.json

@@ -0,0 +1,1196 @@
+{
+    "safe": {
+        "safeTime": {
+            "TTC": {
+                "name": "TTC",
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "2.86",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s"
+            },
+            "MTTC": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.2",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "MTTC"
+            },
+            "THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.4",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "THW"
+            }
+        },
+        "safeDistance": {
+            "LonSD": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "LonSD"
+            },
+            "LatSD": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "2",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "LatSD"
+            }
+        },
+        "safeAcceleration": {
+            "DRAC": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m/s^2",
+                "name": "DRAC"
+            },
+            "BTN": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "BTN"
+            },
+            "STN": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "STN"
+            }
+        },
+        "safeProbability": {
+            "collisionRisk": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.19",
+                            "5.4"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "碰撞风险概率"
+            },
+            "collisionSeverity": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "碰撞严重程度"
+            }
+        }
+    },
+    "function": {
+        "function_ICA": {
+            "cicv_ica_lateral_control01_distance_nearby_lane": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "离近侧车道线最小距离"
+            },
+            "cicv_ica_lateral_control02_lateral_offset": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "最大横向偏移量"
+            },
+            "cicv_ica_lateral_control03_relative_center_distance_expectation": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "相对横向偏移量分布期望"
+            },
+            "cicv_ica_lateral_control04_relative_center_distance_standard_deviation": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "相对横向偏移量分布标准差"
+            },
+            "cicv_ica_lateral_control05_absolute_center_distance_expectation": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "绝对横向偏移量分布期望"
+            },
+            "cicv_ica_lateral_control06_absolute_center_distance_standard_deviation": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "绝对横向偏移量分布标准差"
+            },
+            "cicv_ica_lateral_control07_center_distance_max": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "横向距离极大值"
+            },
+            "cicv_ica_lateral_control08_center_distance_min": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "横向距离极小值"
+            },
+            "cicv_ica_lateral_control09_absolute_position_oscillation_frequency": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "Hz",
+                "name": "横向相对位置振荡频率"
+            },
+            "cicv_ica_lateral_control10_absolute_position_oscillation_difference": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "横向相对位置振荡极差"
+            },
+            "cicv_ica_lateral_control11_heading_deviation_max": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "rad",
+                "name": "最大航向角偏差"
+            },
+            "cicv_ica_lateral_control12_relative_position_oscillation_frequency": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "Hz",
+                "name": "横向相对位置振荡频率"
+            },
+            "cicv_ica_lateral_control13_relative_position_oscillation_difference": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "0",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.00001",
+                        "multiple": [
+                            "1",
+                            "10000000"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "横向相对位置振荡极差"
+            }
+        }
+    },
+    "comfort": {
+        "comfortLat": {
+            "zigzag": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "3",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "画龙"
+            },
+            "shake": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "3",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "晃动"
+            }
+        },
+        "comfortLon": {
+            "cadence": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "顿挫"
+            },
+            "slamBrake": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "急刹"
+            },
+            "slamAccelerate": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "急加速"
+            }
+        }
+    },
+    "efficient": {
+        "efficientDrive": {
+            "averageSpeed": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "24",
+                        "multiple": [
+                            "0.8",
+                            "1.25"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "km/h",
+                "name": "平均速度"
+            }
+        },
+        "efficientStop": {
+            "stopDuration": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "停车平均时长"
+            },
+            "stopCount": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "次",
+                "name": "停车次数"
+            }
+        }
+    },
+    "compliance": {
+        "deduct1": {
+            "overspeed10": {
+                "weight": null,
+                "unit": null,
+                "name": "超速,但未超过10%"
+            },
+            "overspeed10_20": {
+                "weight": null,
+                "unit": null,
+                "name": "超速10%-20%"
+            }
+        },
+        "deduct3": {
+            "pressSolidLine": {
+                "weight": null,
+                "unit": null,
+                "name": "压实线"
+            }
+        },
+        "deduct6": {
+            "runRedLight": {
+                "weight": null,
+                "unit": null,
+                "name": "闯红灯"
+            },
+            "overspeed20_50": {
+                "weight": null,
+                "unit": null,
+                "name": "超速20%-50%"
+            }
+        },
+        "deduct12": {
+            "overspeed50": {
+                "name": "超速50%以上",
+                "weight": null,
+                "unit": null
+            }
+        }
+    },
+    "dimensionWeight": {
+        "efficient": 0.2,
+        "compliance": 0.2,
+        "function": 0.2,
+        "safe": 0.2,
+        "comfort": 0.2
+    },
+    "typeWeight": {
+        "efficient": {
+            "efficientDrive": null,
+            "efficientStop": null
+        },
+        "compliance": {
+            "deduct3": null,
+            "deduct6": null,
+            "deduct12": null,
+            "deduct1": null
+        },
+        "function": {
+            "function_ICA": null
+        },
+        "safe": {
+            "safeDistance": null,
+            "safeTime": null,
+            "safeProbability": null,
+            "safeAcceleration": null
+        },
+        "comfort": {
+            "comfortLat": null,
+            "comfortLon": null
+        }
+    },
+    "dimensionName": {
+        "efficient": "高效性",
+        "compliance": "合规性",
+        "function": "功能性",
+        "safe": "安全性",
+        "comfort": "舒适性"
+    },
+    "typeName": {
+        "efficient": {
+            "efficientDrive": "行驶",
+            "efficientStop": "停车"
+        },
+        "compliance": {
+            "deduct3": "中等违规(扣3分)",
+            "deduct6": "危险违规(扣6分)",
+            "deduct12": "重大违规(扣12分)",
+            "deduct1": "轻微违规(扣1分)"
+        },
+        "function": {
+            "function_ICA": "function_ICA"
+        },
+        "safe": {
+            "safeDistance": "距离类型",
+            "safeTime": "时间类型",
+            "safeProbability": "概率类型",
+            "safeAcceleration": "加速度类型"
+        },
+        "comfort": {
+            "comfortLat": "横向舒适性",
+            "comfortLon": "纵向舒适性"
+        }
+    }
+}

+ 1172 - 0
close_beta_test/config_test/builtin+ica2.json

@@ -0,0 +1,1172 @@
+{
+    "safe": {
+        "safeTime": {
+            "TTC": {
+                "name": "TTC",
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "2.86",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s"
+            },
+            "MTTC": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.2",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "MTTC"
+            },
+            "THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "0.4",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "THW"
+            }
+        },
+        "safeDistance": {
+            "LonSD": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "LonSD"
+            },
+            "LatSD": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "2",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m",
+                "name": "LatSD"
+            }
+        },
+        "safeAcceleration": {
+            "DRAC": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "m/s^2",
+                "name": "DRAC"
+            },
+            "BTN": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "BTN"
+            },
+            "STN": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "STN"
+            }
+        },
+        "safeProbability": {
+            "collisionRisk": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.19",
+                            "5.4"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "碰撞风险概率"
+            },
+            "collisionSeverity": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    },
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "碰撞严重程度"
+            }
+        }
+    },
+    "function": {
+        "function_ICA": {
+            "cicv_ica_longitudinal_control01_delay_time_cruise": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "定速巡航延迟时间"
+            },
+            "cicv_ica_longitudinal_control02_rise_time_cruise": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "定速巡航上升时间"
+            },
+            "cicv_ica_longitudinal_control03_peak_time_cruise": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "定速巡航峰值时间"
+            },
+            "cicv_ica_longitudinal_control04_overshoot_cruise": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "定速巡航超调量"
+            },
+            "cicv_ica_longitudinal_control06_delay_time_THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "跟车延迟时间"
+            },
+            "cicv_ica_longitudinal_control05_steady_error_cruise": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "定速巡航速度稳态误差"
+            },
+            "cicv_ica_longitudinal_control07_rise_time_THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "跟车上升时间"
+            },
+            "cicv_ica_longitudinal_control08_peak_time_THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "跟车峰值时间"
+            },
+            "cicv_ica_longitudinal_control09_overshoot_THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "跟车超调量"
+            },
+            "cicv_ica_longitudinal_control10_steady_error_THW": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1.0",
+                        "multiple": [
+                            "0.5",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "跟车速度稳态误差"
+            },
+            "cicv_ica_longitudinal_control11_reasonable_acceleration_percentage": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "100",
+                        "multiple": [
+                            "0.6",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "合理加减速度占比"
+            },
+            "cicv_ica_longitudinal_control12_reasonable_acceleration_change_rate_percentage": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "100",
+                        "multiple": [
+                            "0.6",
+                            "2"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "%",
+                "name": "合理加减速度变化率占比"
+            }
+        }
+    },
+    "comfort": {
+        "comfortLat": {
+            "zigzag": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "3",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "画龙"
+            },
+            "shake": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "3",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "晃动"
+            }
+        },
+        "comfortLon": {
+            "cadence": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "顿挫"
+            },
+            "slamBrake": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "急刹"
+            },
+            "slamAccelerate": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "10",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    },
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.2",
+                            "5"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": null,
+                "name": "急加速"
+            }
+        }
+    },
+    "efficient": {
+        "efficientDrive": {
+            "averageSpeed": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "24",
+                        "multiple": [
+                            "0.8",
+                            "1.25"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "km/h",
+                "name": "平均速度"
+            }
+        },
+        "efficientStop": {
+            "stopDuration": {
+                "priority": "0",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "5",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "s",
+                "name": "停车平均时长"
+            },
+            "stopCount": {
+                "priority": "1",
+                "paramList": [
+                    {
+                        "kind": "-1",
+                        "spare": [
+                            {
+                                "param": null
+                            },
+                            {
+                                "param": null
+                            }
+                        ],
+                        "optimal": "1",
+                        "multiple": [
+                            "0.33",
+                            "3"
+                        ]
+                    }
+                ],
+                "weight": null,
+                "unit": "次",
+                "name": "停车次数"
+            }
+        }
+    },
+    "compliance": {
+        "deduct1": {
+            "overspeed10": {
+                "weight": null,
+                "unit": null,
+                "name": "超速,但未超过10%"
+            },
+            "overspeed10_20": {
+                "weight": null,
+                "unit": null,
+                "name": "超速10%-20%"
+            }
+        },
+        "deduct3": {
+            "pressSolidLine": {
+                "weight": null,
+                "unit": null,
+                "name": "压实线"
+            }
+        },
+        "deduct6": {
+            "runRedLight": {
+                "weight": null,
+                "unit": null,
+                "name": "闯红灯"
+            },
+            "overspeed20_50": {
+                "weight": null,
+                "unit": null,
+                "name": "超速20%-50%"
+            }
+        },
+        "deduct12": {
+            "overspeed50": {
+                "name": "超速50%以上",
+                "weight": null,
+                "unit": null
+            }
+        }
+    },
+    "dimensionWeight": {
+        "efficient": 0.2,
+        "compliance": 0.2,
+        "function": 0.2,
+        "safe": 0.2,
+        "comfort": 0.2
+    },
+    "typeWeight": {
+        "efficient": {
+            "efficientDrive": null,
+            "efficientStop": null
+        },
+        "compliance": {
+            "deduct3": null,
+            "deduct6": null,
+            "deduct12": null,
+            "deduct1": null
+        },
+        "function": {
+            "function_ICA": null
+        },
+        "safe": {
+            "safeDistance": null,
+            "safeTime": null,
+            "safeProbability": null,
+            "safeAcceleration": null
+        },
+        "comfort": {
+            "comfortLat": null,
+            "comfortLon": null
+        }
+    },
+    "dimensionName": {
+        "efficient": "高效性",
+        "compliance": "合规性",
+        "function": "功能性",
+        "safe": "安全性",
+        "comfort": "舒适性"
+    },
+    "typeName": {
+        "efficient": {
+            "efficientDrive": "行驶",
+            "efficientStop": "停车"
+        },
+        "compliance": {
+            "deduct3": "中等违规(扣3分)",
+            "deduct6": "危险违规(扣6分)",
+            "deduct12": "重大违规(扣12分)",
+            "deduct1": "轻微违规(扣1分)"
+        },
+        "function": {
+            "function_ICA": "function_ICA"
+        },
+        "safe": {
+            "safeDistance": "距离类型",
+            "safeTime": "时间类型",
+            "safeProbability": "概率类型",
+            "safeAcceleration": "加速度类型"
+        },
+        "comfort": {
+            "comfortLat": "横向舒适性",
+            "comfortLon": "纵向舒适性"
+        }
+    }
+}

+ 0 - 0
custom/voyah/ACC/cicv_acc_06_delay_time_THW.json → custom/voyah/0926/ACC/cicv_acc_01_delay_time_cruise.json


+ 196 - 0
custom/voyah/0926/ACC/cicv_acc_01_delay_time_cruise.py

@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group, get_status_active_data
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.status_trigger_dict = self.data.status_trigger_dict
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_acc = pd.DataFrame()
+
+        # self.stable_start_time_cruise = None
+        self.stable_average_speed = None
+        self.delay_time_cruise = None
+
+        self.result = {
+            "name": "定速巡航延迟时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航延迟时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航延迟时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+
+        active_time_ranges = self.status_trigger_dict['ACC']['ACC_active_time']
+        self.df_acc = get_status_active_data(active_time_ranges, self.df)
+        # self.df_acc = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的 LLC_Follow_Line
+        # self.df_acc = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_acc.empty:
+            self.result['statusFlag']['functionACC'] = False
+        else:
+            self.result['statusFlag']['functionACC'] = True
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_acc['speedX'].values  # .tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def data_analyze(self):
+        change_indices = self.df_acc[self.df_acc['set_cruise_speed'] != self.df_acc['set_cruise_speed'].shift()].index
+        print(f"Change indices of set speed: {change_indices}")
+
+        set_cruise_speed = self.df_acc.loc[change_indices[0], 'set_cruise_speed']
+        self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+        if not change_indices.empty:
+            first_change_index = change_indices[change_indices != 0].min()
+            set_cruise_speed_at_change = self.df_acc.loc[first_change_index, 'set_cruise_speed']
+            timestamp_at_change = self.df_acc.loc[first_change_index, 'simTime']
+            print(f"Set speed at first change: {set_cruise_speed_at_change}, Timestamp: {timestamp_at_change}")
+
+            target_speed = (self.stable_average_speed + self.df_acc.loc[first_change_index, 'speedX']) / 2
+            closest_index = (self.df_acc['speedX'] - target_speed).abs().idxmin()
+            closest_current_speed = self.df_acc.loc[closest_index, 'speedX']
+            closest_timestamp = self.df_acc.loc[closest_index, 'simTime']
+            print(f"Closest speed: {closest_current_speed} at time: {closest_timestamp}")
+
+            self.delay_time_cruise = closest_timestamp - timestamp_at_change
+            self.result['value'] = [round(self.delay_time_cruise, 3)]
+            print(f"Delay time: {self.delay_time_cruise}")
+
+        else:
+            self.delay_time_cruise = 0
+            self.result['value'] = [round(self.delay_time_cruise, 3)]
+            print("No valid change point for further calculation.")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_acc.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[delay_time_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 0 - 0
custom/voyah/ACC/cicv_acc_07_rise_time_THW.json → custom/voyah/0926/ACC/cicv_acc_02_rise_time_cruise.json


+ 226 - 0
custom/voyah/0926/ACC/cicv_acc_02_rise_time_cruise.py

@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group, get_status_active_data
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.status_trigger_dict = self.data.status_trigger_dict
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_acc = pd.DataFrame()
+
+        self.stable_average_speed = None
+        self.rise_time_cruise = None
+
+        self.result = {
+            "name": "定速巡航上升时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航上升时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航上升时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+
+        active_time_ranges = self.status_trigger_dict['ACC']['ACC_active_time']
+        self.df_acc = get_status_active_data(active_time_ranges, self.df)
+        # self.df_acc = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_acc.empty:
+            self.result['statusFlag']['functionACC'] = False
+        else:
+            self.result['statusFlag']['functionACC'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_acc[self.df_acc['set_cruise_speed'] != self.df_acc['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_acc['speedX'].values   #.tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def _find_closest_time_stamp_cruise(self, df, target_speed, start_index):
+        """
+        在给定的数据帧df中,从start_index索引位置开始,查找与目标速度target_speed最接近的时间戳。
+
+        Args:
+            df (pd.DataFrame): 包含速度和时间戳等信息的数据帧,需要至少包含'speedX'和'simTime'两列。
+            target_speed (float): 目标速度值,用于在数据帧中查找最接近此值的时间戳。
+            start_index (int): 开始查找的索引位置,即在数据帧df中从该索引位置开始向后查找。
+
+        Returns:
+            pd.Timestamp: 与目标速度最接近的时间戳。
+
+        """
+        subset = df.loc[start_index + 1:]
+        speed_diff = np.abs(subset['speedX'] - target_speed)
+        closest_index = speed_diff.idxmin()
+        closest_timestamp = subset.loc[closest_index, 'simTime']
+        return closest_timestamp
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        set_cruise_speed = self.df_acc.loc[first_change_index, 'set_cruise_speed']
+        self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+        initial_speed = self.df_acc.loc[first_change_index, 'speedX']
+
+        target_speed_90 = initial_speed + (self.stable_average_speed - initial_speed) * 0.9
+        target_speed_10 = initial_speed + (self.stable_average_speed - initial_speed) * 0.1
+
+        timestamp_at_10 = self._find_closest_time_stamp_cruise(self.df_acc, target_speed_10, first_change_index)
+        timestamp_at_90 = self._find_closest_time_stamp_cruise(self.df_acc, target_speed_90, first_change_index)
+
+        print(f"Closest speed at 10% range from set speed: {timestamp_at_10}")
+        print(f"Closest speed at 90% range from set speed: {timestamp_at_90}")
+
+        self.rise_time_cruise = timestamp_at_90 - timestamp_at_10
+        self.result['value'] = [round(self.rise_time_cruise, 3)]
+        print(f"Rise time: {self.rise_time_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_acc.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[rise_time_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 0 - 0
custom/voyah/ACC/cicv_acc_08_peak_time_THW.json → custom/voyah/0926/ACC/cicv_acc_03_peak_time_cruise.json


+ 153 - 0
custom/voyah/0926/ACC/cicv_acc_03_peak_time_cruise.py

@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group, get_status_active_data
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.status_trigger_dict = self.data.status_trigger_dict
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_acc = pd.DataFrame()
+
+        self.peak_time_cruise = None
+
+        self.result = {
+            "name": "定速巡航峰值时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航峰值时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航峰值时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+
+        active_time_ranges = self.status_trigger_dict['ACC']['ACC_active_time']
+        self.df_acc = get_status_active_data(active_time_ranges, self.df)
+        # self.df_acc = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_acc.empty:
+            self.result['statusFlag']['functionACC'] = False
+        else:
+            self.result['statusFlag']['functionACC'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_acc[self.df_acc['set_cruise_speed'] != self.df_acc['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        if not first_change_index:
+            self.peak_time_cruise = 0
+            self.result['value'] = [round(self.peak_time_cruise, 3)]
+            print(f"peak_time_cruise: {self.peak_time_cruise}")
+        else:
+            start_time = self.df_acc.loc[first_change_index, 'simTime']
+            peak_time = self.df_acc.loc[self.df_acc['speedX'].idxmax(), 'simTime']
+            self.peak_time_cruise = peak_time - start_time
+            self.result['value'] = [round(self.peak_time_cruise, 3)]
+            print(f"peak_time_cruise: {self.peak_time_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_acc.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[peak_time_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 0 - 0
custom/voyah/ACC/cicv_acc_09_overshoot_THW.json → custom/voyah/0926/ACC/cicv_acc_04_overshoot_cruise.json


+ 208 - 0
custom/voyah/0926/ACC/cicv_acc_04_overshoot_cruise.py

@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group, get_status_active_data
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.status_trigger_dict = self.data.status_trigger_dict
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_acc = pd.DataFrame()
+
+        self.stable_average_speed = None
+        self.overshoot_cruise = None
+
+        self.result = {
+            "name": "定速巡航超调量",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航超调量(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航超调量: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        active_time_ranges = self.status_trigger_dict['ACC']['ACC_active_time']
+        self.df_acc = get_status_active_data(active_time_ranges, self.df)
+        # self.df_acc = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_acc.empty:
+            self.result['statusFlag']['functionACC'] = False
+        else:
+            self.result['statusFlag']['functionACC'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_acc[self.df_acc['set_cruise_speed'] != self.df_acc['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_acc['speedX'].values  # .tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        set_cruise_speed = self.df_acc.loc[first_change_index, 'set_cruise_speed']
+        self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+        if not first_change_index:
+            self.overshoot_cruise = 0
+        else:
+            initial_speed = self.df.loc[first_change_index, 'speedX']
+
+            if initial_speed > self.stable_average_speed:
+                self.overshoot_cruise = (self.stable_average_speed - self.df[
+                    'speedX'].min()) * 100 / self.stable_average_speed
+            elif initial_speed < self.stable_average_speed:
+                self.overshoot_cruise = (self.df[
+                                             'speedX'].max() - self.stable_average_speed) * 100 / self.stable_average_speed
+            else:
+                self.overshoot_cruise = 0
+
+        self.result['value'] = [round(self.overshoot_cruise, 3)]
+        print(f"overshoot_cruise: {self.overshoot_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_acc.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[overshoot_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 0 - 0
custom/voyah/ACC/cicv_acc_10_steady_error_THW.json → custom/voyah/0926/ACC/cicv_acc_05_steady_error_cruise.json


+ 205 - 0
custom/voyah/0926/ACC/cicv_acc_05_steady_error_cruise.py

@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group, get_status_active_data
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.status_trigger_dict = self.data.status_trigger_dict
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_acc = pd.DataFrame()
+
+        self.stable_average_speed = None
+        self.steady_error_cruise = None
+
+        self.result = {
+            "name": "定速巡航速度稳态误差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航速度稳态误差(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航速度稳态误差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        active_time_ranges = self.status_trigger_dict['ACC']['ACC_active_time']
+        self.df_acc = get_status_active_data(active_time_ranges, self.df)
+        # self.df_acc = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_acc = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_acc.empty:
+            self.result['statusFlag']['functionACC'] = False
+        else:
+            self.result['statusFlag']['functionACC'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_acc[self.df_acc['set_cruise_speed'] != self.df_acc['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_acc['speedX'].values  # .tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        if not first_change_index:
+            self.steady_error_cruise = 0
+            self.result['value'] = [round(self.steady_error_cruise, 3)]
+            print(f"steady_error_cruise: {self.steady_error_cruise}")
+        else:
+            set_cruise_speed = self.df_acc.loc[first_change_index, 'set_cruise_speed']
+            self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+            if self.stable_average_speed:
+                self.steady_error_cruise = (self.stable_average_speed - set_cruise_speed) * 100 / self.stable_average_speed
+            else:
+                self.steady_error_cruise = 0
+                raise ValueError("Stable average speed is None.")
+
+            self.result['value'] = [round(self.steady_error_cruise, 3)]
+            print(f"steady_error_cruise: {self.steady_error_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_acc.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[steady_error_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ACC/cicv_acc_06_delay_time_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 0 - 0
custom/voyah/ACC/cicv_acc_06_delay_time_THW.py → custom/voyah/0926/ACC/cicv_acc_06_delay_time_THW.py


+ 21 - 0
custom/voyah/0926/ACC/cicv_acc_07_rise_time_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 0 - 0
custom/voyah/ACC/cicv_acc_07_rise_time_THW.py → custom/voyah/0926/ACC/cicv_acc_07_rise_time_THW.py


+ 21 - 0
custom/voyah/0926/ACC/cicv_acc_08_peak_time_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 0 - 0
custom/voyah/ACC/cicv_acc_08_peak_time_THW.py → custom/voyah/0926/ACC/cicv_acc_08_peak_time_THW.py


+ 21 - 0
custom/voyah/0926/ACC/cicv_acc_09_overshoot_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 0 - 0
custom/voyah/ACC/cicv_acc_09_overshoot_THW.py → custom/voyah/0926/ACC/cicv_acc_09_overshoot_THW.py


+ 21 - 0
custom/voyah/0926/ACC/cicv_acc_10_steady_error_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 0 - 0
custom/voyah/ACC/cicv_acc_10_steady_error_THW.py → custom/voyah/0926/ACC/cicv_acc_10_steady_error_THW.py


+ 0 - 0
custom/voyah/ACC/cicv_acc_11_reasonable_acceleration_percentage.json → custom/voyah/0926/ACC/cicv_acc_11_reasonable_acceleration_percentage.json


+ 0 - 0
custom/voyah/ACC/cicv_acc_11_reasonable_acceleration_percentage.py → custom/voyah/0926/ACC/cicv_acc_11_reasonable_acceleration_percentage.py


+ 0 - 0
custom/voyah/ACC/cicv_acc_12_reasonable_acceleration_change_rate_percentage.json → custom/voyah/0926/ACC/cicv_acc_12_reasonable_acceleration_change_rate_percentage.json


+ 0 - 0
custom/voyah/ACC/cicv_acc_12_reasonable_acceleration_change_rate_percentage.py → custom/voyah/0926/ACC/cicv_acc_12_reasonable_acceleration_change_rate_percentage.py


+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control01_distance_nearby_lane.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 161 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control01_distance_nearby_lane.py

@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+车道宽度:3.75m
+车宽:1.8m
+车的一边距离车道边界线为0.975m为最佳,值越小,分值越低
+
+"""
+
+
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "离近侧车道线最小距离",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "离近侧车道线最小距离(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标01: 离近侧车道线最小距离: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadMark_df = self.roadMark_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+        # 提取距离左车道线和右车道线距离
+        # roadMark_df['nearby_distance']
+        roadMark_left_df = roadMark_df[roadMark_df.id == 0].reset_index(drop=True)
+        roadMark_right_df = roadMark_df[roadMark_df.id == 2].reset_index(drop=True)
+        roadMark_left_df['right_lateral_distance'] = roadMark_right_df['lateralDist']
+        # 计算到车道边界线距离
+        roadMark_left_df['nearby_distance_to_lane_boundary'] = roadMark_left_df.apply(lambda x: self.Compute_nearby_distance_to_lane_boundary(x, width_ego), axis=1)
+        nearby_distance_to_lane_boundary = min(roadMark_left_df['nearby_distance_to_lane_boundary'])
+        self.result['value'] = [round(nearby_distance_to_lane_boundary, 3)]
+        self.time_list_follow = roadMark_left_df['simTime'].values.tolist()
+        self.frame_list_follow = roadMark_left_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadMark_left_df['nearby_distance_to_lane_boundary'].values.tolist()
+        # print("hello world")
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+
+        v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[0, 0.975]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control02_lateral_offset.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 164 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control02_lateral_offset.py

@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "最大横向偏移量",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "最大横向偏移量(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标02: 最大横向偏移量: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        # roadMark_df['nearby_distance']
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        # roadMark_left_df['right_lateral_distance'] = roadMark_right_df['lateralDist']
+        # # 计算到车道边界线距离
+        roadPos_ego_df['laneOffset_abs'] = roadPos_ego_df.apply(lambda x: self.func_laneOffset_abs(x), axis=1)
+        # max_laneOffset_abs_index = max(roadPos_ego_df['laneOffset_abs'])
+        max_laneOffset_abs_index = roadPos_ego_df['laneOffset_abs'].idxmax()
+        row_with_max_value = roadPos_ego_df.iloc[max_laneOffset_abs_index].laneOffset
+        self.result['value'] = [row_with_max_value]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control03_relative_center_distance_expectation.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 158 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control03_relative_center_distance_expectation.py

@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "相对横向偏移量分布期望",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "相对横向偏移量分布期望(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标03: 相对横向偏移量分布期望: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        # # 计算到车道边界线距离
+        mean_laneOffset_index = roadPos_ego_df['laneOffset'].mean()
+        self.result['value'] = [round(mean_laneOffset_index, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control04_relative_center_distance_standard_deviation.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 155 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control04_relative_center_distance_standard_deviation.py

@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+    设计思路:
+    最大横向偏移量
+    zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "相对横向偏移量分布标准差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "相对横向偏移量分布标准差(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标04: 相对横向偏移量分布标准差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        mean_laneOffset_index = roadPos_ego_df['laneOffset'].std()
+        self.result['value'] = [round(mean_laneOffset_index, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control05_absolute_center_distance_expectation.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 161 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control05_absolute_center_distance_expectation.py

@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "绝对横向偏移量分布期望",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "绝对横向偏移量分布期望(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标05: 绝对横向偏移量分布期望: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        roadPos_ego_df['laneOffset_abs'] = roadPos_ego_df.apply( \
+            lambda x: self.func_laneOffset_abs(x), axis=1)
+        # # 计算到车道边界线距离
+        mean_laneOffset_index = roadPos_ego_df['laneOffset_abs'].mean()
+        self.result['value'] = [round(mean_laneOffset_index, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset_abs'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control06_absolute_center_distance_standard_deviation.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 158 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control06_absolute_center_distance_standard_deviation.py

@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+    设计思路:
+    最大横向偏移量
+    zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "绝对横向偏移量分布标准差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "绝对横向偏移量分布标准差(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标06: 绝对横向偏移量分布标准差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        roadPos_ego_df['laneOffset_abs'] = roadPos_ego_df.apply( \
+            lambda x: self.func_laneOffset_abs(x), axis=1)
+        mean_laneOffset_index = roadPos_ego_df['laneOffset_abs'].std()
+        self.result['value'] = [round(mean_laneOffset_index, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset_abs'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control07_center_distance_max.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 160 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control07_center_distance_max.py

@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "横向距离极大值",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "横向距离极大值(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标07: 横向距离极大值: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        # # 计算到车道边界线距离
+        roadPos_ego_df['laneOffset_abs'] = roadPos_ego_df.apply(lambda x: self.func_laneOffset_abs(x), axis=1)
+        max_laneOffset_abs_index = roadPos_ego_df['laneOffset_abs'].idxmax()
+        row_with_max_value = roadPos_ego_df.iloc[max_laneOffset_abs_index].laneOffset
+        self.result['value'] = [row_with_max_value]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control08_center_distance_min.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 160 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control08_center_distance_min.py

@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "横向距离极小值",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "横向距离极小值(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标08: 横向距离极小值: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+    def func_laneOffset_abs(self, x):
+        return abs(x.laneOffset)
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        # # 计算到车道边界线距离
+        roadPos_ego_df['laneOffset_abs'] = roadPos_ego_df.apply(lambda x: self.func_laneOffset_abs(x), axis=1)
+        min_laneOffset_abs_index = roadPos_ego_df['laneOffset_abs'].idxmin()
+        row_with_min_value = roadPos_ego_df.iloc[min_laneOffset_abs_index].laneOffset
+        self.result['value'] = [row_with_min_value]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control09_absolute_position_oscillation_frequency.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 179 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control09_absolute_position_oscillation_frequency.py

@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "横向相对位置振荡频率",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "横向相对位置振荡频率(Hz)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标09: 横向绝对位置振荡频率: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def func_center_line_cycle(self, l):
+        # print("\n穿过y=0的周期数: ")
+        length = len(l)
+        number_peak = 0
+        number_trough = 0
+        for number, value in enumerate(l):
+            if number == 0:
+                if value > l[number + 1] and value > 0:
+                    number_peak += 1
+                if value < l[number + 1] and value < 0:
+                    number_trough += 1
+                continue
+            if number == length - 1:
+                if value > l[number - 1] and value > 0:
+                    number_peak += 1
+                if value < l[number - 1] and value < 0:
+                    number_trough += 1
+                continue
+            if value >= l[number - 1] and value > l[number + 1] and value > 0:
+                number_peak += 1
+            if value < l[number - 1] and value <= l[number + 1] and value < 0:
+                number_trough += 1
+        # print("number_peak: ", number_peak)
+        # print("number_trough: ", number_trough)
+        cycle = min(number_peak, number_trough) - 1
+        # print("cycle: ", cycle)
+        if cycle == -1:
+            return 0
+        return cycle
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        roadPos_ego_list = roadPos_ego_df['laneOffset'].values.tolist()
+        cycle_number = self.func_center_line_cycle(roadPos_ego_list)
+        if not roadPos_ego_df['simTime'].empty:
+            frenquency = cycle_number / roadPos_ego_df['simTime'].values[-1]
+        else:
+            frenquency = cycle_number
+        self.result['value'] = [round(frenquency, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control10_absolute_position_oscillation_difference.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 211 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control10_absolute_position_oscillation_difference.py

@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "横向相对位置振荡极差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "横向相对位置振荡极差(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标10: 横向绝对位置振荡极差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def func_center_line_cycle_optical(self, l):
+        # print("\n穿过y=0的周期数: ")
+        length = len(l)
+        number_peak = 0
+        number_trough = 0
+        # 生成新的、只含有波峰波谷的列表
+        new_list = []
+        plus = []
+        minus = []
+        for number, value in enumerate(l):
+            if number == 0:
+                if value > l[number + 1] and value > 0:
+                    number_peak += 1
+                    plus.append(value)
+                if value < l[number + 1] and value < 0:
+                    number_trough += 1
+                    minus.append(value)
+                continue
+
+            if number == length - 1:
+                if value > l[number - 1] and value > 0:
+                    number_peak += 1
+                    plus.append(value)
+                    if len(minus) != 0:
+                        new_list.append(min(minus))
+                        minus = []
+                if value < l[number - 1] and value < 0:
+                    number_trough += 1
+                    minus.append(value)
+                    if len(plus) != 0:
+                        new_list.append(max(plus))
+                        plus = []
+                if len(minus) != 0:
+                    new_list.append(min(minus))
+                    minus = []
+                if len(plus) != 0:
+                    new_list.append(max(plus))
+                    plus = []
+                continue
+
+            if value >= l[number - 1] and value > l[number + 1] and value > 0:
+                number_peak += 1
+                plus.append(value)
+                if len(minus) != 0:
+                    new_list.append(min(minus))
+                    minus = []
+            if value < l[number - 1] and value <= l[number + 1] and value < 0:
+                number_trough += 1
+                minus.append(value)
+                if len(plus) != 0:
+                    new_list.append(max(plus))
+                    plus = []
+        cycle = min(number_peak, number_trough) - 1
+        difference_list = []
+        for i in range(len(new_list) - 1):
+            difference = abs(new_list[i] - new_list[i + 1])
+            difference_list.append(difference)
+        if len(difference_list) == 0:
+            maximum_range = -1
+            # print(f"极差: {maximum_range}")
+        else:
+            maximum_range = max(difference_list)
+            # print(f"极差: {maximum_range}")
+        return maximum_range
+
+    def data_analyze(self):
+        roadPos_df = self.roadPos_df
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        # laneOffset_max = max(roadPos_ego_df['laneOffset'])
+        # laneOffset_min = min(roadPos_ego_df['laneOffset'])
+        # oscillation_difference = laneOffset_max-laneOffset_min
+        # self.result['value'] = round(oscillation_difference, 3)
+
+        roadPos_ego_list = roadPos_ego_df['laneOffset'].values.tolist()
+        maximum_range = self.func_center_line_cycle_optical(roadPos_ego_list)
+
+        self.result['value'] = [round(maximum_range, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control11_heading_deviation_max.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 164 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control11_heading_deviation_max.py

@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大航向偏差角
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "最大航向角偏差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "最大航向角偏差(rad)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标11: 最大航向角偏差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def dist(self, x1, y1, x2, y2):
+        dis = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
+        return dis
+
+    def Compute_nearby_distance_to_lane_boundary(self, x, width_ego):
+        if x.lateralDist < abs(x.right_lateral_distance):
+            return x.lateralDist - width_ego/2
+        else:
+            return abs(x.right_lateral_distance) - width_ego/2
+
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        road_mark_df = self.roadMark_df
+        ego_df = player_df[player_df.playerId == 1].reset_index(drop=True)
+        # width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 左车道线曲率,右车道线曲率,求二者平均值,计算车道线曲率,再与自车朝向相减
+        road_mark_left_df = road_mark_df[road_mark_df.id == 0].reset_index(drop=True)
+        road_mark_right_df = road_mark_df[road_mark_df.id == 2].reset_index(drop=True)
+        road_mark_left_df['curvHor_left'] = road_mark_left_df['curvHor']
+        road_mark_left_df['curvHor_right'] = road_mark_right_df['curvHor']
+        road_mark_left_df['curvHor_middle'] = road_mark_left_df[['curvHor_left', 'curvHor_right']].apply( \
+            lambda x: (x['curvHor_left'] + x['curvHor_right'])/2, axis=1)
+        ego_df['curvHor_middle'] = road_mark_left_df['curvHor_middle']
+        ego_df['heading_deviation_abs'] = ego_df[['curvHor_middle', 'posH']].apply( \
+            lambda x: abs(x['posH'] - x['curvHor_middle']), axis=1)
+        row_with_max_value = max(ego_df['heading_deviation_abs'])
+
+        self.result['value'] = [row_with_max_value]
+        self.time_list_follow = ego_df['simTime'].values.tolist()
+        self.frame_list_follow = ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = ego_df['heading_deviation_abs'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control12_relative_position_oscillation_frequency.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 236 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control12_relative_position_oscillation_frequency.py

@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "横向相对位置振荡频率",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "横向相对位置振荡频率(Hz)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标12: 横向相对位置振荡频率: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def func_center_line_cycle(self, l):
+        # print("\n穿过y=0的周期数: ")
+        length = len(l)
+        number_peak = 0
+        number_trough = 0
+        for number, value in enumerate(l):
+            if number == 0:
+                if value > l[number + 1] and value > 0:
+                    number_peak += 1
+                if value < l[number + 1] and value < 0:
+                    number_trough += 1
+                continue
+            if number == length - 1:
+                if value > l[number - 1] and value > 0:
+                    number_peak += 1
+                if value < l[number - 1] and value < 0:
+                    number_trough += 1
+                continue
+            if value >= l[number - 1] and value > l[number + 1] and value > 0:
+                number_peak += 1
+            if value < l[number - 1] and value <= l[number + 1] and value < 0:
+                number_trough += 1
+        # print("number_peak: ", number_peak)
+        # print("number_trough: ", number_trough)
+        cycle = min(number_peak, number_trough) - 1
+        # print("cycle: ", cycle)
+        if cycle == -1:
+            return 0
+        return cycle
+
+    def func_normal_cycle_optical(self, l):
+        # print("正常的周期数: ")
+        length = len(l)
+        number_peak = 0
+        number_trough = 0
+        # value_peak = []
+        # value_trough = []
+        # 生成新的、只含有波峰波谷的列表
+        new_list = []
+        for number, value in enumerate(l):
+            if number == 0:
+                if value > l[number + 1]:
+                    number_peak += 1
+                    new_list.append(value)
+                if value < l[number + 1]:
+                    number_trough += 1
+                    new_list.append(value)
+                continue
+            if number == length - 1:
+                if value > l[number - 1]:
+                    number_peak += 1
+                    new_list.append(value)
+                if value < l[number - 1]:
+                    number_trough += 1
+                    new_list.append(value)
+                continue
+            if value >= l[number - 1] and value > l[number + 1]:
+                number_peak += 1
+                new_list.append(value)
+            if value < l[number - 1] and value <= l[number + 1]:
+                number_trough += 1
+                new_list.append(value)
+        if abs(number_peak - number_trough) > 1:
+            # print("计算波峰波谷有误")
+            pass
+        else:
+            # print("number_peak: ", number_peak)
+            # print("number_trough: ", number_trough)
+            cycle = max(number_peak, number_trough) - 1
+            # print("cycle: ", cycle)
+        # print(f"value_peak: {value_peak}")
+        # print(f"value_trough: {value_trough}")
+
+        # print(f"new_list: {new_list}")
+        difference_list = []
+        for i in range(len(new_list) - 1):
+            difference = abs(new_list[i] - new_list[i + 1])
+            difference_list.append(difference)
+        if len(difference_list) == 0:
+            maximum_range = -1
+            # print(f"极差: {maximum_range}")
+        else:
+            maximum_range = max(difference_list)
+            # print(f"极差: {maximum_range}")
+        return cycle
+
+
+    def data_analyze(self):
+        # 提取自车宽度
+        roadPos_df = self.roadPos_df
+        player_df = self.df
+        ego_df = player_df[player_df.playerId == 1]
+        width_ego = ego_df['dimY'].values.tolist()[0]
+
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        roadPos_ego_list = roadPos_ego_df['laneOffset'].values.tolist()
+        cycle_number = self.func_normal_cycle_optical(roadPos_ego_list)
+        if not roadPos_ego_df['simTime'].empty:
+            frenquency = cycle_number / roadPos_ego_df['simTime'].values[-1]
+        else:
+            frenquency = cycle_number
+        self.result['value'] = [round(frenquency, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 22 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control13_relative_position_oscillation_difference.json

@@ -0,0 +1,22 @@
+
+{
+  "priority": "0",
+  "paramList": [
+    {
+      "kind": "0",
+      "optimal": "0.00001",
+      "multiple": [
+        "1",
+        "10000000"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 186 - 0
custom/voyah/0926/ICA/cicv_ica_lateral_control13_relative_position_oscillation_difference.py

@@ -0,0 +1,186 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhangyu
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+最大横向偏移量
+zy_center_distance_expectation
+"""
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_follow = pd.DataFrame()
+        self.roadMark_df = pd.DataFrame()
+        self.roadPos_df = pd.DataFrame()
+
+
+        self.time_list_follow = list()
+        self.frame_list_follow = list()
+        self.dist_list = list()
+        self.dist_deviation_list = list()
+        self.dist_deviation_list_full_time = list()
+
+        self.result = {
+            "name": "横向相对位置振荡极差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "横向相对位置振荡极差(m)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"指标13: 横向相对位置振荡极差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.object_df[self.data.object_df.playerId == 1]
+        self.df_follow = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_follow = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+        self.roadMark_df = self.data.road_mark_df
+        self.roadPos_df = self.data.road_pos_df
+
+        if self.df_follow.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def func_normal_cycle_optical(self, l):
+        # print("正常的周期数: ")
+        length = len(l)
+        number_peak = 0
+        number_trough = 0
+        # 生成新的、只含有波峰波谷的列表
+        new_list = []
+        for number, value in enumerate(l):
+            if number == 0:
+                if value > l[number + 1]:
+                    number_peak += 1
+                    new_list.append(value)
+                if value < l[number + 1]:
+                    number_trough += 1
+                    new_list.append(value)
+                continue
+            if number == length - 1:
+                if value > l[number - 1]:
+                    number_peak += 1
+                    new_list.append(value)
+                if value < l[number - 1]:
+                    number_trough += 1
+                    new_list.append(value)
+                continue
+            if value >= l[number - 1] and value > l[number + 1]:
+                number_peak += 1
+                new_list.append(value)
+            if value < l[number - 1] and value <= l[number + 1]:
+                number_trough += 1
+                new_list.append(value)
+        if abs(number_peak - number_trough) > 1:
+            pass
+        else:
+            cycle = max(number_peak, number_trough) - 1
+        difference_list = []
+        for i in range(len(new_list) - 1):
+            difference = abs(new_list[i] - new_list[i + 1])
+            difference_list.append(difference)
+        if len(difference_list) == 0:
+            maximum_range = -1
+            # print(f"极差: {maximum_range}")
+        else:
+            maximum_range = max(difference_list)
+            # print(f"极差: {maximum_range}")
+        return maximum_range
+
+    def data_analyze(self):
+        roadPos_df = self.roadPos_df
+        # 提取距离左车道线和右车道线距离
+        roadPos_ego_df = roadPos_df[roadPos_df.playerId == 1].reset_index(drop=True)
+        roadPos_ego_list = roadPos_ego_df['laneOffset'].values.tolist()
+        oscillation_difference = self.func_normal_cycle_optical(roadPos_ego_list)
+        self.result['value'] = [round(oscillation_difference, 3)]
+        self.time_list_follow = roadPos_ego_df['simTime'].values.tolist()
+        self.frame_list_follow = roadPos_ego_df['simFrame'].values.tolist()
+        self.dist_deviation_list = roadPos_ego_df['laneOffset'].values.tolist()
+
+    def markline_statistic(self):
+        unfunc_df = pd.DataFrame({'simTime': self.time_list_follow, 'simFrame': self.frame_list_follow,
+                                  'dist_deviation': self.dist_deviation_list})
+        unfunc_df = unfunc_df[unfunc_df['simFrame'] > 1]
+        # v_df = unfunc_df[unfunc_df['dist_deviation'] > 0]
+        v_df = unfunc_df
+        v_df = v_df[['simTime', 'simFrame', 'dist_deviation']]
+        v_follow_df = continuous_group(v_df)
+        v_follow_df['type'] = "ICA"
+        self.markline_df = pd.concat([self.markline_df, v_follow_df], ignore_index=True)
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.dist_deviation_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.dist_deviation_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        self.markline_statistic()
+        markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = markline_slices
+        self.result['reportData']['range'] = f"[-1.875, 1.875]"
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[ica_distance_deviation:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control01_delay_time_cruise.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 192 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control01_delay_time_cruise.py

@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        # self.stable_start_time_cruise = None
+        self.stable_average_speed = None
+        self.delay_time_cruise = None
+
+        self.result = {
+            "name": "定速巡航延迟时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航延迟时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航延迟时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的 LLC_Follow_Line
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_ica['speedX'].values  # .tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def data_analyze(self):
+        change_indices = self.df_ica[self.df_ica['set_cruise_speed'] != self.df_ica['set_cruise_speed'].shift()].index
+        print(f"Change indices of set speed: {change_indices}")
+
+        set_cruise_speed = self.df_ica.loc[change_indices[0], 'set_cruise_speed']
+        self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+        if not change_indices.empty:
+            first_change_index = change_indices[change_indices != 0].min()
+            set_cruise_speed_at_change = self.df_ica.loc[first_change_index, 'set_cruise_speed']
+            timestamp_at_change = self.df_ica.loc[first_change_index, 'simTime']
+            print(f"Set speed at first change: {set_cruise_speed_at_change}, Timestamp: {timestamp_at_change}")
+
+            target_speed = (self.stable_average_speed + self.df_ica.loc[first_change_index, 'speedX']) / 2
+            closest_index = (self.df_ica['speedX'] - target_speed).abs().idxmin()
+            closest_current_speed = self.df_ica.loc[closest_index, 'speedX']
+            closest_timestamp = self.df_ica.loc[closest_index, 'simTime']
+            print(f"Closest speed: {closest_current_speed} at time: {closest_timestamp}")
+
+            self.delay_time_cruise = closest_timestamp - timestamp_at_change
+            self.result['value'] = [round(self.delay_time_cruise, 3)]
+            print(f"Delay time: {self.delay_time_cruise}")
+
+        else:
+            self.delay_time_cruise = 0
+            self.result['value'] = [round(self.delay_time_cruise, 3)]
+            print("No valid change point for further calculation.")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[delay_time_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control02_rise_time_cruise.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 222 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control02_rise_time_cruise.py

@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.stable_average_speed = None
+        self.rise_time_cruise = None
+
+        self.result = {
+            "name": "定速巡航上升时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航上升时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航上升时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_cruise_speed'] != self.df_ica['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_ica['speedX'].values   #.tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def _find_closest_time_stamp_cruise(self, df, target_speed, start_index):
+        """
+        在给定的数据帧df中,从start_index索引位置开始,查找与目标速度target_speed最接近的时间戳。
+
+        Args:
+            df (pd.DataFrame): 包含速度和时间戳等信息的数据帧,需要至少包含'speedX'和'simTime'两列。
+            target_speed (float): 目标速度值,用于在数据帧中查找最接近此值的时间戳。
+            start_index (int): 开始查找的索引位置,即在数据帧df中从该索引位置开始向后查找。
+
+        Returns:
+            pd.Timestamp: 与目标速度最接近的时间戳。
+
+        """
+        subset = df.loc[start_index + 1:]
+        speed_diff = np.abs(subset['speedX'] - target_speed)
+        closest_index = speed_diff.idxmin()
+        closest_timestamp = subset.loc[closest_index, 'simTime']
+        return closest_timestamp
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        set_cruise_speed = self.df_ica.loc[first_change_index, 'set_cruise_speed']
+        self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+        initial_speed = self.df_ica.loc[first_change_index, 'speedX']
+
+        target_speed_90 = initial_speed + (self.stable_average_speed - initial_speed) * 0.9
+        target_speed_10 = initial_speed + (self.stable_average_speed - initial_speed) * 0.1
+
+        timestamp_at_10 = self._find_closest_time_stamp_cruise(self.df_ica, target_speed_10, first_change_index)
+        timestamp_at_90 = self._find_closest_time_stamp_cruise(self.df_ica, target_speed_90, first_change_index)
+
+        print(f"Closest speed at 10% range from set speed: {timestamp_at_10}")
+        print(f"Closest speed at 90% range from set speed: {timestamp_at_90}")
+
+        self.rise_time_cruise = timestamp_at_90 - timestamp_at_10
+        self.result['value'] = [round(self.rise_time_cruise, 3)]
+        print(f"Rise time: {self.rise_time_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[rise_time_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control03_peak_time_cruise.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 149 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control03_peak_time_cruise.py

@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.peak_time_cruise = None
+
+        self.result = {
+            "name": "定速巡航峰值时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航峰值时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航峰值时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_cruise_speed'] != self.df_ica['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        if not first_change_index:
+            self.peak_time_cruise = 0
+            self.result['value'] = [round(self.peak_time_cruise, 3)]
+            print(f"peak_time_cruise: {self.peak_time_cruise}")
+        else:
+            start_time = self.df_ica.loc[first_change_index, 'simTime']
+            peak_time = self.df_ica.loc[self.df_ica['speedX'].idxmax(), 'simTime']
+            self.peak_time_cruise = peak_time - start_time
+            self.result['value'] = [round(self.peak_time_cruise, 3)]
+            print(f"peak_time_cruise: {self.peak_time_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[peak_time_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control04_overshoot_cruise.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 205 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control04_overshoot_cruise.py

@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.stable_average_speed = None
+        self.overshoot_cruise = None
+
+        self.result = {
+            "name": "定速巡航超调量",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航超调量(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航超调量: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_cruise_speed'] != self.df_ica['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_ica['speedX'].values  # .tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        set_cruise_speed = self.df_ica.loc[first_change_index, 'set_cruise_speed']
+        self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+        if not first_change_index:
+            self.overshoot_cruise = 0
+        else:
+            initial_speed = self.df.loc[first_change_index, 'speedX']
+
+            if initial_speed > self.stable_average_speed:
+                self.overshoot_cruise = (self.stable_average_speed - self.df[
+                    'speedX'].min()) * 100 / self.stable_average_speed
+            elif initial_speed < self.stable_average_speed:
+                self.overshoot_cruise = (self.df[
+                                             'speedX'].max() - self.stable_average_speed) * 100 / self.stable_average_speed
+            else:
+                self.overshoot_cruise = 0
+
+        self.result['value'] = [round(self.overshoot_cruise, 3)]
+        print(f"overshoot_cruise: {self.overshoot_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[overshoot_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control05_steady_error_cruise.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 202 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control05_steady_error_cruise.py

@@ -0,0 +1,202 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.stable_average_speed = None
+        self.steady_error_cruise = None
+
+        self.result = {
+            "name": "定速巡航速度稳态误差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "定速巡航速度稳态误差(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"定速巡航速度稳态误差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Line"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_cruise(self):
+        """
+        获取数据集中第一次巡航速度发生变化的索引。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在巡航速度发生变化的索引,则返回第一个发生变化的索引(int类型);
+            如果不存在,则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_cruise_speed'] != self.df_ica['set_cruise_speed'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_speed_cruise(self, window_size, percent_deviation, set_value):
+        """
+        在给定的速度数据中查找稳定的巡航速度段,并计算该段的平均速度。
+
+        Args:
+            window_size (int): 滑动窗口的大小,表示用于计算平均速度的速度数据点数量。
+            percent_deviation (float): 设定值的允许偏差百分比。
+            set_value (float): 期望的稳定速度设定值。
+
+        Returns:
+            None
+
+        """
+        # speed_data = self.df['speedX'].values
+        speed_data = self.df_ica['speedX'].values  # .tolist()
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_speed = None
+
+        for i in range(len(speed_data) - window_size + 1):
+            window_data = speed_data[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_speed = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(speed_data) - window_size + 1:
+                    next_window_data = speed_data[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_speed = (stable_average_speed * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_speed = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_cruise = self.df['simTime'].iloc[stable_start]
+        self.stable_average_speed = stable_average_speed
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_cruise()
+
+        if not first_change_index:
+            self.steady_error_cruise = 0
+            self.result['value'] = [round(self.steady_error_cruise, 3)]
+            print(f"steady_error_cruise: {self.steady_error_cruise}")
+        else:
+            set_cruise_speed = self.df_ica.loc[first_change_index, 'set_cruise_speed']
+            self._find_stable_speed_cruise(window_size=4, percent_deviation=5, set_value=set_cruise_speed)
+
+            if self.stable_average_speed:
+                self.steady_error_cruise = (self.stable_average_speed - set_cruise_speed) * 100 / self.stable_average_speed
+            else:
+                self.steady_error_cruise = 0
+                raise ValueError("Stable average speed is None.")
+
+            self.result['value'] = [round(self.steady_error_cruise, 3)]
+            print(f"steady_error_cruise: {self.steady_error_cruise}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[steady_error_cruise:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control06_delay_time_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 191 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control06_delay_time_THW.py

@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        # self.stable_start_time_THW = None
+        self.stable_average_THW = None
+        self.delay_time_THW = None
+
+        self.result = {
+            "name": "跟车延迟时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "跟车延迟时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"跟车延迟时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Vehicle"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _find_stable_THW(self, window_size, percent_deviation, set_value):
+        """
+        在给定的数据窗口中查找稳定跟车时距离THW,并计算该段内THW的平均值。
+
+        Args:
+            window_size (int): 窗口大小,表示在数据中寻找稳定段时考虑的连续数据点数量。
+            percent_deviation (float): THW值相对于设定值的允许偏差百分比。
+            set_value (float): THW的设定值。
+
+        Returns:
+            None
+
+        """
+        THW = self.df_ica['THW'].values
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_THW = None
+
+        for i in range(len(THW) - window_size + 1):
+            window_data = THW[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_THW = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(THW) - window_size + 1:
+                    next_window_data = THW[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_THW = (stable_average_THW * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_THW = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_THW = self.df_ica['simTime'].iloc[stable_start]
+        self.stable_average_THW = stable_average_THW
+
+    def data_analyze(self):
+        change_indices = self.df_ica[self.df_ica['set_headway_time'] != self.df_ica['set_headway_time'].shift()].index
+        print(f"Change indices of set speed: {change_indices}")
+
+        set_headway_time = self.df_ica.loc[change_indices[0], 'set_headway_time']
+        self._find_stable_THW(window_size=4, percent_deviation=5, set_value=set_headway_time)
+
+        if not change_indices.empty:
+            first_change_index = change_indices[change_indices != 0].min()
+            set_THW_at_change = self.df_ica.loc[first_change_index, 'set_headway_time']
+            timestamp_at_change = self.df_ica.loc[first_change_index, 'simTime']
+            print(f"Set THW at first change: {set_THW_at_change}, Timestamp: {timestamp_at_change}")
+
+            target_THW = (self.stable_average_THW + self.df_ica.loc[first_change_index, 'set_headway_time']) / 2
+            closest_index = (self.df_ica['set_headway_time'] - target_THW).abs().idxmin()
+            closest_current_THW = self.df_ica.loc[closest_index, 'set_headway_time']
+            closest_timestamp = self.df_ica.loc[closest_index, 'simTime']
+            print(f"Closest speed: {closest_current_THW} at time: {closest_timestamp}")
+
+            self.delay_time_THW = closest_timestamp - timestamp_at_change
+            self.result['value'] = [round(self.delay_time_THW, 3)]
+            print(f"Delay time: {self.delay_time_THW}")
+
+        else:
+            self.delay_time_THW = 0
+            self.result['value'] = [round(self.delay_time_THW, 3)]
+            print("No valid change point for further calculation.")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[delay_time_THW:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control07_rise_time_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 231 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control07_rise_time_THW.py

@@ -0,0 +1,231 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        # self.stable_start_time_THW = None
+        self.stable_average_THW = None
+        self.rise_time_THW = None
+
+        self.result = {
+            "name": "跟车上升时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "跟车上升时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"跟车上升时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Vehicle"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_THW(self):
+        """
+        获取DataFrame中'set_headway_time'列首次发生变化的索引值。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在变化,则返回首次发生变化的索引值(int类型),否则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_headway_time'] != self.df_ica['set_headway_time'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_THW(self, window_size, percent_deviation, set_value):
+        """
+        在给定的数据窗口中查找稳定跟车时距离THW,并计算该段内THW的平均值。
+
+        Args:
+            window_size (int): 窗口大小,表示在数据中寻找稳定段时考虑的连续数据点数量。
+            percent_deviation (float): THW值相对于设定值的允许偏差百分比。
+            set_value (float): THW的设定值。
+
+        Returns:
+            None
+
+        """
+        THW = self.df_ica['THW'].values
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_THW = None
+
+        for i in range(len(THW) - window_size + 1):
+            window_data = THW[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_THW = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(THW) - window_size + 1:
+                    next_window_data = THW[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_THW = (stable_average_THW * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_THW = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_THW = self.df_ica['simTime'].iloc[stable_start]
+        self.stable_average_THW = stable_average_THW
+
+    def _find_closest_time_stamp_THW(self, df, target_THW, start_index):
+        """
+        在DataFrame中找到与目标THW值最接近的时间戳。
+
+        Args:
+            df (pandas.DataFrame): 包含'THW'和'simTime'列的DataFrame,其中'THW'表示目标变量,'simTime'表示时间戳。
+            target_THW (float): 目标THW值。
+            start_index (int): 开始搜索的索引位置(不包含)。
+
+        Returns:
+            pandas.Timestamp: 与目标THW值最接近的时间戳。
+
+        """
+        subset = df.loc[start_index + 1:]
+        THW_diff = np.abs(subset['THW'] - target_THW)
+        closest_index = THW_diff.idxmin()
+        closest_timestamp = subset.loc[closest_index, 'simTime']
+        return closest_timestamp
+
+    def data_analyze(self):
+        """
+        计算巡航时从初THW到达稳定THW的90%的所需时间(rise time)。
+
+        Args:
+            无。
+
+        Returns:
+            无返回值,但会设置实例属性self.rise_time_THW为计算得到的rise time。
+
+        """
+        first_change_index = self._get_first_change_index_THW()
+
+        set_headway_time = self.df_ica.loc[first_change_index, 'set_headway_time']
+        self._find_stable_THW(window_size=4, percent_deviation=5, set_value=set_headway_time)
+
+        initial_THW = self.df_ica.loc[first_change_index, 'THW']
+
+        target_THW_90 = initial_THW + (self.stable_average_THW - initial_THW) * 0.9
+        target_THW_10 = initial_THW + (self.stable_average_THW - initial_THW) * 0.1
+
+        timestamp_at_10 = self._find_closest_time_stamp_THW(self.df_ica, target_THW_10, first_change_index)
+        timestamp_at_90 = self._find_closest_time_stamp_THW(self.df_ica, target_THW_90, first_change_index)
+
+        print(f"Closest speed at 10% range from set speed: {timestamp_at_10}")
+        print(f"Closest speed at 90% range from set speed: {timestamp_at_90}")
+
+        self.rise_time_THW = timestamp_at_90 - timestamp_at_10
+        self.result['value'] = [round(self.rise_time_THW, 3)]
+        print(f"Rise time: {self.rise_time_THW}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[rise_time_THW:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control08_peak_time_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 148 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control08_peak_time_THW.py

@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.peak_time_THW = None
+
+        self.result = {
+            "name": "跟车峰值时间",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "跟车峰值时间(s)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"跟车峰值时间: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Vehicle"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_THW(self):
+        """
+        获取DataFrame中'set_headway_time'列首次发生变化的索引值。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在变化,则返回首次发生变化的索引值(int类型),否则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_headway_time'] != self.df_ica['set_headway_time'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_THW()
+
+        if not first_change_index:
+            self.peak_time_THW = 0
+            self.result['value'] = [round(self.peak_time_THW, 3)]
+            print(f"peak_time_THW: {self.peak_time_THW}")
+        else:
+            start_time = self.df_ica.loc[first_change_index, 'simTime']
+            peak_time = self.df_ica.loc[self.df_ica['THW'].idxmax(), 'simTime']
+            self.peak_time_THW = peak_time - start_time
+            self.result['value'] = [round(self.peak_time_THW, 3)]
+            print(f"peak_time_THW: {self.peak_time_THW}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[peak_time_THW:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control09_overshoot_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 201 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control09_overshoot_THW.py

@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.stable_average_THW = None
+        self.overshoot_THW = None
+
+        self.result = {
+            "name": "跟车超调量",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "跟车超调量(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"跟车超调量: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Vehicle"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_THW(self):
+        """
+        获取DataFrame中'set_headway_time'列首次发生变化的索引值。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在变化,则返回首次发生变化的索引值(int类型),否则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_headway_time'] != self.df_ica['set_headway_time'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_THW(self, window_size, percent_deviation, set_value):
+        """
+        在给定的数据窗口中查找稳定跟车时距离THW,并计算该段内THW的平均值。
+
+        Args:
+            window_size (int): 窗口大小,表示在数据中寻找稳定段时考虑的连续数据点数量。
+            percent_deviation (float): THW值相对于设定值的允许偏差百分比。
+            set_value (float): THW的设定值。
+
+        Returns:
+            None
+
+        """
+        THW = self.df_ica['THW'].values
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_THW = None
+
+        for i in range(len(THW) - window_size + 1):
+            window_data = THW[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_THW = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(THW) - window_size + 1:
+                    next_window_data = THW[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_THW = (stable_average_THW * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_THW = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_THW = self.df_ica['simTime'].iloc[stable_start]
+        self.stable_average_THW = stable_average_THW
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_THW()
+
+        set_headway_time = self.df_ica.loc[first_change_index, 'set_headway_time']
+        self._find_stable_THW(window_size=4, percent_deviation=5, set_value=set_headway_time)
+
+        if not first_change_index:
+            self.overshoot_THW = 0
+        else:
+            initial_THW = self.df_ica.loc[first_change_index, 'THW']
+
+            if initial_THW > self.stable_average_THW:
+                self.overshoot_THW = (self.stable_average_THW - self.df_ica['THW'].min()) * 100 / self.stable_average_THW
+            elif initial_THW < self.stable_average_THW:
+                self.overshoot_THW = (self.df_ica['THW'].max() - self.stable_average_THW) * 100 / self.stable_average_THW
+            else:
+                self.overshoot_THW = 0
+
+        self.result['value'] = [round(self.overshoot_THW, 3)]
+        print(f"overshoot_THW: {self.overshoot_THW}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[overshoot_THW:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control10_steady_error_THW.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "-1",
+      "optimal": "1.0",
+      "multiple": [
+        "0.5",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 201 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control10_steady_error_THW.py

@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.stable_average_THW = None
+        self.steady_error_THW = None
+
+        self.result = {
+            "name": "跟车速度稳态误差",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "跟车速度稳态误差(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"跟车速度稳态误差: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'] == "LLC_Follow_Vehicle"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def _get_first_change_index_THW(self):
+        """
+        获取DataFrame中'set_headway_time'列首次发生变化的索引值。
+
+        Args:
+            无参数。
+
+        Returns:
+            Union[int, None]: 如果存在变化,则返回首次发生变化的索引值(int类型),否则返回None。
+
+        """
+        change_indices = self.df_ica[self.df_ica['set_headway_time'] != self.df_ica['set_headway_time'].shift()].index
+        if not change_indices.empty:
+            first_change_index = change_indices.min()
+        else:
+            first_change_index = None
+        return first_change_index
+
+    def _find_stable_THW(self, window_size, percent_deviation, set_value):
+        """
+        在给定的数据窗口中查找稳定跟车时距离THW,并计算该段内THW的平均值。
+
+        Args:
+            window_size (int): 窗口大小,表示在数据中寻找稳定段时考虑的连续数据点数量。
+            percent_deviation (float): THW值相对于设定值的允许偏差百分比。
+            set_value (float): THW的设定值。
+
+        Returns:
+            None
+
+        """
+        THW = self.df_ica['THW'].values
+        deviation = set_value * (percent_deviation / 100)
+        stable_start = None
+        stable_average_THW = None
+
+        for i in range(len(THW) - window_size + 1):
+            window_data = THW[i:i + window_size]
+
+            if all(set_value - deviation <= s <= set_value + deviation for s in window_data):
+                if stable_start is None:
+                    stable_start = i
+                    stable_end = i + window_size - 1
+                    stable_average_THW = np.mean(window_data)
+
+                j = i + window_size
+                while j < len(THW) - window_size + 1:
+                    next_window_data = THW[j:j + window_size]
+
+                    if all(set_value - deviation <= s <= set_value + deviation for s in next_window_data):
+                        stable_end = j + window_size - 1
+                        stable_average_THW = (stable_average_THW * (j - stable_start) + sum(next_window_data)) / (
+                                j - stable_start + window_size)
+                        j += window_size
+                    else:
+                        stable_start = j + window_size - 1
+                        stable_end = i + window_size - 1
+                        stable_average_THW = np.mean(window_data)
+                        break
+
+        # self.stable_start_time_THW = self.df_ica['simTime'].iloc[stable_start]
+        self.stable_average_THW = stable_average_THW
+
+    def data_analyze(self):
+        first_change_index = self._get_first_change_index_THW()
+
+
+        if not first_change_index:
+            self.steady_error_THW = 0
+            self.result['value'] = [round(self.steady_error_THW, 3)]
+            print(f"steady_error_THW: {self.steady_error_THW}")
+        else:
+            set_headway_time = self.df_ica.loc[first_change_index, 'set_headway_time']
+            self._find_stable_THW(window_size=4, percent_deviation=5, set_value=set_headway_time)
+
+            if self.stable_average_THW:
+                self.steady_error_THW = (self.stable_average_THW - set_headway_time) * 100 / self.stable_average_THW
+            else:
+                self.steady_error_THW = 0
+                raise ValueError("Stable average speed is None.")
+
+            self.result['value'] = [round(self.steady_error_THW, 3)]
+            print(f"steady_error_THW: {self.steady_error_THW}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        # time_list = self.ego_df['simTime'].values.tolist()
+        # graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = self.result['value'][0] if not self.df_ica.empty else '-'
+        self.result['tableData']['max'] = '-'
+        self.result['tableData']['min'] = '-'
+
+        # zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = []
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 1.2]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[steady_error_THW:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control11_reasonable_acceleration_percentage.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "1",
+      "optimal": "100",
+      "multiple": [
+        "0.6",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 129 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control11_reasonable_acceleration_percentage.py

@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.percentage_accel = 0
+
+        self.result = {
+            "name": "合理加减速度占比",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "合理加减速度占比(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"合理加减速度占比: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def data_analyze(self):
+        col_list = ['simTime', 'simFrame', 'playerId', 'v', 'accel', 'lon_acc_roc']  # target_id
+        df = self.df_ica[col_list].copy()
+        count_accel_in_range = 0
+        total_accel_frames = 0
+
+        self.graph_list = df['accel'].values.tolist()
+        filtered_data = df[(df['accel'] >= -5) & (df['accel'] <= 4)]
+        count_accel_in_range = count_accel_in_range + len(filtered_data)
+        total_accel_frames = total_accel_frames + len(df)
+        self.percentage_accel = (count_accel_in_range / total_accel_frames) * 100
+
+        self.result['value'] = [round(self.percentage_accel, 3)]
+        print(f"percentage_accel: {self.percentage_accel}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 100]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[percentage_accel:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 21 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control12_reasonable_acceleration_change_rate_percentage.json

@@ -0,0 +1,21 @@
+{
+  "priority": "1",
+  "paramList": [
+    {
+      "kind": "1",
+      "optimal": "100",
+      "multiple": [
+        "0.6",
+        "2"
+      ],
+      "spare": [
+        {
+          "param": null
+        },
+        {
+          "param": null
+        }
+      ]
+    }
+  ]
+}

+ 133 - 0
custom/voyah/0926/ICA/cicv_ica_longitudinal_control12_reasonable_acceleration_change_rate_percentage.py

@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##################################################################
+#
+# Copyright (c) 2023 CICV, Inc. All Rights Reserved
+#
+##################################################################
+"""
+@Authors:           zhanghaiwen, yangzihao
+@Data:              2024/02/21
+@Last Modified:     2024/02/21
+@Summary:           The template of custom indicator.
+"""
+
+"""
+设计思路:
+
+"""
+
+import math
+import pandas as pd
+import numpy as np
+from common import zip_time_pairs, continuous_group
+from log import logger
+
+"""import functions"""
+
+
+# custom metric codes
+class CustomMetric(object):
+    def __init__(self, all_data, case_name):
+        self.data = all_data
+        self.optimal_dict = self.data.config
+        self.case_name = case_name
+        self.markline_df = pd.DataFrame(columns=['start_time', 'end_time', 'start_frame', 'end_frame', 'type'])
+        self.graph_list = []
+
+        self.df = pd.DataFrame()
+        self.ego_df = pd.DataFrame()
+        self.df_ica = pd.DataFrame()
+
+        self.percentage_lon_acc_roc = 0
+
+        self.result = {
+            "name": "合理加减速度变化率占比",
+            "value": [],
+            # "weight": [],
+            "tableData": {
+                "avg": "",  # 平均值,或指标值
+                "max": "",
+                "min": ""
+            },
+            "reportData": {
+                "name": "合理加减速度变化率占比(%)",
+                # "legend": [], # 如果有多个data,则需要增加data对应的说明,如:["横向加速度", "纵向加速度"]
+                "data": [],
+                "markLine": [],
+                "range": [],
+            },
+            "statusFlag": {}
+        }
+        self.run()
+        print(f"合理加减速度变化率占比: {self.result['value']}")
+
+    def data_extract(self):
+        self.df = self.data.object_df
+        self.ego_df = self.data.ego_data
+        active_status_list = ["LLC_Follow_Line", "LLC_Follow_Vehicle", "Only_Longitudinal_Control"]
+        self.df_ica = self.ego_df[self.ego_df['ICA_status'].isin(active_status_list)].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Shut_off"].copy()  # 数字3对应ICA的Active
+        # self.df_ica = self.df[self.df['ACC_status'] == "Active"].copy()  # 数字3对应ICA的Active
+
+        if self.df_ica.empty:
+            self.result['statusFlag']['function_ICA'] = False
+        else:
+            self.result['statusFlag']['function_ICA'] = True
+
+    def data_analyze(self):
+        col_list = ['simTime', 'simFrame', 'playerId', 'v', 'accel', 'lon_acc_roc']  # target_id
+        df = self.df_ica[col_list].copy()
+
+        count_lon_acc_roc_in_range = 0
+        total_lon_acc_roc_frames = 0
+
+        self.graph_list = df['lon_acc_roc'].values.tolist()
+        filtered_data = df[(df['lon_acc_roc'] >= -5) & (df['lon_acc_roc'] <= 6)]
+        count_lon_acc_roc_in_range = count_lon_acc_roc_in_range + len(filtered_data)
+        total_lon_acc_roc_frames = total_lon_acc_roc_frames + len(df)
+        self.percentage_lon_acc_roc = (count_lon_acc_roc_in_range / total_lon_acc_roc_frames) * 100
+
+        self.result['value'] = [round(self.percentage_lon_acc_roc, 3)]
+        print(f"percentage_lon_acc_roc: {self.percentage_lon_acc_roc}")
+
+    def markline_statistic(self):
+        pass
+
+    def report_data_statistic(self):
+        time_list = self.ego_df['simTime'].values.tolist()
+        graph_list = [x for x in self.graph_list if not np.isnan(x)]
+        self.result['tableData']['avg'] = f'{np.mean(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['max'] = f'{max(graph_list):.2f}' if graph_list else 0
+        self.result['tableData']['min'] = f'{min(graph_list):.2f}' if graph_list else 0
+
+        zip_vs_time = zip_time_pairs(time_list, self.graph_list)
+        self.result['reportData']['data'] = zip_vs_time
+
+        # self.markline_statistic()
+        # markline_slices = self.markline_df.to_dict('records')
+        self.result['reportData']['markLine'] = []
+
+        self.result['reportData']['range'] = [0, 100]
+
+    def run(self):
+        # logger.info(f"Custom metric run:[{self.result['name']}].")
+        logger.info(f"[case:{self.case_name}] Custom metric:[percentage_lon_acc_roc:{self.result['name']}] evaluate.")
+
+        try:
+            self.data_extract()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data extract ERROR!", e)
+
+        try:
+            self.data_analyze()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} data analyze ERROR!", e)
+
+        try:
+            self.report_data_statistic()
+        except Exception as e:
+            logger.error(f"[case:{self.case_name}] Custom metric:{self.result['name']} report data statistic ERROR!", e)
+
+# if __name__ == "__main__":
+#     pass

+ 0 - 0
custom/voyah/LKA/cicv_LKA_01_distance_nearby_lane.json → custom/voyah/0926/LKA/cicv_LKA_01_distance_nearby_lane.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_01_distance_nearby_lane.py → custom/voyah/0926/LKA/cicv_LKA_01_distance_nearby_lane.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_02_lateral_offset.json → custom/voyah/0926/LKA/cicv_LKA_02_lateral_offset.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_02_lateral_offset.py → custom/voyah/0926/LKA/cicv_LKA_02_lateral_offset.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_03_heading_deviation_max.json → custom/voyah/0926/LKA/cicv_LKA_03_heading_deviation_max.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_03_heading_deviation_max.py → custom/voyah/0926/LKA/cicv_LKA_03_heading_deviation_max.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_04_relative_position_oscillation_frequency.json → custom/voyah/0926/LKA/cicv_LKA_04_relative_position_oscillation_frequency.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_04_relative_position_oscillation_frequency.py → custom/voyah/0926/LKA/cicv_LKA_04_relative_position_oscillation_frequency.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_05_relative_position_oscillation_difference.json → custom/voyah/0926/LKA/cicv_LKA_05_relative_position_oscillation_difference.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_05_relative_position_oscillation_difference.py → custom/voyah/0926/LKA/cicv_LKA_05_relative_position_oscillation_difference.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_06_absolute_center_distance_expectation.json → custom/voyah/0926/LKA/cicv_LKA_06_absolute_center_distance_expectation.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_06_absolute_center_distance_expectation.py → custom/voyah/0926/LKA/cicv_LKA_06_absolute_center_distance_expectation.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_07_absolute_center_distance_standard_deviation.json → custom/voyah/0926/LKA/cicv_LKA_07_absolute_center_distance_standard_deviation.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_07_absolute_center_distance_standard_deviation.py → custom/voyah/0926/LKA/cicv_LKA_07_absolute_center_distance_standard_deviation.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_08_fixed_driving_direction_TLC.json → custom/voyah/0926/LKA/cicv_LKA_08_fixed_driving_direction_TLC.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_08_fixed_driving_direction_TLC.py → custom/voyah/0926/LKA/cicv_LKA_08_fixed_driving_direction_TLC.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_09_fixed_steering_wheel_angle_TLC.json → custom/voyah/0926/LKA/cicv_LKA_09_fixed_steering_wheel_angle_TLC.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_09_fixed_steering_wheel_angle_TLC.py → custom/voyah/0926/LKA/cicv_LKA_09_fixed_steering_wheel_angle_TLC.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_10_maximum_lateral_deviation.json → custom/voyah/0926/LKA/cicv_LKA_10_maximum_lateral_deviation.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_10_maximum_lateral_deviation.py → custom/voyah/0926/LKA/cicv_LKA_10_maximum_lateral_deviation.py


+ 0 - 0
custom/voyah/LKA/cicv_LKA_11_minimum_lateral_deviation.json → custom/voyah/0926/LKA/cicv_LKA_11_minimum_lateral_deviation.json


+ 0 - 0
custom/voyah/LKA/cicv_LKA_11_minimum_lateral_deviation.py → custom/voyah/0926/LKA/cicv_LKA_11_minimum_lateral_deviation.py


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