Euro NCAP 2026儿童存在检测(CPD)协议详解:从检测到干预的完整要求

Euro NCAP 2026儿童存在检测(CPD)协议详解:从检测到干预的完整要求

协议背景

最新版本: Euro NCAP CPD Test and Assessment Protocol v1.2 / v0.9 (2025年3月)
适用时间: 2023-2025(过渡),2026年强制
评估分数: 最高5分(纳入Occupant Monitoring类别)


核心要求:直接检测 vs 间接检测

Euro NCAP明确区分

检测方式 2023-2024 2025+ 2026+
间接检测 可得分 可得分 不得分
直接检测 可得分 可得分 必须

间接检测(不再符合要求):

  • 车门开关逻辑
  • 座椅压力传感器
  • 重量感应

直接检测(必须):

  • 雷达检测呼吸/心跳
  • 摄像头检测运动
  • 超声波/毫米波传感

检测场景要求

必须覆盖的场景

场景 描述 检测时限
场景A 儿童被遗忘在锁车内 锁车后15秒内触发
场景B 儿童自行进入未锁车辆 关门后10分钟内触发

必须覆盖的区域

1
2
3
4
5
6
7
8
9
车辆内部检测覆盖区域:

✅ 必须覆盖:
• 所有座椅位置(包括可选/可拆卸座椅)
• 脚部空间
• 驾驶员座椅

❌ 可排除:
• 行李舱/后备箱

目标对象要求

  • 年龄范围: 0-6岁儿童
  • 必须检测: 呼吸、运动、心跳任一生理信号

警告时序要求(严格规范)

锁车场景时序

1
2
3
4
5
6
7
T=0s    车辆锁定

T≤15s 检测到儿童 → 触发初始警告

T≤15s+90s 升级警告开始

T≤15s+90s+20min 持续周期警告(每分钟一次)

未锁车场景时序

1
2
3
4
5
T=0s    车门关闭(未锁)

T≤10min 检测到儿童 → 触发初始警告

T≤10min+90s 升级警告开始

警告形式要求

警告类型 最小时长 最小强度 可中断性
初始警告 3秒 可在车外感知 可延迟一次(最多10分钟)
升级警告 15秒/次 视觉+听觉 不可中断
周期警告 每1分钟重复 持续≥15秒 不可中断
总时长 ≥20分钟 - -

警告内容要求

初始警告:

  • 声音信号(鸣笛/蜂鸣)
  • 视觉信号(闪烁灯光)

升级警告:

  • 声音信号
  • 灯光闪烁
  • 车内显示屏显示”检查座椅”等信息(需从车外可见)

可选增强通道:

  • 手机App推送
  • 钥匙震动/蜂鸣
  • 紧急联系人通知

干预措施要求(额外得分)

基础检测 = 0分

仅检测+警告无法获得满分。

干预措施 = 额外分数

干预措施 技术要求 得分
温度管理 触发空调维持安全温度 +1分
解锁车门 自动解锁允许救援 +1分
远程通知 App/联系人告警 +1分

干预时机要求

1
2
3
4
干预触发条件(满足任一):
1. 锁车后10分钟内
2. 首次升级警告后5分钟内
3. 车内温度达到危险水平 → 立即触发

技术实现方案

方案1:60GHz毫米波雷达(推荐)

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
import numpy as np
from dataclasses import dataclass
from typing import Optional
from scipy import signal

@dataclass
class CPDDetection:
"""儿童存在检测结果"""
detected: bool
confidence: float
vital_signs: dict # 呼吸率、心率
position: tuple # (row, seat)
motion_level: float

class MillimeterWaveCPD:
"""
60GHz毫米波雷达CPD检测

硬件:TI IWR6843AOP / ARIA Hydrogen

核心原理:
1. 发射FMCW信号
2. 接收反射信号
3. 分离静态和动态分量
4. 从动态分量提取呼吸/心跳频率
"""

