Euro NCAP 2026 驾驶员参与度评分详解:25分完整计算与实现指南

Euro NCAP 2026 驾驶员参与度评分详解:25分完整计算与实现指南

背景

Euro NCAP 2026 将驾驶员监测从辅助功能提升为独立评分类别——驾驶员参与度(Driver Engagement),总分 25 分。本文详细解读评分规则和实现方法。


评分体系总览

25 分构成

1
2
3
4
5
6
7
8
9
10
驾驶员参与度 (25分)
├── 驾驶员监测 (25分)
│ ├── 瞬态状态 (15分)
│ │ ├── 长时分心 (5分)
│ │ ├── 短时分心 (5分)
│ │ └── 手机使用 (5分)
│ └── 非瞬态状态 (10分)
│ ├── 疲劳 (5分)
│ ├── 损伤 (3分)
│ └── 无响应 (2分)

瞬态状态评分详解

1. 长时分心检测(5分)

定义: 单次视线偏离道路 3-4 秒。

检测要求:

参数 要求
偏离时间 3-4 秒
前置条件 先注视道路 4 秒
检测区域 侧窗、脚坑、乘客、中控、手套箱、后视镜
运动分类 Owl(头部)/ Lizard(眼部)/ Body Lean(身体)

评分细则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class LongDistractionScoring:
"""长时分心评分计算"""

def __init__(self):
# 检测要求
self.min_distraction_duration = 3.0 # 秒
self.max_distraction_duration = 4.0
self.required_onroad_gaze = 4.0 # 前置道路注视

# 测试场景
self.test_scenarios = [
'LD-01': {'zone': 'driver_window', 'movement': 'owl'},
'LD-02': {'zone': 'passenger_window', 'movement': 'owl'},
'LD-03': {'zone': 'footwell', 'movement': 'lizard'},
'LD-04': {'zone': 'infotainment', 'movement': 'lizard'},
'LD-05': {'zone': 'mirror', 'movement': 'lizard'}
]

def calculate_score(
self,
test_results: dict
) -> dict:
"""
计算长时分心得分

Args:
test_results: 测试结果 {
'LD-01': {'detected': True, 'time': 3.2},
...
}

Returns:
score: 得分详情
"""
total_scenarios = len(self.test_scenarios)
passed = 0

for scenario_id, result in test_results.items():
if result['detected'] and result['time'] <= self.max_distraction_duration:
passed += 1

# 线性评分
score = (passed / total_scenarios) * 5.0

return {
'score': score,
'max_score': 5.0,
'passed_scenarios': passed,
'total_scenarios': total_scenarios
}

2. 短时分心(VATS)检测(5分)

定义: 30 秒窗口内累计视线偏离 ≥10 秒。

检测逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class VATSScoring:
"""短时分心(VATS)评分"""

def __init__(self):
self.window_sec = 30.0
self.accumulated_threshold = 10.0 # 累计偏离秒数

def detect_vats(
self,
gaze_history: List[dict]
) -> dict:
"""
检测 VATS

Args:
gaze_history: 视线历史 [{timestamp, zone}, ...]

Returns:
result: 检测结果
"""
if len(gaze_history) < 10:
return {'detected': False}

# 按时间窗口分析
current_time = gaze_history[-1]['timestamp']
window_start = current_time - self.window_sec

# 计算累计偏离时间
offroad_time = 0.0
for event in gaze_history:
if event['timestamp'] >= window_start:
if event['zone'] != 'road_forward':
# 假设每个事件持续 100ms
offroad_time += 0.1

# 判断
detected = offroad_time >= self.accumulated_threshold

return {
'detected': detected,
'accumulated_offroad_sec': offroad_time,
'threshold': self.accumulated_threshold,
'window_sec': self.window_sec
}

def calculate_score(
self,
test_results: dict
) -> dict:
"""计算 VATS 得分"""

# 测试场景
scenarios = {
'VATS-01': 'accumulated_gaze_offroad',
'VATS-02': 'repeated_brief_glances',
'VATS-03': 'mixed_gaze_patterns'
}

passed = sum(1 for r in test_results.values() if r['detected'])
score = (passed / len(scenarios)) * 5.0

return {
'score': score,
'max_score': 5.0,
'passed': passed,
'total': len(scenarios)
}

3. 手机使用检测(5分)

检测场景矩阵:

手机使用类型 运动分类 检测位置 分值
基础使用 Owl 膝盖、大腿、仪表盘 1.5分
基础使用 Lizard 膝盖、大腿、方向盘下方 1.5分
高级使用 Lizard 仪表盘、方向盘上方、挡风玻璃 2分

评分实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class PhoneUseScoring:
"""手机使用评分"""

def __init__(self):
self.use_types = {
'basic_owl': {
'positions': ['knee_outboard', 'knee_inboard', 'lap', 'dashboard_mount'],
'score_weight': 0.3
},
'basic_lizard': {
'positions': ['knee_outboard', 'knee_inboard', 'lap', 'wheel_center_below'],
'score_weight': 0.3
},
'advanced_lizard': {
'positions': ['dashboard_mount', 'wheel_9_11', 'wheel_1_3', 'windshield_view'],
'score_weight': 0.4
}
}

