Euro NCAP 2026 乘员监测与自适应约束系统:完整技术指南

Euro NCAP 2026 乘员监测与自适应约束系统:完整技术指南

法规背景

Euro NCAP 2026 对乘员监测提出全新要求,从传统的”检测是否有乘员”升级为”检测乘员特征并自适应调整约束系统”。

核心变化:

  • 乘员身材分类成为强制要求
  • 异常姿态(OOP)检测强制化
  • 安全气囊自动管理
  • 约束系统自适应调整

乘员身材分类要求

Euro NCAP 2026 分类标准

分类 身高范围 体重范围 CDC 生长曲线
5th 百分位 <155cm (女) <50kg 5th percentile
50th 百分位 160-175cm 60-80kg 50th percentile
95th 百分位 >180cm >90kg 95th percentile

评分要求:

  • 驾驶员位置:3分
  • 副驾位置:1分
  • 必须定义至少 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
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
import numpy as np
from dataclasses import dataclass
from typing import Tuple, Optional
import torch
import torch.nn as nn

@dataclass
class OccupantMetrics:
"""乘员测量指标"""
estimated_height_cm: float
estimated_weight_kg: float
shoulder_width_cm: float
hip_width_cm: float
head_position: Tuple[float, float, float] # (x, y, z)
confidence: float


class StatureClassifier(nn.Module):
"""
乘员身材分类器

基于 3D 深度信息估计身高和体重
"""

def __init__(self, input_channels: int = 1):
super().__init__()

