Euro NCAP 2026 CPD儿童存在检测完整实施指南

来源: Euro NCAP CPD Test and Assessment Protocol v1.2 + Smart Eye分析
生效时间: 2026年
核心要求: 直接检测 + 快速响应 + 主动干预


Euro NCAP CPD 核心要求

检测场景

场景 描述 触发条件
场景1 儿童被遗忘在锁闭车辆中 车辆锁闭后检测到儿童
场景2 儿童自行进入未锁车辆被困 车门关闭后检测到儿童

检测范围

区域 要求
所有座椅位置 ✅ 必须,包括可选和可拆卸座椅
脚坑 ✅ 必须
驾驶座 ✅ 必须
行李舱 ❌ 不要求

检测目标

年龄范围 要求
≤ 6岁 ✅ 必须检测
> 6岁 ❌ 不要求

直接检测方法

方法 原理 Euro NCAP认可
运动检测 检测身体运动
呼吸检测 检测呼吸运动(胸腔起伏)
心跳检测 检测心脏跳动
门开关记录 间接推断 ❌ 不接受
座椅传感器 压力检测 ❌ 不够(无法区分儿童/物品)

时间要求详解

锁闭车辆场景

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
┌─────────────────────────────────────────────────────────────────┐
│ 锁闭车辆CPD时序 │
├─────────────────────────────────────────────────────────────────┤
│ │
T=0 车辆锁闭 │
│ │ │
│ ├── 15s ───► 检测到儿童后15秒内开始警告 │
│ │ │
│ ├── 初始警告 │
│ │ ├── 视觉/听觉信号(喇叭/灯光) │
│ │ ├── 持续 ≥ 3秒 │
│ │ └── 可从车外感知 │
│ │ │
│ ├── 驾驶员可延迟(可选) │
│ │ └── 最多延迟10分钟 │
│ │ │
│ ├── 升级警告(初始警告结束后90秒内) │
│ │ ├── 每分钟重复一次 │
│ │ ├── 持续 ≥ 20分钟 │
│ │ ├── 每次持续 ≥ 15秒 │
│ │ └── 车内显示"Check the seats"
│ │ │
│ └── 干预措施(10分钟内或温度危险时立即) │
│ ├── 激活空调 │
│ ├── 解锁车门 │
│ └── 发送远程通知 │
│ │
└─────────────────────────────────────────────────────────────────┘

未锁车辆场景

1
2
3
4
5
6
7
8
9
10
11
┌─────────────────────────────────────────────────────────────────┐
│ 未锁车辆CPD时序 │
├─────────────────────────────────────────────────────────────────┤
│ │
T=0 车门关闭(未锁) │
│ │ │
│ ├── 10分钟 ─► 检测到儿童后10分钟内开始警告 │
│ │ │
│ └── 后续流程同锁闭车辆场景 │
│ │
└─────────────────────────────────────────────────────────────────┘

满分要求

基础分数(3分)

要求 分值
直接检测方法 必需
所有座椅位置覆盖 必需
6岁以下儿童检测 必需
默认开启 必需

干预分数(2分)

干预措施 要求
激活空调 10分钟内或温度危险时立即
解锁车门 允许外部人员进入救援
远程通知 发送到手机APP/紧急联系人

技术实现方案

方案1:mmWave雷达检测

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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
"""
mmWave雷达CPD检测实现
检测原理:分析呼吸运动产生的微多普勒信号

硬件要求:
- 60GHz mmWave雷达(如TI IWR6843AOP)
- 4发4收天线阵列
- 能检测0.2-0.7Hz呼吸频率
"""

import numpy as np
from typing import List, Tuple, Optional
from dataclasses import dataclass
from enum import Enum


class OccupantType(Enum):
"""乘员类型"""
EMPTY = "empty"
ADULT = "adult"
CHILD = "child"
INFANT = "infant"
OBJECT = "object"


@dataclass
class RadarFrame:
"""雷达帧数据"""
timestamp: float # 毫秒
range_profile: np.ndarray # 距离剖面
doppler_profile: np.ndarray # 多普勒剖面
point_cloud: List[Tuple[float, float, float, float, float]] # (x, y, z, velocity, rcs)


@dataclass
class VitalSigns:
"""生命体征"""
breathing_rate: float # 呼吸频率 (次/分)
breathing_confidence: float # 置信度
movement_detected: bool # 是否检测到运动


