乘员分类与自适应约束:Euro NCAP 2026要求下的传感器融合方案

技术背景

  • 核心要求: Euro NCAP 2026 Protocol v1.2 — 气囊必须按乘员大小/位置/姿态自适应
  • 关键产业: IEE Smart Sensing BodySense™、BeBop Sensors织物压力、InCabin Europe 2026
  • 标准: FMVSS 208(美国)、Euro NCAP(欧洲)、GB 14167(中国)
  • 成本目标: 织物传感器~$7-10(InCabin 2026报告:现有技术的一半成本)

Euro NCAP 2026 乘员分类要求清单

要求编号 场景 检测要求 时限 分值
OC-01 成人 vs 儿童 重量+体型分类 ≤2秒 2分
OC-02 后向儿童座椅 自动识别+气囊禁用 ≤2秒 3分
OC-03 体型小成人(前排) 气囊低力度展开 ≤2秒 1分
OC-04 脚搭仪表台 OOP检测+警告 ≤5秒 2分
OC-05 上身靠近仪表台 <20cm检测+警告 ≤3秒 2分
OC-06 后排乘员存在 存在+安全带状态 实时 2分
OC-07 eCall乘员数据 碰撞时传输人数 实时 3分

传感器融合方案

多传感器分类架构

graph TB
    subgraph 传感器层
        A[座椅重量传感器<br/>压阻式 4点]
        B[座椅压力阵列<br/>16x16织物]
        C[OMS摄像头<br/>RGB-IR]
        D[mmWave雷达<br/>60GHz]
        E[安全带张力<br/>应变片]
    end
    
    subgraph 特征提取
        A --> F[重量±2kg]
        B --> G[压力分布图]
        C --> H[人体关键点<br/>体型估计]
        D --> I[呼吸率<br/>存在检测]
        E --> J[安全带状态]
    end
    
    subgraph 融合分类
        F --> K[Bayesian融合]
        G --> K
        H --> K
        I --> K
        J --> K
        K --> L{乘员分类}
    end
    
    subgraph 输出
        L --> M[成人/儿童/儿童座椅]
        L --> N[体型分类]
        L --> O[姿态/OOP]
        L --> P[气囊策略]
    end

传感器BOM

传感器 型号/规格 覆盖场景 单价 来源
座椅重量 4点压阻式传感器 OC-01/02 $5 IEE/通用
压力阵列 16×16织物压力 OC-04/05 $7 BeBop/AIQ
OMS摄像头 OV2311 RGB-IR OC-03/04/05 $8 OmniVision
60GHz雷达 TI IWR6843AOP OC-06/呼吸 $15 TI
安全带张力 应变片 安全带状态 $3 通用
总计 - - $38 -

技术实现

多传感器乘员分类引擎

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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
"""
Euro NCAP 2026 乘员分类系统

融合: 重量 + 压力分布 + 摄像头 + 雷达 + 安全带
依赖: pip install numpy scipy

输出:
- 乘员类别: 成人/儿童/儿童座椅/空座
- 体型: 小/中/大
- 姿态: 正常/OOP
- 气囊策略: 正常/低力度/禁用
"""

import numpy as np
from typing import Dict, Tuple, Optional
from dataclasses import dataclass
from enum import IntEnum

class OccupantCategory(IntEnum):
EMPTY = 0
CHILD_SEAT_REAR = 1 # 后向儿童座椅
CHILD_SEAT_FORWARD = 2 # 前向儿童座椅
CHILD = 3 # 儿童(<36kg)
SMALL_ADULT = 4 # 小体型成人(<50kg)
ADULT = 5 # 成人(50-100kg)
LARGE_ADULT = 6 # 大体型成人(>100kg)

class AirbagStrategy(IntEnum):
DISABLE = 0 # 禁用
LOW_POWER = 1 # 低力度
NORMAL = 2 # 正常

@dataclass
class SensorReadings:
"""传感器读数"""
weight_kg: float = 0.0
pressure_map: Optional[np.ndarray] = None # 16x16
body_keypoints: Optional[np.ndarray] = None # 17个关键点
breathing_rate: float = 0.0 # 雷达呼吸率
presence_detected: bool = False # 雷达存在检测
seatbelt_buckled: bool = False
seatbelt_position: str = 'correct'

class OccupantClassifier:
"""
多传感器乘员分类器

方法: 加权证据融合
每个传感器提供独立证据,加权融合后决策
"""

def __init__(self):
self.weight_thresholds = {
'empty': 2.0, # <2kg = 空座
'child': 36.0, # <36kg = 儿童
'small': 50.0, # <50kg = 小成人
'large': 100.0, # >100kg = 大成人
}