# 3D 深度图编码器
self.depth_encoder = nn.Sequential(
nn.Conv2d(input_channels, 32, 5, stride=2, padding=2),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.Conv2d(32, 64, 3, stride=2, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.Conv2d(64, 128, 3, stride=2, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.AdaptiveAvgPool2d((8, 8))
)

# 身高回归头
self.height_regressor = nn.Sequential(
nn.Linear(128 * 8 * 8, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 1),
nn.ReLU() # 身高 > 0
)

# 体重回归头
self.weight_regressor = nn.Sequential(
nn.Linear(128 * 8 * 8, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 1),
nn.ReLU() # 体重 > 0
)

# 身材分类头
self.stature_classifier = nn.Sequential(
nn.Linear(2, 64), # [height, weight]
nn.ReLU(),
nn.Linear(64, 3) # 5th, 50th, 95th
)

def forward(self, depth_map: torch.Tensor) -> dict:
"""
前向传播

Args:
depth_map: 深度图, shape=(B, 1, H, W)

Returns:
height: 估计身高 (cm)
weight: 估计体重 (kg)
stature_class: 身材分类 (0=5th, 1=50th, 2=95th)
"""
# 编码
features = self.depth_encoder(depth_map)
features = features.view(features.size(0), -1)

# 回归
height = self.height_regressor(features)
weight = self.weight_regressor(features)

# 分类
hw_features = torch.cat([height, weight], dim=1)
stature_logits = self.stature_classifier(hw_features)

return {
'height_cm': height.squeeze(-1),
'weight_kg': weight.squeeze(-1),
'stature_logits': stature_logits
}


class OccupantClassificationSystem:
"""
乘员分类系统

整合多种传感器数据进行分类
"""

def __init__(self):
self.stature_classifier = StatureClassifier()
self.stature_classifier.eval()

# 座椅传感器阈值
self.seat_pressure_thresholds = {
'empty': 5.0, # kg
'child': 30.0, # kg
'adult': 50.0 # kg
}

def classify(
self,
depth_map: np.ndarray,
seat_pressure: float,
seat_track_position: int,
seat_back_angle: float
) -> dict:
"""
综合分类

Args:
depth_map: 深度图
seat_pressure: 座椅压力传感器读数 (kg)
seat_track_position: 座椅滑轨位置 (0-100)
seat_back_angle: 靠背角度 (度)

Returns:
classification: {
'stature_class': str,
'estimated_height': float,
'estimated_weight': float,
'airbag_strategy': str,
'restraint_strategy': dict
}
"""
# 深度图推理
depth_tensor = torch.tensor(depth_map).float().unsqueeze(0).unsqueeze(0)

with torch.no_grad():
outputs = self.stature_classifier(depth_tensor)
estimated_height = outputs['height_cm'].item()
estimated_weight = outputs['weight_kg'].item()
stature_class = torch.argmax(outputs['stature_logits'], dim=1).item()

# 结合座椅压力校正
if seat_pressure > 0:
# 压力传感器更可靠,用于校正
weight_correction_factor = seat_pressure / max(estimated_weight, 30)
if 0.8 < weight_correction_factor < 1.2:
# 两者一致
pass
else:
# 使用压力传感器值
estimated_weight = seat_pressure

# 身材分类映射
class_map = {
0: '5th_percentile',
1: '50th_percentile',
2: '95th_percentile'
}

stature_name = class_map[stature_class]

# 确定约束策略
airbag_strategy = self._get_airbag_strategy(
stature_name, seat_track_position, seat_back_angle
)

restraint_strategy = self._get_restraint_strategy(
stature_name, estimated_height, estimated_weight
)

return {
'stature_class': stature_name,
'estimated_height_cm': estimated_height,
'estimated_weight_kg': estimated_weight,
'airbag_strategy': airbag_strategy,
'restraint_strategy': restraint_strategy,
'confidence': 0.85 # 示例
}

def _get_airbag_strategy(
self,
stature_class: str,
seat_position: int,
back_angle: float
) -> str:
"""确定安全气囊策略"""

# 5th 百分位可能需要低功率展开
if stature_class == '5th_percentile':
if seat_position < 30: # 座椅靠前
return 'low_power'
return 'standard'

# 50th 百分位标准策略
if stature_class == '50th_percentile':
return 'standard'

# 95th 百分位可能需要高功率
if stature_class == '95th_percentile':
return 'high_power'

return 'standard'

def _get_restraint_strategy(
self,
stature_class: str,
height: float,
weight: float
) -> dict:
"""确定约束系统策略"""

# 预紧器力度
pretensioner_force = 'standard'
if weight < 55:
pretensioner_force = 'low'
elif weight > 85:
pretensioner_force = 'high'

# 负载限制器
load_limiter = 'standard'
if stature_class == '5th_percentile':
load_limiter = 'reduced'
elif stature_class == '95th_percentile':
load_limiter = 'increased'

return {
'pretensioner_force': pretensioner_force,
'load_limiter_level': load_limiter,
'airbag_deployment_level': self._get_airbag_strategy(stature_class, 50, 25)
}

异常姿态(OOP)检测

Euro NCAP 2026 OOP 检测要求

OOP 类型 描述 检测要求 警告时限
脚踩仪表盘 单脚或双脚放在仪表盘上 3种姿态(内侧/中线/外侧) ≤30秒
身体前倾 头部距仪表盘 <20cm 持续检测 ≤30秒
斜靠车门 身体倾斜靠车门 持续检测 ≤30秒

OOP 检测实现

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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
from enum import Enum
from typing import List, Tuple

class OOPType(Enum):
"""异常姿态类型"""
FEET_ON_DASHBOARD_INBOARD = 'feet_inboard'
FEET_ON_DASHBOARD_CENTER = 'feet_center'
FEET_ON_DASHBOARD_OUTBOARD = 'feet_outboard'
HEAD_CLOSE_TO_FASCIA = 'head_close'
LEANING_ON_DOOR = 'lean_door'
RECLINED_EXCESSIVELY = 'reclined'
NORMAL = 'normal'


class OOPDetector(nn.Module):
"""
异常姿态检测器

基于人体关键点检测 OOP 状态
"""

def __init__(self, num_keypoints: int = 17):
super().__init__()

# 关键点编码器
self.keypoint_encoder = nn.Sequential(
nn.Linear(num_keypoints * 3, 128), # (x, y, conf) for each keypoint
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(128, 64)
)

# OOP 分类器
self.oop_classifier = nn.Sequential(
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, len(OOPType))
)

# 头部距离回归器
self.head_distance_regressor = nn.Sequential(
nn.Linear(64, 16),
nn.ReLU(),
nn.Linear(16, 1)
)

def forward(self, keypoints: torch.Tensor) -> dict:
"""
前向传播

Args:
keypoints: 人体关键点, shape=(B, 17, 3)

Returns:
oop_class: OOP 类型
head_distance: 头部距仪表盘距离 (cm)
"""
# 编码
keypoints_flat = keypoints.view(keypoints.size(0), -1)
features = self.keypoint_encoder(keypoints_flat)

# 分类
oop_logits = self.oop_classifier(features)

# 头部距离
head_distance = self.head_distance_regressor(features)

return {
'oop_logits': oop_logits,
'head_distance_cm': head_distance.squeeze(-1)
}


class OOPWarningSystem:
"""
OOP 警告系统

实现持续监测和警告升级
"""

def __init__(self):
self.warning_interval = 900 # 15分钟 = 900秒
self.last_warning_time = {}
self.oop_history = []

def detect_and_warn(
self,
oop_detector: OOPDetector,
keypoints: np.ndarray,
current_time: float,
passenger_id: str = 'front_passenger'
) -> dict:
"""
检测并触发警告

Returns:
warning: {
'required': bool,
'type': str,
'visual': bool,
'audible': bool
}
"""
# 推理
keypoints_tensor = torch.tensor(keypoints).float().unsqueeze(0)

with torch.no_grad():
outputs = oop_detector(keypoints_tensor)
oop_class = torch.argmax(outputs['oop_logits'], dim=1).item()
head_distance = outputs['head_distance_cm'].item()

oop_type = list(OOPType)[oop_class]

# 判断是否需要警告
if oop_type == OOPType.NORMAL:
return {'required': False}

# 检查警告间隔
last_warn = self.last_warning_time.get(passenger_id, 0)
time_since_last = current_time - last_warn

# 30秒内首次警告,之后每15分钟重复
should_warn = False
if time_since_last < 30:
# 首次检测到 OOP
should_warn = True
elif time_since_last >= self.warning_interval:
# 重复警告
should_warn = True

if should_warn:
self.last_warning_time[passenger_id] = current_time

return {
'required': True,
'type': oop_type.value,
'visual': True,
'audible': True,
'message': self._get_warning_message(oop_type),
'head_distance_cm': head_distance
}

return {'required': False}

def _get_warning_message(self, oop_type: OOPType) -> str:
"""获取警告信息"""
messages = {
OOPType.FEET_ON_DASHBOARD_INBOARD:
"Please put your feet down from the dashboard",
OOPType.FEET_ON_DASHBOARD_CENTER:
"Please put your feet down from the dashboard",
OOPType.FEET_ON_DASHBOARD_OUTBOARD:
"Please put your feet down from the dashboard",
OOPType.HEAD_CLOSE_TO_FASCIA:
"Please move back from the dashboard",
OOPType.LEANING_ON_DOOR:
"Please sit upright",
OOPType.RECLINED_EXCESSIVELY:
"Please adjust your seat back to an upright position"
}
return messages.get(oop_type, "Please adjust your seating position")

安全气囊自动管理

Euro NCAP 2026 气囊管理要求

场景 气囊状态 检测要求
后向儿童座椅 OFF 自动检测并禁用
5th 百分位成人 ON 自动启用
空座 OFF 可选禁用
冲突状态 警告 气囊状态与乘员冲突时警告

自动管理实现

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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
class AirbagManagementSystem:
"""
安全气囊自动管理系统

符合 Euro NCAP 2026 要求
"""

def __init__(self):
# 气囊状态
self.airbag_status = 'ON' # 默认开启

# 儿童座椅检测器
self.crs_detector = CRSDetector()

# 乘员分类器
self.occupant_classifier = OccupantClassificationSystem()

def update_airbag_status(
self,
depth_map: np.ndarray,
seat_pressure: float,
crs_detected: bool,
manual_override: Optional[str] = None
) -> dict:
"""
更新安全气囊状态

Args:
depth_map: 深度图
seat_pressure: 座椅压力
crs_detected: 是否检测到儿童座椅
manual_override: 手动覆盖 ('ON' / 'OFF' / None)

Returns:
status: {
'airbag_on': bool,
'reason': str,
'warning': Optional[str],
'automatic': bool
}
"""
# 1. 检测儿童座椅
if crs_detected:
# 检测到儿童座椅,确定类型
crs_type = self.crs_detector.classify(depth_map)

if crs_type == 'rear_facing':
# 后向儿童座椅必须禁用气囊
self.airbag_status = 'OFF'
return {
'airbag_on': False,
'reason': 'rear_facing_child_seat_detected',
'warning': None,
'automatic': True
}

# 2. 座椅无乘员
if seat_pressure < 5.0: # <5kg
self.airbag_status = 'OFF'
return {
'airbag_on': False,
'reason': 'seat_empty',
'warning': None,
'automatic': True
}

# 3. 乘员分类
classification = self.occupant_classifier.classify(
depth_map, seat_pressure, 50, 25
)

# 4. 根据身材确定气囊策略
if classification['stature_class'] == '5th_percentile':
# 小身材成人,气囊开启但可能调整展开力度
self.airbag_status = 'ON'
return {
'airbag_on': True,
'reason': 'adult_5th_percentile',
'warning': None,
'automatic': True,
'deployment_level': 'low_power'
}

# 5. 标准成人
self.airbag_status = 'ON'
return {
'airbag_on': True,
'reason': 'adult_standard',
'warning': None,
'automatic': True
}

def check_conflict(
self,
airbag_status: str,
occupant_status: dict
) -> Optional[str]:
"""
检查气囊状态与乘员状态的冲突

Returns:
warning: 冲突警告(若有)
"""
# 气囊关闭但检测到成人
if airbag_status == 'OFF' and occupant_status.get('is_adult', False):
return "Airbag is OFF but adult passenger detected"

# 气囊开启但检测到儿童座椅
if airbag_status == 'ON' and occupant_status.get('crs_detected', False):
return "Airbag is ON with child seat present"

return None


class CRSDetector(nn.Module):
"""
儿童约束系统(CRS)检测器

检测儿童座椅类型和朝向
"""

def __init__(self):
super().__init__()

# 图像编码器
self.encoder = nn.Sequential(
nn.Conv2d(3, 32, 5, stride=2, padding=2),
nn.ReLU(),
nn.Conv2d(32, 64, 3, stride=2, padding=1),
nn.ReLU(),
nn.Conv2d(64, 128, 3, stride=2, padding=1),
nn.ReLU(),
nn.AdaptiveAvgPool2d((4, 4))
)

# CRS 分类器
self.classifier = nn.Sequential(
nn.Linear(128 * 4 * 4, 128),
nn.ReLU(),
nn.Linear(128, 4) # no_crs, rear_facing, forward_facing, booster
)

def forward(self, image: torch.Tensor) -> dict:
"""
前向传播

Args:
image: 座椅区域图像, shape=(B, 3, H, W)

Returns:
crs_type: 儿童座椅类型
"""
features = self.encoder(image)
features = features.view(features.size(0), -1)
logits = self.classifier(features)
return {'crs_logits': logits}

def classify(self, depth_map: np.ndarray) -> str:
"""分类儿童座椅类型"""
# 实际实现会使用训练好的模型
# 这里返回示例
return 'rear_facing'

约束系统自适应调整

调整参数矩阵

参数 5th 百分位 50th 百分位 95th 百分位
预紧器力度 标准
负载限制器 降低 标准 提高
气囊展开力度 低功率 标准 高功率
展开时机 提前 标准 延后

自适应系统实现

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
from dataclasses import dataclass

@dataclass
class RestraintParameters:
"""约束系统参数"""
pretensioner_force_N: float
load_limiter_N: float
airbag_power_level: int # 1-3
airbag_deploy_timing_ms: float


class AdaptiveRestraintController:
"""
自适应约束系统控制器

根据乘员特征动态调整约束参数
"""

def __init__(self):
# 基础参数
self.base_params = {
'5th_percentile': RestraintParameters(
pretensioner_force_N=3000,
load_limiter_N=4000,
airbag_power_level=1,
airbag_deploy_timing_ms=15
),
'50th_percentile': RestraintParameters(
pretensioner_force_N=4500,
load_limiter_N=6000,
airbag_power_level=2,
airbag_deploy_timing_ms=20
),
'95th_percentile': RestraintParameters(
pretensioner_force_N=6000,
load_limiter_N=8000,
airbag_power_level=3,
airbag_deploy_timing_ms=25
)
}

def get_restraint_params(
self,
occupant_classification: dict
) -> RestraintParameters:
"""
获取约束参数

Args:
occupant_classification: 乘员分类结果

Returns:
params: 约束参数
"""
stature = occupant_classification['stature_class']

# 获取基础参数
base = self.base_params.get(stature, self.base_params['50th_percentile'])

# 根据具体体重/身高微调
weight = occupant_classification.get('estimated_weight_kg', 70)
height = occupant_classification.get('estimated_height_cm', 170)

# 调整预紧器力度(根据体重)
weight_factor = weight / 70.0 # 以 70kg 为基准
adjusted_pretensioner = base.pretensioner_force_N * weight_factor

# 调整负载限制器(根据身高)
height_factor = height / 175.0 # 以 175cm 为基准
adjusted_load_limiter = base.load_limiter_N * height_factor

return RestraintParameters(
pretensioner_force_N=adjusted_pretensioner,
load_limiter_N=adjusted_load_limiter,
airbag_power_level=base.airbag_power_level,
airbag_deploy_timing_ms=base.airbag_deploy_timing_ms
)

def update_in_realtime(
self,
classification_history: List[dict],
update_interval_sec: float = 10.0
) -> bool:
"""
实时更新约束参数

Euro NCAP 要求:乘员变化后 10 秒内更新

Returns:
updated: 是否需要更新
"""
if len(classification_history) < 2:
return False

# 检查最近两次分类是否变化
current = classification_history[-1]
previous = classification_history[-2]

if current['stature_class'] != previous['stature_class']:
# 身材分类变化
return True

# 检查体重/身高显著变化
weight_change = abs(
current['estimated_weight_kg'] - previous['estimated_weight_kg']
)
if weight_change > 10: # 变化超过 10kg
return True

return False

Euro NCAP 测试场景

测试矩阵

测试编号 场景 检测内容 通过条件
OM-01 5th 百分位乘员 身材分类 ≤10秒正确分类
OM-02 95th 百分位乘员 身材分类 ≤10秒正确分类
OM-03 后向儿童座椅 气囊禁用 自动 OFF
OM-04 脚踩仪表盘 OOP 检测 ≤30秒警告
OM-05 头部近仪表盘 距离检测 <20cm 触发警告
OM-06 座椅调整 参数更新 ≤10秒更新

IMS 开发建议

硬件配置

传感器 数量 位置 用途
TOF 深度相机 1-2 车顶/仪表台 身材估计、OOP检测
座椅压力传感器 1/座 座椅底部 乘员检测、体重估计
2D 摄像头 1-2 车顶 辅助检测

部署时间表

1
2
3
4
5
2025 Q3: 传感器集成
2025 Q4: 算法开发
2026 Q1: 实车测试
2026 Q2: Euro NCAP 认证
2026 Q3: SOP

关键验证点

  1. 身材分类准确率: ≥95%
  2. OOP 检测时延: ≤30秒
  3. 气囊状态更新: ≤10秒
  4. 误报率: <1%

参考文献

  1. Smart Eye, “Euro NCAP 2026: New Standards for Occupant Monitoring and Adaptive Restraints”, 2025
  2. Euro NCAP, “Safe Driving Occupant Monitoring Protocol v1.1”, 2025
  3. CDC, “2000 CDC Growth Charts for the United States”

总结: Euro NCAP 2026 要求乘员监测系统实现身材分类、OOP 检测和自适应约束调整。建议采用 TOF 深度相机 + 压力传感器融合方案,重点实现 10 秒内分类更新和 30 秒内 OOP 警告触发。


Euro NCAP 2026 乘员监测与自适应约束系统:完整技术指南
https://dapalm.com/2026/06/04/2026-06-04-Euro-NCAP-2026乘员监测与自适应约束系统完整技术指南/
作者
Mars
发布于
2026年6月4日
许可协议