class CPDRadarDetector:
"""
Euro NCAP CPD雷达检测器

符合2026协议要求:
- 检测呼吸/运动
- 识别儿童(≤6岁)
- 15秒内触发警告
"""

# 儿童呼吸频率范围(次/分)
CHILD_BREATHING_RANGE = (20, 40)

# 成人呼吸频率范围
ADULT_BREATHING_RANGE = (12, 20)

def __init__(
self,
radar_frame_rate: int = 10,
fft_size: int = 512,
breathing_threshold: float = 0.3,
movement_threshold: float = 0.5
):
"""
初始化CPD检测器

Args:
radar_frame_rate: 雷达帧率
fft_size: FFT点数
breathing_threshold: 呼吸检测阈值
movement_threshold: 运动检测阈值
"""
self.frame_rate = radar_frame_rate
self.fft_size = fft_size
self.breathing_threshold = breathing_threshold
self.movement_threshold = movement_threshold

# 数据缓存
self.doppler_buffer = []
self.range_buffer = []
self.buffer_duration = 30 # 30秒缓存

# 状态
self.last_detection_time = None
self.warning_state = "idle"

def process_frame(self, frame: RadarFrame) -> Tuple[Optional[VitalSigns], OccupantType]:
"""
处理单帧雷达数据

Args:
frame: 雷达帧

Returns:
vital_signs: 生命体征
occupant_type: 乘员类型
"""
# 添加到缓存
self.doppler_buffer.append(frame.doppler_profile)
self.range_buffer.append(frame.range_profile)

# 限制缓存大小
max_frames = self.buffer_duration * self.frame_rate
if len(self.doppler_buffer) > max_frames:
self.doppler_buffer = self.doppler_buffer[-max_frames:]
self.range_buffer = self.range_buffer[-max_frames:]

# 需要至少10秒数据才能分析呼吸
if len(self.doppler_buffer) < 10 * self.frame_rate:
return None, OccupantType.EMPTY

# 检测呼吸
vital_signs = self._detect_breathing()

# 检测运动
movement = self._detect_movement()
if vital_signs:
vital_signs.movement_detected = movement

# 分类乘员
occupant_type = self._classify_occupant(vital_signs)

return vital_signs, occupant_type

def _detect_breathing(self) -> Optional[VitalSigns]:
"""
检测呼吸信号

使用FFT分析多普勒信号中的呼吸频率
"""
# 构建多普勒时间序列
doppler_series = np.array(self.doppler_buffer)

# 对每个距离bin计算时间序列
# 选择最强目标的距离bin
mean_range = np.mean(self.range_buffer, axis=0)
target_range_bin = np.argmax(mean_range)

# 提取该距离bin的多普勒时间序列
if doppler_series.ndim == 2:
doppler_time_series = doppler_series[:, target_range_bin]
else:
doppler_time_series = doppler_series

# 去除直流分量
doppler_time_series = doppler_time_series - np.mean(doppler_time_series)

# FFT
fft_result = np.fft.rfft(doppler_time_series, n=self.fft_size)
fft_magnitude = np.abs(fft_result)

# 频率轴
freq_resolution = self.frame_rate / self.fft_size
frequencies = np.arange(len(fft_magnitude)) * freq_resolution

# 寻找呼吸频率峰值(0.2-0.7 Hz)
breathing_mask = (frequencies >= 0.2) & (frequencies <= 0.7)
breathing_spectrum = fft_magnitude * breathing_mask

if np.max(breathing_spectrum) > 0:
peak_idx = np.argmax(breathing_spectrum)
breathing_freq = frequencies[peak_idx]
breathing_rate = breathing_freq * 60 # 转换为次/分

# 计算置信度
total_power = np.sum(fft_magnitude)
breathing_power = np.sum(breathing_spectrum)
confidence = breathing_power / total_power if total_power > 0 else 0

if confidence > self.breathing_threshold:
return VitalSigns(
breathing_rate=breathing_rate,
breathing_confidence=confidence,
movement_detected=False
)

return None

def _detect_movement(self) -> bool:
"""
检测大动作

通过多普勒信号的变化检测
"""
if len(self.doppler_buffer) < 10:
return False

recent_doppler = self.doppler_buffer[-10:]
variance = np.var(recent_doppler)

