CPD 儿童检测雷达融合方案:从毫米波雷达到摄像头集成

前言

儿童遗留车内检测(Child Presence Detection, CPD)是 Euro NCAP 2026 的强制要求。2025 年起,北美市场也将强制配备 CPD 系统。

本文分析主流 CPD 技术方案,重点介绍 60GHz 毫米波雷达与摄像头融合方案。


一、CPD 技术背景

1.1 问题严重性

地区 年度儿童车内死亡数 原因
美国 38 例/年 中暑(被遗忘在车内)
欧洲 估计 50+ 例/年 多国数据未统一统计
中国 估计 100+ 例/年 夏季高温季节高发

1.2 法规时间线

法规/标准 地区 时间线
Euro NCAP CPD 评分 欧洲 2026 年起
US Hot Cars Act 美国 2025 年起新车强制
UNECE R16 修订 全球 2027 年预期

1.3 检测挑战

挑战 描述
遮挡 儿童被毯子、衣物覆盖
姿势变化 儿童可能蜷缩、躺卧
环境干扰 阳光直射、高温
误报控制 避免频繁误报导致用户关闭

二、技术方案对比

2.1 主流方案

方案 原理 优点 缺点 成本
60GHz 雷达 检测呼吸/心跳微动 穿透性强、全天候 分辨率低、成本高 $50-80
IR 摄像头 图像识别 分辨率高、成本低 受遮挡影响 $20-40
压力传感器 座椅压力变化 成本低、简单 只能检测座椅 $10-20
UWB 雷达 超宽带脉冲 精度高、功耗低 成本高 $60-100
融合方案 雷达 + 摄像头 互补优势 复杂度高 $70-120

2.2 方案选择建议

应用场景 推荐方案 原因
经济型车型 IR 摄像头 成本优先
中高端车型 60GHz 雷达 可靠性优先
Euro NCAP 满分 融合方案 覆盖所有场景

三、60GHz 毫米波雷达方案

3.1 技术原理

60GHz 频段优势:

特性 60GHz 24GHz(传统)
波长 5mm 12.5mm
分辨率
穿透性 强(穿透毯子) 较强
功耗
体积

检测原理:

1
人体呼吸 → 胸腔微动(1-5mm)→ 雷达回波相位变化 → 信号处理 → 检测呼吸频率

3.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
"""
60GHz 雷达呼吸检测算法

基于 TI IWR6843AOP 芯片
"""

import numpy as np
from scipy import signal
from typing import Tuple, List

class RadarBreathDetector:
"""
雷达呼吸检测器

核心原理:
1. 提取雷达回波相位
2. 滤除身体大运动
3. 提取呼吸频率成分
4. 检测呼吸信号
"""

def __init__(
self,
sample_rate: float = 20, # Hz
breath_freq_range: Tuple[float, float] = (0.2, 0.8), # Hz (12-48 次/分)
child_breath_range: Tuple[float, float] = (0.5, 1.2), # Hz (30-72 次/分)
):
self.sample_rate = sample_rate
self.breath_freq_range = breath_freq_range
self.child_breath_range = child_breath_range

def extract_phase(
self,
radar_data: np.ndarray
) -> np.ndarray:
"""
提取雷达回波相位

Args:
radar_data: (N, M) 雷达数据,N=帧数,M=天线数

Returns:
phase: (N,) 相位序列
"""
# 取第一根天线(或所有天线平均)
if len(radar_data.shape) > 1:
radar_signal = radar_data[:, 0]
else:
radar_signal = radar_data

# 计算相位
phase = np.angle(radar_signal)

# 解卷绕(unwrap)
phase = np.unwrap(phase)

return phase

def filter_motion(
self,
phase: np.ndarray,
cutoff_freq: float = 2.0
) -> np.ndarray:
"""
滤除身体大运动

使用高通滤波器去除低频运动成分

Args:
phase: 相位序列
cutoff_freq: 截止频率 (Hz)

Returns:
filtered_phase: 滤波后相位
"""
# 设计高通滤波器
nyquist = self.sample_rate / 2
normalized_cutoff = cutoff_freq / nyquist

# Butterworth 高通滤波器
b, a = signal.butter(4, normalized_cutoff, btype='high')

# 滤波
filtered_phase = signal.filtfilt(b, a, phase)

return filtered_phase

def detect_breath_freq(
self,
phase: np.ndarray
) -> Tuple[float, float]:
"""
检测呼吸频率

Args:
phase: 相位序列

Returns:
breath_freq: 呼吸频率 (Hz)
confidence: 置信度
"""
# 功率谱密度
freqs, psd = signal.periodogram(phase, fs=self.sample_rate)

