TI 60GHz毫米波雷达CPD方案:满足Euro NCAP 2026的完整指南

TI 60GHz毫米波雷达CPD方案:满足Euro NCAP 2026的完整指南

技术背景

Texas Instruments推出的60GHz毫米波雷达方案是首个明确满足Euro NCAP 2026 CPD要求的芯片级解决方案。


为什么选择60GHz?

频段对比

频段 波长 穿透力 精度 成本
24GHz 12.5mm
60GHz 5mm
77GHz 3.9mm 最高

60GHz优势

  1. 波长适中: 能穿透毛毯、衣物,同时保持足够分辨率
  2. 多普勒敏感: 精确检测呼吸(0.1-0.5Hz)和心跳(1-2Hz)
  3. 成本可控: 相比77GHz更具成本优势
  4. 法规友好: 全球通用ISM频段

TI IWR6843AOP芯片

核心规格

参数 规格
频段 60-64 GHz
天线 3发4收(片上天线AOP)
带宽 4 GHz
距离分辨率 4 cm
速度分辨率 0.04 m/s
角度分辨率 15°(水平)
功耗 <2W
封装 10.4mm × 10.4mm BGA

开发套件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
TI CPD开发套件:

IWR6843ISK-ODS
├── IWR6843AOP芯片
├── 60GHz天线阵列
├── USB供电/数据接口
├── LEDs(状态指示)
└── 尺寸: 85mm × 55mm

配套软件:
├── mmWave SDK 3.x
├── CPD Demo应用
├── ROS驱动
└── 可视化工具

CPD检测算法

完整实现

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

@dataclass
class CPDTarget:
"""CPD检测目标"""
range_idx: int # 距离索引
doppler_idx: int # 多普勒索引
snr: float # 信噪比
breath_rate: float # 呼吸率(次/分)
heart_rate: float # 心率(次/分)
confidence: float # 置信度
position: Tuple[float, float, float] # (x, y, z)米

class IWR6843CPD:
"""
TI IWR6843 CPD处理器

完整处理流程:
1. ADC数据采集
2. 距离-多普勒处理
3. 静态目标检测
4. 生命体征提取
5. 儿童存在判断
"""

def __init__(
self,
num_tx: int = 3,
num_rx: int = 4,
num_chirps: int = 128,
num_samples: int = 256,
sample_rate: float = 10e6, # 10 MHz
chirp_rate: float = 50e12, # 50 MHz/us
start_freq: float = 60e9 # 60 GHz
):
self.num_tx = num_tx
self.num_rx = num_rx
self.num_chirps = num_chirps
self.num_samples = num_samples
self.sample_rate = sample_rate
self.chirp_rate = chirp_rate
self.start_freq = start_freq

# 计算分辨率
self.range_resolution = self._compute_range_resolution()
self.velocity_resolution = self._compute_velocity_resolution()

print(f"距离分辨率: {self.range_resolution * 100:.2f} cm")
print(f"速度分辨率: {self.velocity_resolution * 100:.2f} cm/s")

def _compute_range_resolution(self) -> float:
"""计算距离分辨率"""
bandwidth = self.chirp_rate * self.num_samples / self.sample_rate
return 3e8 / (2 * bandwidth)

def _compute_velocity_resolution(self) -> float:
"""计算速度分辨率"""
# 60GHz波长
wavelength = 3e8 / self.start_freq
# 假设chirp周期100us
chirp_period = 100e-6
return wavelength / (2 * self.num_chirps * chirp_period)

def process_frame(self, adc_data: np.ndarray) -> List[CPDTarget]:
"""
处理单帧ADC数据

Args:
adc_data: (num_chirps, num_samples, num_rx) 复数ADC数据

Returns:
List[CPDTarget]: 检测到的目标列表
"""
# 1. 距离FFT
range_fft = self._range_fft(adc_data)