def calculate_score(
self,
detection_results: dict
) -> dict:
"""
计算手机使用得分

Args:
detection_results: {
'basic_owl': {'positions_detected': 4, 'accuracy': 0.95},
'basic_lizard': {'positions_detected': 3, 'accuracy': 0.90},
'advanced_lizard': {'positions_detected': 2, 'accuracy': 0.85}
}

Returns:
score: 得分
"""
total_score = 0.0

for use_type, result in detection_results.items():
config = self.use_types[use_type]

# 计算该类型的得分
positions_ratio = result['positions_detected'] / len(config['positions'])
type_score = positions_ratio * result['accuracy'] * 5.0 * config['score_weight']

total_score += type_score

return {
'score': total_score,
'max_score': 5.0,
'breakdown': detection_results
}

非瞬态状态评分详解

1. 疲劳检测(5分)

检测标准:

  • KSS(Karolinska Sleepiness Scale)≥7
  • PERCLOS ≥15%
  • 或等效指标

评分细则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class DrowsinessScoring:
"""疲劳检测评分"""

def __init__(self):
# 检测阈值
self.kss_threshold = 7
self.perclos_threshold = 0.15

# 测试场景
self.test_conditions = {
'D-01': {'type': 'mild_drowsiness', 'kss': 6},
'D-02': {'type': 'moderate_drowsiness', 'kss': 7},
'D-03': {'type': 'severe_drowsiness', 'kss': 8},
'D-04': {'type': 'microsleep', 'duration_sec': 1.5},
'D-05': {'type': 'sleep', 'duration_sec': 3.0}
}

def calculate_score(
self,
test_results: dict
) -> dict:
"""计算疲劳检测得分"""

# 必须检测的场景
required_pass = ['D-02', 'D-03', 'D-04', 'D-05']

passed_required = all(
test_results.get(s, {}).get('detected', False)
for s in required_pass
)

if not passed_required:
return {
'score': 0.0,
'reason': 'Failed required scenarios'
}

# 计算完整得分
total = len(self.test_conditions)
passed = sum(1 for r in test_results.values() if r.get('detected', False))

score = (passed / total) * 5.0

return {
'score': score,
'max_score': 5.0,
'passed': passed,
'total': total
}

2. 损伤检测(3分)

检测要求:

  • 速度 ≥50km/h 时激活
  • 行程前 10 分钟内开始检测
  • 区分疲劳与酒精/药物损伤

评分计算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class ImpairmentScoring:
"""损伤检测评分"""

def __init__(self):
self.activation_speed = 50 # km/h
self.detection_window = 600 # 秒(10分钟)

def calculate_score(
self,
test_results: dict
) -> dict:
"""
计算损伤检测得分

测试场景:
- 酒精损伤模拟
- 药物损伤模拟
- 与疲劳的区分能力
"""

scenarios = {
'I-01': 'alcohol_impairment',
'I-02': 'drug_impairment',
'I-03': 'fatigue_vs_impairment_distinction',
'I-04': 'early_detection_within_10min'
}

passed = sum(1 for s in scenarios if test_results.get(s, {}).get('detected', False))
score = (passed / len(scenarios)) * 3.0

return {
'score': score,
'max_score': 3.0,
'passed': passed,
'total': len(scenarios)
}

3. 无响应驾驶员检测(2分)

定义:

  • 视线未在警告后 3 秒内返回道路
  • 或眼部持续闭合 ≥6 秒

评分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class UnresponsiveDriverScoring:
"""无响应驾驶员评分"""

def __init__(self):
self.gaze_return_timeout = 3.0 # 秒
self.eye_closure_sleep = 3.0 # 秒(微睡眠)
self.eye_closure_unresponsive = 6.0 # 秒

def calculate_score(
self,
test_results: dict
) -> dict:
"""计算得分"""

scenarios = {
'UD-01': 'no_response_to_warning',
'UD-02': 'continued_eye_closure',
'UD-03': 'emergency_stop_activation'
}

passed = sum(1 for s in scenarios if test_results.get(s, {}).get('passed', False))
score = (passed / len(scenarios)) * 2.0

return {
'score': score,
'max_score': 2.0,
'passed': passed,
'total': len(scenarios)
}

完整评分计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
class DriverEngagementScoring:
"""
Euro NCAP 2026 驾驶员参与度完整评分

总分:25分
"""

def __init__(self):
# 初始化各子评分器
self.long_distraction = LongDistractionScoring()
self.vats = VATSScoring()
self.phone_use = PhoneUseScoring()
self.drowsiness = DrowsinessScoring()
self.impairment = ImpairmentScoring()
self.unresponsive = UnresponsiveDriverScoring()