def __init__(
self,
sample_rate: int = 100,
fft_size: int = 2048,
breath_freq_range: tuple = (0.1, 0.5), # Hz (6-30次/分)
heart_freq_range: tuple = (1.0, 2.0) # Hz (60-120次/分)
):
self.sample_rate = sample_rate
self.fft_size = fft_size
self.breath_freq_range = breath_freq_range
self.heart_freq_range = heart_freq_range

def process_radar_data(
self,
adc_data: np.ndarray # (N_samples, N_rx)
) -> CPDDetection:
"""
处理雷达ADC数据

Args:
adc_data: 雷达ADC采样数据

Returns:
CPDDetection: 检测结果
"""
# 1. 距离-多普勒处理
range_doppler = self._compute_range_doppler(adc_data)

# 2. 静态杂波抑制
range_doppler_clean = self._remove_static_clutter(range_doppler)

# 3. 检测运动目标
motion_map = self._detect_motion(range_doppler_clean)

# 4. 提取生命体征
vital_signs = self._extract_vital_signs(adc_data)

# 5. 综合判断
detected = (
motion_map['total_motion'] > 0.1 or
vital_signs['breath_rate'] > 0
)

return CPDDetection(
detected=detected,
confidence=self._compute_confidence(motion_map, vital_signs),
vital_signs=vital_signs,
position=self._locate_target(range_doppler_clean),
motion_level=motion_map['total_motion']
)

def _compute_range_doppler(self, adc_data: np.ndarray) -> np.ndarray:
"""计算距离-多普勒图"""
# 距离FFT
range_fft = np.fft.fft(adc_data, n=self.fft_size, axis=0)

# 多普勒FFT
range_doppler = np.fft.fftshift(
np.fft.fft(range_fft, axis=0),
axes=0
)

return np.abs(range_doppler)

def _remove_static_clutter(self, range_doppler: np.ndarray) -> np.ndarray:
"""静态杂波抑制(移除零多普勒分量)"""
center = range_doppler.shape[0] // 2
# 移除中心(零多普勒)附近的能量
range_doppler[center-5:center+5] *= 0.01
return range_doppler

def _detect_motion(self, range_doppler: np.ndarray) -> dict:
"""检测运动目标"""
# 计算总运动能量
total_energy = np.sum(range_doppler)
motion_threshold = 0.05 * total_energy

motion_map = (range_doppler > motion_threshold).astype(float)
total_motion = np.sum(motion_map) / range_doppler.size

return {
'motion_map': motion_map,
'total_motion': total_motion
}

def _extract_vital_signs(self, adc_data: np.ndarray) -> dict:
"""
提取生命体征(呼吸率、心率)

原理:胸腔微动调制雷达回波相位
- 呼吸:胸腔起伏约1-5mm,频率0.1-0.5Hz
- 心跳:胸壁微动约0.2-0.5mm,频率1-2Hz
"""
# 提取相位信号(假设单目标)
phase = np.angle(adc_data[:, 0])

# 解缠绕
phase_unwrapped = np.unwrap(phase)

# 去趋势
phase_detrended = signal.detrend(phase_unwrapped)

# FFT分析
freq = np.fft.fftfreq(len(phase_detrended), 1/self.sample_rate)
spectrum = np.abs(np.fft.fft(phase_detrended))