# 2. 多普勒FFT
range_doppler = self._doppler_fft(range_fft)

# 3. 静态目标检测(CPD关键:检测静态目标)
static_targets = self._detect_static_targets(range_doppler)

# 4. 生命体征提取
targets = []
for target in static_targets:
vital_signs = self._extract_vital_signs(adc_data, target['range_idx'])

cpd_target = CPDTarget(
range_idx=target['range_idx'],
doppler_idx=target['doppler_idx'],
snr=target['snr'],
breath_rate=vital_signs['breath_rate'],
heart_rate=vital_signs['heart_rate'],
confidence=vital_signs['confidence'],
position=self._compute_position(target['range_idx'])
)

targets.append(cpd_target)

return targets

def _range_fft(self, adc_data: np.ndarray) -> np.ndarray:
"""距离FFT"""
# 对每个chirp和rx做FFT
range_fft = np.fft.fft(adc_data, n=self.num_samples, axis=1)
return range_fft

def _doppler_fft(self, range_fft: np.ndarray) -> np.ndarray:
"""多普勒FFT"""
# 对距离维度做FFT
doppler_fft = np.fft.fftshift(
np.fft.fft(range_fft, n=self.num_chirps, axis=0),
axes=0
)
return np.abs(doppler_fft)

def _detect_static_targets(self, range_doppler: np.ndarray) -> List[dict]:
"""
检测静态目标

CPD关键:静态目标在零多普勒附近
"""
targets = []

# 对所有RX求和
range_doppler_sum = np.sum(range_doppler, axis=2) if range_doppler.ndim > 2 else range_doppler

# 零多普勒切片
zero_doppler_idx = self.num_chirps // 2
range_profile = range_doppler_sum[zero_doppler_idx, :]

# CFAR检测
threshold = self._cfar_threshold(range_profile)

# 找峰值
peaks = np.where(range_profile > threshold)[0]

for peak_idx in peaks:
if 10 < peak_idx < self.num_samples - 10: # 排除近端和远端
snr = range_profile[peak_idx] / np.mean(range_profile)

targets.append({
'range_idx': peak_idx,
'doppler_idx': zero_doppler_idx,
'snr': snr
})

return targets

def _cfar_threshold(self, signal: np.ndarray, guard_cells: int = 4, train_cells: int = 8) -> np.ndarray:
"""CA-CFAR阈值"""
threshold = np.zeros_like(signal)

for i in range(train_cells + guard_cells, len(signal) - train_cells - guard_cells):
# 训练窗口
left = signal[i - train_cells - guard_cells : i - guard_cells]
right = signal[i + guard_cells + 1 : i + guard_cells + train_cells + 1]

# 噪声估计
noise_level = (np.sum(left) + np.sum(right)) / (2 * train_cells)

# 阈值
threshold[i] = noise_level * 3.0 # 3dB阈值因子

return threshold

def _extract_vital_signs(self, adc_data: np.ndarray, range_idx: int) -> dict:
"""
提取生命体征

原理:呼吸和心跳引起微小相位变化
"""
# 提取该距离bin的相位序列
phase_sequence = np.angle(adc_data[:, range_idx, 0])

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

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

# 带通滤波
# 呼吸:0.1-0.5 Hz (6-30次/分)
# 心跳:1.0-2.0 Hz (60-120次/分)

fs = 1.0 / (100e-6 * self.num_chirps) # 帧率

# 呼吸滤波
b_breath, a_breath = signal.butter(4, [0.1, 0.5], btype='band', fs=fs)
breath_signal = signal.filtfilt(b_breath, a_breath, phase_detrended)

# 心跳滤波
b_heart, a_heart = signal.butter(4, [1.0, 2.0], btype='band', fs=fs)
heart_signal = signal.filtfilt(b_heart, a_heart, phase_detrended)

# FFT分析频率
breath_freq, breath_psd = signal.periodogram(breath_signal, fs=fs)
heart_freq, heart_psd = signal.periodogram(heart_signal, fs=fs)