return variance > self.movement_threshold

def _classify_occupant(self, vital_signs: Optional[VitalSigns]) -> OccupantType:
"""
分类乘员类型

基于呼吸频率区分儿童/成人
"""
if vital_signs is None:
return OccupantType.EMPTY

breathing_rate = vital_signs.breathing_rate

# 儿童呼吸频率较高
if self.CHILD_BREATHING_RANGE[0] <= breathing_rate <= self.CHILD_BREATHING_RANGE[1]:
return OccupantType.CHILD

# 成人
if self.ADULT_BREATHING_RANGE[0] <= breathing_rate <= self.ADULT_BREATHING_RANGE[1]:
return OccupantType.ADULT

# 婴儿呼吸频率更高
if breathing_rate > self.CHILD_BREATHING_RANGE[1]:
return OccupantType.INFANT

return OccupantType.OBJECT


class CPDWarningController:
"""
CPD警告控制器

符合Euro NCAP 2026时序要求
"""

def __init__(self):
self.state = "idle"
self.detection_time = None
self.warning_count = 0
self.last_warning_time = None

def update(
self,
occupant_type: OccupantType,
vehicle_locked: bool,
doors_closed: bool,
current_time: float
) -> dict:
"""
更新警告状态

Args:
occupant_type: 乘员类型
vehicle_locked: 车辆是否锁闭
doors_closed: 车门是否关闭
current_time: 当前时间(秒)

Returns:
action: 需要执行的动作
"""
# 只对儿童/婴儿触发
if occupant_type not in [OccupantType.CHILD, OccupantType.INFANT]:
self.state = "idle"
self.detection_time = None
return {"action": "none"}

# 记录首次检测时间
if self.detection_time is None:
self.detection_time = current_time

elapsed = current_time - self.detection_time

# 锁闭车辆:15秒内警告
if vehicle_locked:
if self.state == "idle" and elapsed >= 15:
self.state = "initial_warning"
self.last_warning_time = current_time
return {
"action": "initial_warning",
"duration": 3,
"type": "visual_audible"
}

# 未锁车辆:10分钟内警告
else:
if self.state == "idle" and elapsed >= 600:
self.state = "initial_warning"
self.last_warning_time = current_time
return {
"action": "initial_warning",
"duration": 3,
"type": "visual_audible"
}

# 升级警告
if self.state == "initial_warning":
if self.last_warning_time and (current_time - self.last_warning_time) >= 90:
self.state = "escalation"
self.warning_count += 1
self.last_warning_time = current_time
return {
"action": "escalation",
"duration": 15,
"type": "intensive",
"message": "Check the seats",
"count": self.warning_count
}

# 持续警告(每分钟一次)
if self.state == "escalation":
if self.last_warning_time and (current_time - self.last_warning_time) >= 60:
self.warning_count += 1
self.last_warning_time = current_time

# 20分钟后停止
if elapsed <= 1200:
return {
"action": "escalation",
"duration": 15,
"type": "intensive",
"message": "Check the seats",
"count": self.warning_count
}

# 干预(10分钟内)
if elapsed >= 600:
return {
"action": "intervention",
"measures": ["climate_control", "unlock_doors", "remote_notification"]
}

return {"action": "none"}


# 测试代码
if __name__ == "__main__":
# 初始化检测器
detector = CPDRadarDetector(radar_frame_rate=10)
controller = CPDWarningController()

print("=== Euro NCAP CPD测试 ===")
print(f"儿童呼吸频率范围: {detector.CHILD_BREATHING_RANGE}")
print()

# 模拟儿童呼吸信号(30次/分 = 0.5 Hz)
breathing_rate = 30
breathing_freq = breathing_rate / 60

# 模拟30秒数据
frame_rate = 10
duration = 30

for i in range(duration * frame_rate):
t = i / frame_rate

# 模拟雷达帧
breathing_motion = 0.02 * np.sin(2 * np.pi * breathing_freq * t)
noise = np.random.normal(0, 0.005, 10)

frame = RadarFrame(
timestamp=t * 1000,
range_profile=np.random.randn(10),
doppler_profile=breathing_motion + noise,
point_cloud=[]
)

vital_signs, occupant_type = detector.process_frame(frame)

# 模拟锁车场景
if t >= 5 and i % 20 == 0:
action = controller.update(
occupant_type=occupant_type,
vehicle_locked=True,
doors_closed=True,
current_time=t
)