# 只取正频率
pos_freq = freq[:len(freq)//2]
pos_spectrum = spectrum[:len(spectrum)//2]

# 呼吸频率检测
breath_mask = (pos_freq >= self.breath_freq_range[0]) & \
(pos_freq <= self.breath_freq_range[1])
if np.any(breath_mask):
breath_peak_idx = np.argmax(pos_spectrum[breath_mask])
breath_freq = pos_freq[breath_mask][breath_peak_idx]
breath_rate = breath_freq * 60 # 转换为次/分钟
else:
breath_rate = 0

# 心跳频率检测
heart_mask = (pos_freq >= self.heart_freq_range[0]) & \
(pos_freq <= self.heart_freq_range[1])
if np.any(heart_mask):
heart_peak_idx = np.argmax(pos_spectrum[heart_mask])
heart_freq = pos_freq[heart_mask][heart_peak_idx]
heart_rate = heart_freq * 60 # 转换为次/分钟
else:
heart_rate = 0

return {
'breath_rate': breath_rate,
'heart_rate': heart_rate,
'phase_signal': phase_detrended
}

def _compute_confidence(self, motion_map: dict, vital_signs: dict) -> float:
"""计算检测置信度"""
# 综合运动和生命体征判断
motion_score = min(motion_map['total_motion'] / 0.5, 1.0)

# 呼吸检测是关键指标
breath_score = 1.0 if 10 < vital_signs['breath_rate'] < 40 else 0.5
heart_score = 1.0 if 60 < vital_signs['heart_rate'] < 160 else 0.5

confidence = 0.3 * motion_score + 0.4 * breath_score + 0.3 * heart_score

return confidence

def _locate_target(self, range_doppler: np.ndarray) -> tuple:
"""定位目标位置"""
# 找到能量最大的位置
max_idx = np.unravel_index(np.argmax(range_doppler), range_doppler.shape)

# 转换为座椅位置(简化)
row = max_idx[0] // (range_doppler.shape[0] // 3) # 前/中/后排
seat = max_idx[1] // (range_doppler.shape[1] // 3) # 左/中/右

return (row, seat)


# 测试代码
if __name__ == "__main__":
cpd = MillimeterWaveCPD(sample_rate=100, fft_size=2048)

# 模拟雷达数据(包含呼吸信号)
t = np.linspace(0, 5, 500) # 5秒数据
breath_signal = 0.5 * np.sin(2 * np.pi * 0.25 * t) # 15次/分钟呼吸
heart_signal = 0.1 * np.sin(2 * np.pi * 1.2 * t) # 72次/分钟心跳
noise = 0.05 * np.random.randn(len(t))

# 模拟ADC数据(相位调制)
phase = breath_signal + heart_signal + noise
adc_data = np.exp(1j * 2 * np.pi * phase).reshape(-1, 1)

# 检测
result = cpd.process_radar_data(adc_data)

print("=" * 60)
print("CPD检测结果")
print("=" * 60)
print(f"检测到儿童: {result.detected}")
print(f"置信度: {result.confidence:.2f}")
print(f"呼吸率: {result.vital_signs['breath_rate']:.1f} 次/分钟")
print(f"心率: {result.vital_signs['heart_rate']:.1f} 次/分钟")
print(f"运动水平: {result.motion_level:.3f}")
print(f"位置: 第{result.position[0]+1}排, 第{result.position[1]+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
import cv2
import numpy as np

class CameraCPD:
"""
基于摄像头的儿童存在检测

原理:检测微小运动(呼吸引起的胸腹起伏)
技术:光流法 / 帧差法

局限:
- 需要充足光照(或红外补光)
- 遮挡影响大
- 对静态儿童检测困难
"""

def __init__(
self,
motion_threshold: float = 0.01,
history_frames: int = 30
):
self.motion_threshold = motion_threshold
self.history_frames = history_frames
self.prev_frame = None
self.motion_history = []

def detect(self, frame: np.ndarray) -> dict:
"""
检测儿童存在

Args:
frame: 输入图像帧

Returns:
dict: 检测结果
"""
# 灰度化
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# 高斯模糊降噪
gray = cv2.GaussianBlur(gray, (21, 21), 0)

if self.prev_frame is None:
self.prev_frame = gray
return {'detected': False, 'confidence': 0.0}

# 帧差法检测运动
frame_diff = cv2.absdiff(self.prev_frame, gray)

# 阈值化
_, thresh = cv2.threshold(frame_diff, 25, 255, cv2.THRESH_BINARY)

# 计算运动比例
motion_ratio = np.sum(thresh > 0) / thresh.size

# 更新历史
self.motion_history.append(motion_ratio)
if len(self.motion_history) > self.history_frames:
self.motion_history.pop(0)

# 累积运动判断
if len(self.motion_history) >= self.history_frames:
avg_motion = np.mean(self.motion_history)
detected = avg_motion > self.motion_threshold
confidence = min(avg_motion / (self.motion_threshold * 3), 1.0)
else:
detected = False
confidence = 0.0

self.prev_frame = gray

return {
'detected': detected,
'confidence': confidence,
'motion_level': motion_ratio
}

IMS开发建议

1. 传感器选型

传感器 优势 劣势 推荐度
60GHz毫米波雷达 穿透遮挡、精准测距、隐私友好 成本较高 ⭐⭐⭐⭐⭐
红外摄像头 成本低、可复用DMS 光照敏感、遮挡影响大 ⭐⭐⭐
超声波 成本极低 精度低、易受干扰 ⭐⭐

2. 部署位置

1
2
3
4
5
6
7
8
9
推荐雷达安装位置:

方案A(全景覆盖):
├── 后视镜背面(覆盖前排)
├── B柱上方(覆盖后排)
└── 后排顶棚中央(覆盖后排座椅)

方案B(最小配置):
└── 后排顶棚中央(单雷达覆盖)

3. 算法集成架构

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
class CPDSystem:
"""
完整CPD系统架构

集成:检测 + 警告 + 干预
"""

def __init__(self):
self.radar_detector = MillimeterWaveCPD()
self.camera_detector = CameraCPD()
self.alert_controller = AlertController()
self.intervention_controller = InterventionController()

self.state = 'IDLE'
self.detection_start_time = None

def update(self, radar_data, camera_frame, vehicle_state):
"""主循环更新"""
# 多传感器融合
radar_result = self.radar_detector.process_radar_data(radar_data)
camera_result = self.camera_detector.detect(camera_frame)

# 融合判断
child_detected = (
radar_result.detected or
(camera_result['detected'] and camera_result['confidence'] > 0.7)
)

# 状态机
if child_detected:
if self.state == 'IDLE':
self.state = 'DETECTED'
self.detection_start_time = time.time()
elif self.state == 'DETECTED':
elapsed = time.time() - self.detection_start_time
self._handle_warning(elapsed, vehicle_state)
else:
if self.state != 'IDLE':
self._reset()

def _handle_warning(self, elapsed: float, vehicle_state: dict):
"""处理警告逻辑"""
if vehicle_state['locked']:
# 锁车场景:15秒内触发
if elapsed >= 15:
self.alert_controller.trigger_initial_warning()

if elapsed >= 105: # 15 + 90
self.alert_controller.trigger_escalation()
self.intervention_controller.check_temperature()
else:
# 未锁场景:10分钟内触发
if elapsed >= 600:
self.alert_controller.trigger_initial_warning()

测试验证清单

Euro NCAP CPD测试工具

测试项 测试工具 通过条件
新生儿检测 新生儿假人 15秒内触发
1岁儿童检测 1岁假人 15秒内触发
3岁儿童检测 3岁假人 15秒内触发
6岁儿童检测 6岁假人 15秒内触发
遮挡场景 毛毯覆盖假人 仍能检测
安全覆盖 空座 不触发
警告时序 计时器 符合协议要求

参考资源

  1. Euro NCAP CPD Protocol v1.2: https://www.euroncap.com/media/79888/
  2. TI 60GHz Radar CPD Solution: https://www.ti.com/document-viewer/lit/html/SSZT046
  3. Smart Eye CPD Blog: https://smarteye.se/blog/what-euro-ncap-2026-says-about-child-presence-detection/

本文详细解读Euro NCAP CPD协议要求,提供可执行代码实现。