# 找峰值频率
breath_peak_idx = np.argmax(breath_psd)
heart_peak_idx = np.argmax(heart_psd)

breath_rate_hz = breath_freq[breath_peak_idx]
heart_rate_hz = heart_freq[heart_peak_idx]

# 转换为次/分钟
breath_rate = breath_rate_hz * 60
heart_rate = heart_rate_hz * 60

# 计算置信度
confidence = self._compute_vital_confidence(
breath_psd[breath_peak_idx],
heart_psd[heart_peak_idx],
np.max(breath_psd),
np.max(heart_psd)
)

return {
'breath_rate': breath_rate,
'heart_rate': heart_rate,
'confidence': confidence
}

def _compute_vital_confidence(
self,
breath_peak: float,
heart_peak: float,
breath_max: float,
heart_max: float
) -> float:
"""计算生命体征置信度"""
# 呼吸信号强度
breath_conf = breath_peak / breath_max if breath_max > 0 else 0

# 心跳信号强度
heart_conf = heart_peak / heart_max if heart_max > 0 else 0

# 综合置信度
confidence = 0.6 * breath_conf + 0.4 * heart_conf

return min(confidence, 1.0)

def _compute_position(self, range_idx: int) -> Tuple[float, float, float]:
"""计算目标位置"""
# 简化:仅计算距离
range_m = range_idx * self.range_resolution

# 假设安装在顶棚中央
# 实际需要角度估计
x = 0.0
y = 0.0
z = range_m

return (x, y, z)


# 测试
if __name__ == "__main__":
cpd = IWR6843CPD()

# 模拟ADC数据(包含呼吸信号)
num_chirps = 128
num_samples = 256
num_rx = 4

# 生成模拟数据
t = np.linspace(0, 1, num_chirps)
breath_phase = 0.5 * np.sin(2 * np.pi * 0.25 * t) # 15次/分呼吸

adc_data = np.zeros((num_chirps, num_samples, num_rx), dtype=complex)

# 在某个距离bin注入信号
target_range_idx = 50 # 约2米
adc_data[:, target_range_idx, :] = np.exp(1j * breath_phase)[:, np.newaxis]

# 添加噪声
adc_data += 0.1 * (np.random.randn(*adc_data.shape) + 1j * np.random.randn(*adc_data.shape))

# 处理
targets = cpd.process_frame(adc_data)

print(f"\n检测到 {len(targets)} 个目标:")
for target in targets:
print(f" 距离: {target.range_idx * cpd.range_resolution:.2f} m")
print(f" 呼吸率: {target.breath_rate:.1f} 次/分")
print(f" 心率: {target.heart_rate:.1f} 次/分")
print(f" 置信度: {target.confidence:.2f}")

Euro NCAP测试场景

测试用例

场景编号 描述 测试工具 通过条件
CPD-01 新生儿检测 新生儿假人 15秒内检测
CPD-02 1岁儿童检测 1岁假人 15秒内检测
CPD-03 3岁儿童检测 3岁假人 15秒内检测
CPD-04 6岁儿童检测 6岁假人 15秒内检测
CPD-05 毛毯遮挡检测 毛毯覆盖假人 仍能检测
CPD-06 安全覆盖 空座 不误报
CPD-07 多目标场景 成人+儿童 正确识别儿童
CPD-08 宠物干扰 小型宠物 不误报

安装位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
推荐安装位置(全景覆盖):

车辆顶棚:
┌─────────────────────────────────────┐
│ [前] │
│ ○ 后视镜后方 │
│ │
│ ○ ○ │
│ B柱左 B柱右 │
│ │
│ ○ │
│ 后排中央 │
│ │
│ [后] │
└─────────────────────────────────────┘

单雷达覆盖方案:
└── 后排顶棚中央(覆盖后排所有座椅)