if action["action"] != "none":
print(f"[{t:.1f}s] 检测结果: {occupant_type.value}")
if vital_signs:
print(f" 呼吸频率: {vital_signs.breathing_rate:.1f} 次/分")
print(f" 置信度: {vital_signs.breathing_confidence:.2f}")
print(f" 警告动作: {action}")
print()

print("=== 测试完成 ===")

方案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
"""
摄像头+雷达融合CPD方案

摄像头:提供视觉确认
雷达:检测呼吸/心跳

融合策略:互补验证
"""

import numpy as np
from typing import Tuple, Optional
from dataclasses import dataclass


@dataclass
class CameraDetection:
"""摄像头检测结果"""
has_occupant: bool
occupant_type: str # "child", "adult", "unknown"
seat_position: Tuple[int, int]
confidence: float


@dataclass
class FusionResult:
"""融合结果"""
child_detected: bool
confidence: float
detection_method: str


class CPDFusionDetector:
"""
摄像头+雷达融合CPD检测器
"""

def __init__(
self,
camera_weight: float = 0.4,
radar_weight: float = 0.6
):
"""
Args:
camera_weight: 摄像头权重
radar_weight: 雷达权重
"""
self.camera_weight = camera_weight
self.radar_weight = radar_weight

def fuse(
self,
camera_det: Optional[CameraDetection],
radar_vital: Optional[VitalSigns],
radar_occupant: OccupantType
) -> FusionResult:
"""
融合摄像头和雷达检测结果

Args:
camera_det: 摄像头检测结果
radar_vital: 雷达生命体征
radar_occupant: 雷达乘员类型

Returns:
fusion_result: 融合结果
"""
# 雷达检测到生命体征
if radar_vital and radar_vital.breathing_confidence > 0.5:
# 雷达确认有呼吸
if radar_occupant in [OccupantType.CHILD, OccupantType.INFANT]:
# 摄像头辅助确认
if camera_det and camera_det.has_occupant:
confidence = (
self.radar_weight * radar_vital.breathing_confidence +
self.camera_weight * camera_det.confidence
)
else:
# 雷达单独检测到
confidence = radar_vital.breathing_confidence * 0.8

return FusionResult(
child_detected=True,
confidence=confidence,
detection_method="radar_primary"
)

# 摄像头检测到儿童(无雷达生命体征)
if camera_det and camera_det.occupant_type == "child":
return FusionResult(
child_detected=True,
confidence=camera_det.confidence * self.camera_weight,
detection_method="camera_only"
)

return FusionResult(
child_detected=False,
confidence=0.0,
detection_method="none"
)

干预措施实现

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
"""
CPD干预措施控制器

符合Euro NCAP 2026要求:
- 10分钟内启动
- 温度危险时立即启动
"""

from typing import List, Optional
from dataclasses import dataclass
from enum import Enum


class CabinCondition(Enum):
"""车内环境状态"""
NORMAL = "normal"
WARNING = "warning" # 35-40°C
DANGER = "danger" # > 40°C


@dataclass
class InterventionAction:
"""干预动作"""
action_type: str
trigger_time: float
parameters: dict


class CPDInterventionController:
"""
CPD干预控制器

管理空调、门锁、通知等干预措施
"""

# 温度阈值
WARNING_TEMP = 35.0 # °C
DANGER_TEMP = 40.0

def __init__(self):
self.intervention_history = []
self.cabin_temp = 25.0

def update(
self,
child_detected: bool,
detection_duration: float,
cabin_temp: float
) -> List[InterventionAction]:
"""
更新干预状态

Args:
child_detected: 是否检测到儿童
detection_duration: 检测持续时间(秒)
cabin_temp: 车内温度(°C)

Returns:
actions: 需要执行的干预动作
"""
self.cabin_temp = cabin_temp
actions = []

if not child_detected:
return actions

# 评估环境状态
condition = self._assess_cabin_condition(cabin_temp)

# 温度危险:立即干预
if condition == CabinCondition.DANGER:
actions.append(InterventionAction(
action_type="climate_control",
trigger_time=0,
parameters={"target_temp": 25.0, "mode": "max_cooling"}
))
actions.append(InterventionAction(
action_type="unlock_doors",
trigger_time=0,
parameters={}
))
actions.append(InterventionAction(
action_type="emergency_notification",
trigger_time=0,
parameters={"contacts": ["emergency", "caregiver"]}
))
return actions