def classify_from_weight(self, weight: float) -> Tuple[OccupantCategory, float]:
"""重量分类"""
if weight < self.weight_thresholds['empty']:
return OccupantCategory.EMPTY, 0.9
elif weight < self.weight_thresholds['child']:
return OccupantCategory.CHILD, 0.7
elif weight < self.weight_thresholds['small']:
return OccupantCategory.SMALL_ADULT, 0.65
elif weight < self.weight_thresholds['large']:
return OccupantCategory.ADULT, 0.8
else:
return OccupantCategory.LARGE_ADULT, 0.75

def classify_from_pressure(self, pressure_map: np.ndarray) -> Tuple[OccupantCategory, float]:
"""压力分布分类"""
total_pressure = np.sum(pressure_map)
pressure_area = np.sum(pressure_map > 0.1) # 有效接触面积

if total_pressure < 1.0:
return OccupantCategory.EMPTY, 0.85

# 后向儿童座椅特征:压力集中在中部+头部区域有压力
center_pressure = np.sum(pressure_map[4:12, 6:10])
upper_pressure = np.sum(pressure_map[:4, 4:12])

if center_pressure > total_pressure * 0.6 and upper_pressure > 5:
return OccupantCategory.CHILD_SEAT_REAR, 0.6

# 按接触面积分类
if pressure_area < 50:
return OccupantCategory.CHILD, 0.6
elif pressure_area < 100:
return OccupantCategory.SMALL_ADULT, 0.55
elif pressure_area < 200:
return OccupantCategory.ADULT, 0.7
else:
return OccupantCategory.LARGE_ADULT, 0.65

def classify_from_camera(self, keypoints: np.ndarray) -> Tuple[OccupantCategory, float]:
"""摄像头体型估计"""
if keypoints is None or len(keypoints) < 5:
return OccupantCategory.ADULT, 0.3 # 默认假设

# 肩宽估计
left_shoulder = keypoints[5] # 左肩
right_shoulder = keypoints[6] # 右肩
shoulder_width = np.sqrt(
(left_shoulder[0] - right_shoulder[0])**2 +
(left_shoulder[1] - right_shoulder[1])**2
)

# 坐高估计
nose = keypoints[0]
hip = keypoints[11]
sitting_height = np.sqrt(
(nose[0] - hip[0])**2 + (nose[1] - hip[1])**2
)

# 分类
if shoulder_width < 80 and sitting_height < 150:
return OccupantCategory.CHILD, 0.6
elif shoulder_width < 100:
return OccupantCategory.SMALL_ADULT, 0.5
elif shoulder_width > 160:
return OccupantCategory.LARGE_ADULT, 0.55
else:
return OccupantCategory.ADULT, 0.6

def detect_child_seat(self, weight: float,
pressure_map: np.ndarray,
breathing_rate: float) -> Tuple[bool, str, float]:
"""
儿童座椅检测

特征:
- 重量异常轻但压力分布有座椅轮廓
- 呼吸率偏高(婴幼儿30-40次/分 vs 成人12-20次/分)
- 压力分布模式不同于人体
"""
# 后向儿童座椅
if weight < 15 and breathing_rate > 25:
return True, 'rear_facing', 0.7

# 压力分布异常(座椅模式)
if pressure_map is not None:
center = pressure_map[6:10, 6:10]
edges = pressure_map[:2, :].sum() + pressure_map[-2:, :].sum()
if center.mean() > edges * 0.3:
return True, 'forward_facing', 0.5

return False, '', 0.0

def detect_oop(self, pressure_map: np.ndarray,
keypoints: np.ndarray,
distance_to_dash: float) -> Dict:
"""
OOP异常姿态检测
"""
oop_results = {}

# 脚搭仪表台
if keypoints is not None and len(keypoints) > 15:
left_ankle = keypoints[15]
right_ankle = keypoints[16]
if left_ankle[1] < 100 or right_ankle[1] < 100: # y坐标小说明在前方
oop_results['feet_on_dash'] = True

# 上身靠近仪表台
if distance_to_dash < 20:
oop_results['too_close'] = True
oop_results['distance'] = distance_to_dash

# 前伏
if pressure_map is not None:
upper = pressure_map[:6, :].sum()
lower = pressure_map[10:, :].sum()
if upper > lower * 1.5:
oop_results['forward_bent'] = True

return oop_results

def determine_airbag_strategy(self, category: OccupantCategory,
oop: Dict) -> AirbagStrategy:
"""确定气囊策略"""
if category == OccupantCategory.CHILD_SEAT_REAR:
return AirbagStrategy.DISABLE
elif category == OccupantCategory.CHILD:
return AirbagStrategy.DISABLE
elif category == OccupantCategory.SMALL_ADULT:
return AirbagStrategy.LOW_POWER
elif oop.get('too_close') or oop.get('feet_on_dash'):
return AirbagStrategy.LOW_POWER
else:
return AirbagStrategy.NORMAL

def classify(self, readings: SensorReadings) -> Dict:
"""
完整乘员分类
"""
# 各传感器独立分类
w_cat, w_conf = self.classify_from_weight(readings.weight_kg)
p_cat = OccupantCategory.ADULT
p_conf = 0.3
if readings.pressure_map is not None:
p_cat, p_conf = self.classify_from_pressure(readings.pressure_map)