# 在呼吸频率范围内找峰值
mask = (freqs >= self.breath_freq_range[0]) & (freqs <= self.breath_freq_range[1])
breath_freqs = freqs[mask]
breath_psd = psd[mask]

if len(breath_psd) == 0:
return 0.0, 0.0

# 找最大峰值
peak_idx = np.argmax(breath_psd)
breath_freq = breath_freqs[peak_idx]

# 置信度 = 峰值功率 / 总功率
total_power = np.sum(psd)
peak_power = breath_psd[peak_idx]
confidence = peak_power / total_power if total_power > 0 else 0

return breath_freq, confidence

def classify_occupant(
self,
breath_freq: float
) -> Tuple[str, float]:
"""
分类乘员类型(成人/儿童)

Args:
breath_freq: 呼吸频率 (Hz)

Returns:
occupant_type: 乘员类型
probability: 概率
"""
# 成人呼吸频率:12-20 次/分 (0.2-0.33 Hz)
# 儿童呼吸频率:20-40 次/分 (0.33-0.67 Hz)
# 婴儿呼吸频率:30-60 次/分 (0.5-1.0 Hz)

if breath_freq < 0.2:
return "unknown", 0.5
elif breath_freq < 0.33:
return "adult", 0.8
elif breath_freq < 0.5:
# 成人/儿童边界
return "adult/child", 0.6
elif breath_freq < 0.8:
return "child", 0.85
else:
return "infant", 0.9

def detect(
self,
radar_data: np.ndarray
) -> dict:
"""
综合检测

Args:
radar_data: 雷达数据

Returns:
result: 检测结果
"""
# 1. 提取相位
phase = self.extract_phase(radar_data)

# 2. 滤除大运动
filtered_phase = self.filter_motion(phase)

# 3. 检测呼吸频率
breath_freq, confidence = self.detect_breath_freq(filtered_phase)

# 4. 分类乘员
occupant_type, prob = self.classify_occupant(breath_freq)

# 5. 计算呼吸率
breath_rate = breath_freq * 60 # 次/分

return {
'breath_detected': confidence > 0.3,
'breath_freq_hz': breath_freq,
'breath_rate_per_min': breath_rate,
'confidence': confidence,
'occupant_type': occupant_type,
'occupant_prob': prob,
'is_child': occupant_type in ['child', 'infant']
}


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

# 创建检测器
detector = RadarBreathDetector()

# 模拟雷达数据(儿童呼吸)
n_samples = 300 # 15秒 @ 20Hz
t = np.arange(n_samples) / 20
breath_freq = 0.6 # 36次/分(儿童)

# 呼吸信号 + 噪声
breath_signal = 0.5 * np.sin(2 * np.pi * breath_freq * t)
noise = 0.1 * np.random.randn(n_samples)
phase = breath_signal + noise

# 转换为复数(雷达数据)
radar_data = np.exp(1j * phase * 10) # 放大相位变化

# 检测
result = detector.detect(radar_data)

print("检测结果:")
print(f" 检测到呼吸: {result['breath_detected']}")
print(f" 呼吸频率: {result['breath_rate_per_min']:.1f} 次/分")
print(f" 置信度: {result['confidence']:.2f}")
print(f" 乘员类型: {result['occupant_type']}")
print(f" 是否儿童: {result['is_child']}")

3.3 硬件方案

主流芯片:

厂商 芯片型号 特点
Texas Instruments IWR6843AOP 4发4收,集成天线,AOP封装
Infineon BGT60ATR24C 低功耗,紧凑封装
CEVA RivieraWaves UWB UWB 方案,精度高

典型配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# TI IWR6843AOP 配置
Radar:
chip: IWR6843AOP
frequency: 60-64 GHz
antennas: 4 TX, 4 RX
range_resolution: 4 cm
velocity_resolution: 0.3 m/s
field_of_view:
azimuth: 120°
elevation: 60°

Processing:
platform: TDA4VM or external MCU
frame_rate: 20 Hz
detection_range: 0.3-3 m

四、摄像头方案

4.1 技术原理

检测方式 描述 准确率
YOLO 目标检测 直接检测儿童 85-90%
姿态估计 检测人体姿态 80-85%
面部识别 检测面部特征 75-80%

4.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
"""
摄像头 CPD 检测算法

结合目标检测和姿态估计
"""

import numpy as np
from typing import List, Tuple

class CameraCPDDetector:
"""
摄像头儿童检测器

检测流程:
1. 目标检测(YOLO)
2. 年龄/体型估计
3. 姿态分析
4. 综合判断
"""

def __init__(self):
# 年龄分类阈值(基于体型比例)
self.height_ratio_child = 0.7 # 相对成人高度
self.head_body_ratio_child = 0.25 # 头身比(儿童较大)