def calculate_total_score(
self,
all_test_results: dict
) -> dict:
"""
计算总得分

Args:
all_test_results: {
'long_distraction': {...},
'vats': {...},
'phone_use': {...},
'drowsiness': {...},
'impairment': {...},
'unresponsive': {...}
}

Returns:
total: 总得分详情
"""
# 计算各项得分
scores = {
'long_distraction': self.long_distraction.calculate_score(
all_test_results.get('long_distraction', {})
),
'vats': self.vats.calculate_score(
all_test_results.get('vats', {})
),
'phone_use': self.phone_use.calculate_score(
all_test_results.get('phone_use', {})
),
'drowsiness': self.drowsiness.calculate_score(
all_test_results.get('drowsiness', {})
),
'impairment': self.impairment.calculate_score(
all_test_results.get('impairment', {})
),
'unresponsive': self.unresponsive.calculate_score(
all_test_results.get('unresponsive', {})
)
}

# 计算总分
total_score = sum(s['score'] for s in scores.values())

# 判断星级
star_rating = self._determine_star_rating(total_score)

return {
'total_score': total_score,
'max_score': 25.0,
'percentage': (total_score / 25.0) * 100,
'star_rating': star_rating,
'breakdown': scores
}

def _determine_star_rating(self, total_score: float) -> int:
"""确定星级"""

percentage = (total_score / 25.0) * 100

# Euro NCAP 星级标准(简化)
if percentage >= 80:
return 5
elif percentage >= 70:
return 4
elif percentage >= 60:
return 3
elif percentage >= 50:
return 2
else:
return 1


# 测试示例
if __name__ == "__main__":
scorer = DriverEngagementScoring()

# 模拟测试结果
test_results = {
'long_distraction': {
'LD-01': {'detected': True, 'time': 3.2},
'LD-02': {'detected': True, 'time': 3.5},
'LD-03': {'detected': True, 'time': 3.8},
'LD-04': {'detected': True, 'time': 3.1},
'LD-05': {'detected': True, 'time': 3.6}
},
'vats': {
'VATS-01': {'detected': True},
'VATS-02': {'detected': True},
'VATS-03': {'detected': True}
},
'phone_use': {
'basic_owl': {'positions_detected': 4, 'accuracy': 0.95},
'basic_lizard': {'positions_detected': 4, 'accuracy': 0.92},
'advanced_lizard': {'positions_detected': 4, 'accuracy': 0.88}
},
'drowsiness': {
'D-01': {'detected': True},
'D-02': {'detected': True},
'D-03': {'detected': True},
'D-04': {'detected': True},
'D-05': {'detected': True}
},
'impairment': {
'I-01': {'detected': True},
'I-02': {'detected': True},
'I-03': {'detected': True},
'I-04': {'detected': True}
},
'unresponsive': {
'UD-01': {'passed': True},
'UD-02': {'passed': True},
'UD-03': {'passed': True}
}
}

result = scorer.calculate_total_score(test_results)

print(f"总得分: {result['total_score']:.1f} / {result['max_score']}")
print(f"百分比: {result['percentage']:.1f}%")
print(f"星级: {result['star_rating']} 星")

print("\n各项目得分:")
for item, score in result['breakdown'].items():
print(f" {item}: {score['score']:.1f} / {score['max_score']}")

Euro NCAP 测试场景清单

瞬态状态测试

场景ID 描述 通过条件
LD-01 看驾驶员侧窗 3.5秒 ≤4秒检测
LD-02 看乘客侧窗 3.5秒 ≤4秒检测
LD-03 看脚坑 3.5秒 ≤4秒检测
LD-04 看中控 3.5秒 ≤4秒检测
VATS-01 30秒内累计偏离 12秒 检测并警告
PU-01 手机放在大腿 检测手机使用
PU-02 手机放在方向盘上方 检测高级使用

非瞬态状态测试

场景ID 描述 通过条件
D-01 轻度疲劳(KSS=6) 可选检测
D-02 中度疲劳(KSS=7) 必须检测
D-03 重度疲劳(KSS=8) 必须检测
D-04 微睡眠 1.5秒 必须检测
D-05 睡眠 ≥3秒 必须检测
I-01 酒精损伤模拟 检测并区分疲劳
I-02 药物损伤模拟 检测并区分疲劳
UD-01 警告后无响应 3秒 触发紧急程序
UD-02 持续闭眼 ≥6秒 触发紧急停车

参考文献

  1. Euro NCAP, “Safe Driving Driver Engagement Protocol v1.1”, 2025
  2. Smart Eye, “Driver Monitoring 2.0: How Euro NCAP is Raising the Bar in 2026”, 2025
  3. ETSC, “Euro NCAP: New 2026 protocols target distraction, impairment, and speeding”, 2026

总结: Euro NCAP 2026 驾驶员参与度共 25 分,其中瞬态状态(分心)15 分,非瞬态状态(疲劳/损伤/无响应)10 分。建议优先实现长时分心、手机使用、疲劳检测,确保核心场景通过后再逐步覆盖损伤和无响应检测。


Euro NCAP 2026 驾驶员参与度评分详解:25分完整计算与实现指南
https://dapalm.com/2026/06/04/2026-06-04-Euro-NCAP-2026驾驶员参与度评分详解25分完整计算与实现指南/
作者
Mars
发布于
2026年6月4日
许可协议