c_cat = OccupantCategory.ADULT
c_conf = 0.3
if readings.body_keypoints is not None:
c_cat, c_conf = self.classify_from_camera(readings.body_keypoints)

# 儿童座椅检测
is_child_seat, seat_type, cs_conf = self.detect_child_seat(
readings.weight_kg,
readings.pressure_map,
readings.breathing_rate
)

# 证据融合(加权投票)
weights = {'weight': 0.35, 'pressure': 0.30, 'camera': 0.35}

if is_child_seat and cs_conf > 0.5:
final_category = (OccupantCategory.CHILD_SEAT_REAR
if seat_type == 'rear_facing'
else OccupantCategory.CHILD_SEAT_FORWARD)
final_conf = cs_conf
else:
# 加权投票
votes = {}
for cat, conf, w in [
(w_cat, w_conf, weights['weight']),
(p_cat, p_conf, weights['pressure']),
(c_cat, c_conf, weights['camera']),
]:
if cat not in votes:
votes[cat] = 0
votes[cat] += conf * w

final_category = max(votes, key=votes.get)
final_conf = votes[final_category]

# OOP检测
distance = 999.0
if readings.body_keypoints is not None:
# 简化距离估计
distance = 30.0 # 实际应从深度图计算

oop = self.detect_oop(
readings.pressure_map if readings.pressure_map is not None else np.zeros((16,16)),
readings.body_keypoints,
distance
)

# 气囊策略
airbag = self.determine_airbag_strategy(final_category, oop)

return {
'category': final_category.name,
'confidence': round(final_conf, 2),
'weight_kg': readings.weight_kg,
'child_seat': is_child_seat,
'seat_type': seat_type,
'oop': oop,
'airbag_strategy': airbag.name,
'seatbelt_status': 'buckled' if readings.seatbelt_buckled else 'unbuckled',
}


# 测试
if __name__ == "__main__":
np.random.seed(42)
classifier = OccupantClassifier()

# 成人
adult = SensorReadings(
weight_kg=75,
pressure_map=np.random.rand(16, 16) * 0.3 + 0.3,
body_keypoints=np.random.rand(17, 2) * 200,
breathing_rate=16,
presence_detected=True,
seatbelt_buckled=True,
)

# 儿童
child = SensorReadings(
weight_kg=22,
pressure_map=np.random.rand(16, 16) * 0.2 + 0.1,
body_keypoints=np.random.rand(17, 2) * 100,
breathing_rate=28,
presence_detected=True,
seatbelt_buckled=True,
)

# 后向儿童座椅
infant = SensorReadings(
weight_kg=8,
pressure_map=np.random.rand(16, 16) * 0.1,
breathing_rate=35,
presence_detected=True,
)

print("=== 成人 ===")
r = classifier.classify(adult)
for k, v in r.items():
print(f" {k}: {v}")

print(f"\n=== 儿童 ===")
r = classifier.classify(child)
for k, v in r.items():
print(f" {k}: {v}")

print(f"\n=== 后向儿童座椅 ===")
r = classifier.classify(infant)
for k, v in r.items():
print(f" {k}: {v}")

织物压力传感器方案

InCabin Europe 2026 产业报告

“最成熟的应用是新一代座椅占用分类,使用座椅装饰下方薄织物传感器,成本约为现有技术的一半” — InCabin 2026

参数 织物传感器(新) 重量传感器(现有)
厚度 <2mm ~10mm
成本 ~$7 ~$15
铺设 座椅面下方全铺 座椅底部4点
分辨率 16×16=256点 4点
分类能力 体型+姿态 仅重量
耐久 >10年 >10年
水洗 ✅ ❌
供应商 BeBop/AIQ/IEE IEE/H.B. Fuller

参考文献

  1. Euro NCAP Protocol v1.2: https://cdn.euroncap.com/cars/assets/Euro_NCAP_Protocol_Safe_Driving_Occupant_Monitoring_v1_2_aebbc7361f.pdf
  2. Smart Eye: https://smarteye.se/blog/euro-ncap-2026-new-standards-for-occupant-monitoring-and-adaptive-restraints/
  3. InCabin 2026: https://incabin.com/blog/incabin-europe-2026-press-conference-recap/
  4. IEE BodySense: https://iee-sensing.com/automotive/safety-and-comfort/occupant-classification/
  5. Anyverse OEM指南: https://anyverse.ai/euro-ncap-2026-in-cabin-monitoring-oem-guidelines-to-readiness/
  6. EDAG儿童安全: https://insights.edag.com/en/child-safety-euro-ncap-ratings

https://dapalm.com/2026/10/03/2026-10-03-06-occupant-classification-adaptive-restraint-sensor-fusion-ims/
作者
Mars
发布于
2026年10月3日
许可协议