def detect_occupants(
self,
image: np.ndarray,
detections: List[dict]
) -> List[dict]:
"""
检测乘员

Args:
image: 输入图像
detections: 目标检测结果

Returns:
occupants: 乘员信息列表
"""
occupants = []

for det in detections:
# 提取边界框
x1, y1, x2, y2 = det['bbox']
width = x2 - x1
height = y2 - y1

# 1. 体型比例分析
aspect_ratio = height / width if width > 0 else 0

# 2. 头身比估计(简化:使用边界框比例)
head_height = height * 0.15 # 假设头部占 15%
head_body_ratio = head_height / height if height > 0 else 0

# 3. 年龄估计
is_child_likelihood = 0.0

# 基于体型
if aspect_ratio < 1.2: # 儿童体型较圆润
is_child_likelihood += 0.3

# 基于高度(相对图像高度)
img_height = image.shape[0]
height_ratio = height / img_height
if height_ratio < 0.4: # 相对较小
is_child_likelihood += 0.3

# 基于头身比
if head_body_ratio > 0.2:
is_child_likelihood += 0.2

# 4. 综合判断
is_child = is_child_likelihood > 0.5

occupants.append({
'bbox': det['bbox'],
'is_child': is_child,
'child_likelihood': is_child_likelihood,
'aspect_ratio': aspect_ratio,
'height_ratio': height_ratio
})

return occupants

def check_seat_position(
self,
occupant: dict,
seat_zones: dict
) -> str:
"""
检查乘员座椅位置

Args:
occupant: 乘员信息
seat_zones: 座椅区域定义

Returns:
seat_position: 座椅位置
"""
bbox = occupant['bbox']
center_x = (bbox[0] + bbox[2]) / 2
center_y = (bbox[1] + bbox[3]) / 2

for seat_name, zone in seat_zones.items():
if (zone['x1'] <= center_x <= zone['x2'] and
zone['y1'] <= center_y <= zone['y2']):
return seat_name

return "unknown"

4.3 摄像头配置

参数 要求
类型 IR(红外)或 RGB-IR
分辨率 ≥1280×720
视场角 120°(覆盖后排)
帧率 ≥15 fps
位置 车顶中央或后视镜

五、融合方案

5.1 融合架构

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
┌────────────────────────────────────────────────┐
│ CPD 融合系统架构 │
├────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 60GHz雷达 │ │ IR摄像头 │ │
│ └─────┬────┘ └─────┬────┘ │
│ │ │ │
│ v v │
│ ┌──────────┐ ┌──────────┐ │
│ │ 呼吸检测 │ │ 目标检测 │ │
│ │ 乘员分类 │ │ 年龄估计 │ │
│ └─────┬────┘ └─────┬────┘ │
│ │ │ │
│ └──────────┬──────────┘ │
│ v │
│ ┌──────────────┐ │
│ │ 融合决策模块 │ │
│ └───────┬──────┘ │
│ v │
│ ┌──────────────┐ │
│ │ 报警/通知 │ │
│ └──────────────┘ │
│ │
└────────────────────────────────────────────────┘

5.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
"""
雷达 + 摄像头融合算法
"""

from typing import Dict, List
from dataclasses import dataclass

@dataclass
class FusionResult:
"""融合结果"""
is_child_present: bool
confidence: float
location: str
detection_sources: List[str]
breath_rate: float
is_covered: bool

class CPDFusion:
"""
CPD 融合检测器

融合策略:
1. 雷达检测到呼吸 + 摄像头未检测到人 → 被覆盖的儿童
2. 雷达检测到儿童呼吸 + 摄像头检测到儿童 → 高置信度儿童
3. 仅摄像头检测到儿童 → 需要验证
4. 仅雷达检测到呼吸 → 可能是儿童或宠物
"""

def __init__(self):
self.radar_weight = 0.6
self.camera_weight = 0.4

def fuse(
self,
radar_result: Dict,
camera_result: Dict
) -> FusionResult:
"""
融合雷达和摄像头结果

Args:
radar_result: 雷达检测结果
camera_result: 摄像头检测结果

Returns:
fusion_result: 融合结果
"""
# 提取关键信息
radar_breath = radar_result.get('breath_detected', False)
radar_is_child = radar_result.get('is_child', False)
radar_confidence = radar_result.get('confidence', 0)
breath_rate = radar_result.get('breath_rate_per_min', 0)

camera_occupants = camera_result.get('occupants', [])
camera_has_child = any(o['is_child'] for o in camera_occupants)
camera_confidence = max(
[o['child_likelihood'] for o in camera_occupants],
default=0
)

# 融合判断
detection_sources = []