系统集成

完整CPD系统

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

包含:
1. 雷达数据处理
2. 警告逻辑
3. 干预措施
4. 车辆接口
"""

def __init__(self):
self.radar = IWR6843CPD()
self.state = 'IDLE'
self.detection_time = None
self.child_detected = False

# 配置
self.detection_threshold = 0.6
self.warning_delay_locked = 15 # 锁车后15秒
self.warning_delay_unlocked = 600 # 未锁车10分钟
self.escalation_delay = 90 # 升级警告90秒后

def update(self, radar_data, vehicle_state):
"""
主循环更新

Args:
radar_data: 雷达ADC数据
vehicle_state: 车辆状态字典
"""
# 雷达检测
targets = self.radar.process_frame(radar_data)

# 判断是否有儿童
self.child_detected = self._is_child_present(targets)

# 状态机
if self.child_detected:
if self.state == 'IDLE':
self.state = 'DETECTED'
self.detection_time = time.time()

elapsed = time.time() - self.detection_time

if vehicle_state['locked']:
self._handle_locked_scenario(elapsed, vehicle_state)
else:
self._handle_unlocked_scenario(elapsed, vehicle_state)
else:
if self.state != 'IDLE':
self._reset()

def _is_child_present(self, targets: List[CPDTarget]) -> bool:
"""判断是否有儿童"""
for target in targets:
# 呼吸率在儿童范围内(20-40次/分)
if 15 < target.breath_rate < 45 and target.confidence > self.detection_threshold:
return True
return False

def _handle_locked_scenario(self, elapsed, vehicle_state):
"""处理锁车场景"""
if elapsed >= self.warning_delay_locked:
self._trigger_initial_warning()

if elapsed >= self.warning_delay_locked + self.escalation_delay:
self._trigger_escalation()
self._check_intervention(vehicle_state)

def _handle_unlocked_scenario(self, elapsed, vehicle_state):
"""处理未锁车场景"""
if elapsed >= self.warning_delay_unlocked:
self._trigger_initial_warning()

def _trigger_initial_warning(self):
"""触发初始警告"""
if self.state != 'WARNING_INITIAL':
self.state = 'WARNING_INITIAL'
print("⚠️ 初始警告:鸣笛+闪灯")
# 调用车辆CAN接口

def _trigger_escalation(self):
"""触发升级警告"""
if self.state != 'WARNING_ESCALATION':
self.state = 'WARNING_ESCALATION'
print("🚨 升级警告:持续鸣笛+App通知")

def _check_intervention(self, vehicle_state):
"""检查干预措施"""
# 温度检测
if vehicle_state.get('cabin_temp', 25) > 35:
self._activate_climate()

# 自动解锁
self._unlock_doors()

def _activate_climate(self):
"""激活空调"""
print("❄️ 激活空调降温")

def _unlock_doors(self):
"""解锁车门"""
print("🔓 解锁车门允许救援")

def _reset(self):
"""重置状态"""
self.state = 'IDLE'
self.detection_time = None
self.child_detected = False

开发资源

TI官方资源

资源 链接
IWR6843数据手册 ti.com/product/IWR6843
mmWave SDK ti.com/tool/MMWAVE-SDK
CPD Demo dev.ti.com/tirex/explore/node?node=AD__…
技术文档 ti.com/lit/SSZT046

开发步骤

  1. 购买IWR6843ISK-ODS评估板
  2. 安装mmWave SDK
  3. 烧录CPD Demo固件
  4. 使用TI可视化工具验证
  5. 集成到整车系统

参考资源

  1. TI CPD技术文档: https://www.ti.com/document-viewer/lit/html/SSZT046
  2. Euro NCAP CPD协议: https://www.euroncap.com/media/79888/
  3. IWR6843产品页: https://www.ti.com/product/IWR6843

本文详细介绍TI 60GHz毫米波雷达CPD方案,代码可复用。