# 温度警告:提前干预
if condition == CabinCondition.WARNING:
actions.append(InterventionAction(
action_type="climate_control",
trigger_time=0,
parameters={"target_temp": 28.0, "mode": "cooling"}
))

# 10分钟内干预
if detection_duration >= 600:
actions.append(InterventionAction(
action_type="climate_control",
trigger_time=600,
parameters={"target_temp": 25.0, "mode": "cooling"}
))

actions.append(InterventionAction(
action_type="unlock_doors",
trigger_time=600,
parameters={}
))

actions.append(InterventionAction(
action_type="app_notification",
trigger_time=600,
parameters={"message": "Child detected in vehicle. Check immediately."}
))

return actions

def _assess_cabin_condition(self, temp: float) -> CabinCondition:
"""评估车内环境状态"""
if temp >= self.DANGER_TEMP:
return CabinCondition.DANGER
elif temp >= self.WARNING_TEMP:
return CabinCondition.WARNING
else:
return CabinCondition.NORMAL


# 测试代码
if __name__ == "__main__":
controller = CPDInterventionController()

print("=== CPD干预测试 ===")

# 测试场景
scenarios = [
{"temp": 30, "duration": 600, "desc": "正常温度,10分钟"},
{"temp": 38, "duration": 300, "desc": "警告温度,5分钟"},
{"temp": 42, "duration": 60, "desc": "危险温度,1分钟"},
]

for scenario in scenarios:
print(f"\n场景: {scenario['desc']}")
print(f" 温度: {scenario['temp']}°C, 持续: {scenario['duration']}秒")

actions = controller.update(
child_detected=True,
detection_duration=scenario['duration'],
cabin_temp=scenario['temp']
)

print(f" 干预动作:")
for action in actions:
print(f" - {action.action_type}: {action.parameters}")

IMS开发部署建议

硬件配置

方案 传感器 成本 检测能力
基础版 1个mmWave雷达 $50-100 呼吸/运动检测
标准版 2个mmWave雷达 $100-200 全覆盖 + 精确定位
高端版 雷达 + 摄像头 $200-400 融合检测 + 视觉确认

软件架构

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
┌─────────────────────────────────────────────────────────────┐
│ CPD软件架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ mmWave雷达 │ │ 摄像头 │ │ 温度传感器 │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └──────────────────┼───────────────────┘ │
│ ↓ │
│ ┌────────────────┐ │
│ │ 传感器融合层 │ │
│ └────────┬───────┘ │
│ ↓ │
│ ┌────────────────┐ │
│ │ CPD检测算法 │ │
│ │ - 呼吸检测 │ │
│ │ - 运动检测 │ │
│ │ - 乘员分类 │ │
│ └────────┬───────┘ │
│ ↓ │
│ ┌────────────────┐ │
│ │ 警告控制器 │ │
│ │ - 时序管理 │ │
│ │ - 状态机 │ │
│ └────────┬───────┘ │
│ ↓ │
│ ┌────────────────┐ │
│ │ 干预执行器 │ │
│ │ - 空调控制 │ │
│ │ - 门锁控制 │ │
│ │ - 通知服务 │ │
│ └────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

测试清单

测试项 通过条件
呼吸检测 检测到0.2-0.7Hz信号
儿童分类 正确识别≤6岁儿童
15秒警告 锁车后15秒内触发
毛毯覆盖 能穿透覆盖物检测
温度干预 >40°C立即启动空调
通知发送 APP收到警告通知

总结

维度 Euro NCAP 2026要求
检测方法 直接检测(呼吸/运动/心跳)
检测范围 所有座椅、脚坑、驾驶座
检测目标 ≤6岁儿童
警告时限 锁车后15秒
升级警告 90秒后,每分钟一次
干预措施 空调/解锁/通知
满分条件 检测+干预

发布时间: 2026-04-22
标签: #Euro NCAP #CPD #儿童检测 #mmWave雷达 #IMS


Euro NCAP 2026 CPD儿童存在检测完整实施指南
https://dapalm.com/2026/04/22/2026-04-22-euro-ncap-cpd-implementation-guide/
作者
Mars
发布于
2026年4月22日
许可协议