# Case 1: 雷达检测到呼吸,摄像头未检测到人
if radar_breath and len(camera_occupants) == 0:
# 可能是被覆盖的儿童
is_child_present = True
confidence = radar_confidence * 0.8 # 降低置信度
is_covered = True
detection_sources.append('radar_breath')

# Case 2: 雷达和摄像头都检测到儿童
elif radar_is_child and camera_has_child:
is_child_present = True
confidence = (
radar_confidence * self.radar_weight +
camera_confidence * self.camera_weight
)
is_covered = False
detection_sources.extend(['radar_child', 'camera_child'])

# Case 3: 仅摄像头检测到儿童
elif camera_has_child and not radar_breath:
# 需要验证(可能是误检)
is_child_present = camera_confidence > 0.7
confidence = camera_confidence * 0.6
is_covered = False
detection_sources.append('camera_only')

# Case 4: 仅雷达检测到呼吸(无儿童特征)
elif radar_breath and not camera_has_child:
# 可能是成人或宠物
is_child_present = radar_is_child
confidence = radar_confidence * 0.5
is_covered = True
detection_sources.append('radar_breath_only')

# Case 5: 都未检测到
else:
is_child_present = False
confidence = 0.0
is_covered = False

# 确定位置
location = self._determine_location(camera_occupants)

return FusionResult(
is_child_present=is_child_present,
confidence=confidence,
location=location,
detection_sources=detection_sources,
breath_rate=breath_rate,
is_covered=is_covered
)

def _determine_location(self, occupants: List[Dict]) -> str:
"""确定儿童位置"""
for occ in occupants:
if occ['is_child']:
# 根据边界框位置判断
bbox = occ['bbox']
center_x = (bbox[0] + bbox[2]) / 2

if center_x < 0.33:
return "left_rear"
elif center_x < 0.67:
return "center_rear"
else:
return "right_rear"

return "unknown"


# 测试
if __name__ == "__main__":
fusion = CPDFusion()

# 模拟场景:后排儿童被毯子覆盖
radar_result = {
'breath_detected': True,
'is_child': True,
'confidence': 0.75,
'breath_rate_per_min': 36
}

camera_result = {
'occupants': [] # 摄像头未检测到(被覆盖)
}

result = fusion.fuse(radar_result, camera_result)

print("融合结果:")
print(f" 检测到儿童: {result.is_child_present}")
print(f" 置信度: {result.confidence:.2f}")
print(f" 位置: {result.location}")
print(f" 呼吸率: {result.breath_rate} 次/分")
print(f" 是否被覆盖: {result.is_covered}")
print(f" 检测来源: {result.detection_sources}")

5.3 报警策略

检测结果 系统响应
置信度 >80% 立即报警(车外喇叭 + App 通知)
置信度 50-80% 车内警告 + 延迟 30 秒确认
置信度 <50% 记录日志 + 监控

六、主流方案商

6.1 厂商对比

厂商 方案 芯片 特点
Magna 雷达+摄像头融合 TI IWR6843 全球首发融合方案
IEE VitaSense 雷达 自研 UCD 专业方案
TMYTEK 60GHz 雷达 自研 CES 2024 展示
CEVA UWB 雷达 RivieraWaves 精度高、功耗低

6.2 集成案例

车企 车型 方案 时间
Volkswagen 新款 SUV 雷达 CPD 2025 年
Hyundai Genesis 系列 摄像头 CPD 2024 年
Tesla Model Y 摄像头 CPD 2023 年

七、IMS 开发建议

7.1 功能优先级

优先级 功能 Euro NCAP 得分
P0 基础 CPD(雷达) 3 分
P1 融合方案 5 分(满分)
P2 座椅位置识别 加分项

7.2 开发路线

Phase 1(基础合规):

  • 集成 60GHz 雷达
  • 实现呼吸检测
  • 实现儿童分类

Phase 2(融合优化):

  • 添加 IR 摄像头
  • 实现融合算法
  • 优化误报率

Phase 3(体验升级):

  • 多座椅检测
  • 宠物识别
  • App 远程通知

总结

CPD 儿童检测的关键要点:

  1. 技术选择: 60GHz 雷达方案穿透性强,适合遮挡场景
  2. 融合优势: 雷达 + 摄像头互补,覆盖所有场景
  3. Euro NCAP 要求: 检测率 ≥95%,误报率 ≤1次/100h
  4. IMS 建议: 短期雷达方案,中期融合方案

参考来源:

  1. Euro NCAP 2026 Protocols
  2. TI IWR6843AOP Datasheet
  3. Magna CPD Press Release, July 2025
  4. CEVA UWB Radar Platform, March 2023

CPD 儿童检测雷达融合方案:从毫米波雷达到摄像头集成
https://dapalm.com/2026/04/20/2026-04-20-cpd-radar-fusion/
作者
Mars
发布于
2026年4月20日
许可协议