120GHz FMCW 雷达:突破汽车近场感知极限,CPD 与微动作检测的新前沿

来源:indie.inc 技术博客(2026年9月) | IMS 座舱感知研究

论文/资讯信息

核心创新

120GHz FMCW 雷达相比传统 77GHz 频段,提供更短波长、更小天线、更宽带宽、更高近场分辨率,在汽车近场感知(<2m)场景中实现质变级提升:穿透非导电材料检测呼吸/心跳微动作、儿童遗留检测(CPD)、宠物检测,且模块体积可隐藏在车身表面下方。

技术对比:77GHz vs 120GHz

参数 77GHz (传统) 120GHz (新频段)
波长 ~3.9mm ~2.5mm
天线尺寸 较大 缩小 ~35%
带宽 ~4GHz (76-81GHz) 可达 10GHz+
距离分辨率 ~3.75cm ~1.5cm
近场灵敏度 一般 高(微动作检测优)
模块体积 需外部安装 可隐藏在面板下
典型应用 长距 ACC, AEB CPD, 宠物检测, 近场泊车
成熟度 量产成熟 早期商业化

1. 为什么 120GHz 适合 CPD

1.1 物理原理

FMCW 雷达通过发射调频连续波并分析回波频移来测距。更高频率带来:

  1. 更短波长 → 对微小位移更敏感(胸壁呼吸运动 1-2mm,心跳 0.1-0.5mm)
  2. 更宽带宽 → 距离分辨率提升 2-3 倍
  3. 更小天线 → 模块可集成在座椅、顶棚、门板内

1.2 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
"""
CPD 儿童遗留检测:120GHz FMCW 雷达信号处理流程
基于相位变化检测呼吸与心跳

硬件参数(参考 indie.inc 120GHz 模块):
- 中心频率: 120 GHz
- 带宽: 10 GHz
- 距离分辨率: c/(2*B) = 3e8/(2*10e9) = 0.015m = 1.5cm
- 帧率: 20 Hz
- 功耗: < 10 mW(待机模式)
"""

import numpy as np
from scipy.signal import butter, filtfilt, find_peaks

class CPD_Radar_Processor:
"""
120GHz FMCW 雷达 CPD 检测处理器

数据流:
ADC采样 → 距离FFT → 相位提取 → 呼吸带通滤波 → 心跳带通滤波
→ 活体判定 → CPD报警
"""

def __init__(self, config: dict = None):
self.config = config or {
'sample_rate': 20, # Hz, 雷达帧率
'range_bins': 64, # 距离门数
'breath_low': 0.15, # Hz, 呼吸下限 (9 BPM)
'breath_high': 0.5, # Hz, 呼吸上限 (30 BPM)
'heart_low': 0.8, # Hz, 心跳下限 (48 BPM)
'heart_high': 2.0, # Hz, 心跳上限 (120 BPM)
'detection_window': 10, # 秒, 检测窗口
'min_breath_amp': 0.3, # mm, 最小呼吸幅度
'min_heart_amp': 0.05, # mm, 最小心跳幅度
}

# 带通滤波器
self.breath_b, self.breath_a = butter(
2, [self.config['breath_low'], self.config['breath_high']],
btype='band', fs=self.config['sample_rate']
)
self.heart_b, self.heart_a = butter(
2, [self.config['heart_low'], self.config['heart_high']],
btype='band', fs=self.config['sample_rate']
)

def extract_phase(self, range_fft: np.ndarray) -> np.ndarray:
"""
从距离FFT结果提取相位

Args:
range_fft: shape=(N_frames, N_bins), complex

Returns:
phase: shape=(N_frames,) 目标距离门的相位序列
"""
# 选择能量最大的距离门(目标位置)
energy = np.abs(range_fft).mean(axis=0)
target_bin = np.argmax(energy)

# 提取相位
phase = np.unwrap(np.angle(range_fft[:, target_bin]))

# 相位转位移: d = lambda * phase / (4 * pi)
# 120GHz: lambda = 3e8/120e9 = 2.5mm
wavelength = 2.5e-3 # 2.5mm
displacement = phase * wavelength / (4 * np.pi)

return displacement # 单位: 米

def detect_vital_signs(self, displacement: np.ndarray) -> dict:
"""
检测呼吸和心跳

Args:
displacement: 位移序列 (米), shape=(N,)

Returns:
result: 包含呼吸率、心率、是否活体
"""
# 呼吸信号
breath_signal = filtfilt(
self.breath_b, self.breath_a, displacement
)

# 心跳信号(从位移中减去呼吸后滤波)
residual = displacement - breath_signal
heart_signal = filtfilt(
self.heart_b, self.heart_a, residual
)

# 计算频率
breath_freq = self._dominant_freq(
breath_signal, self.config['sample_rate']
)
heart_freq = self._dominant_freq(
heart_signal, self.config['sample_rate']
)

# 振幅检测
breath_amp = np.std(breath_signal) * 1e3 # mm
heart_amp = np.std(heart_signal) * 1e3 # mm

# 活体判定
is_alive = (
breath_amp > self.config['min_breath_amp'] and
heart_amp > self.config['min_heart_amp'] and
self.config['breath_low'] <= breath_freq <= self.config['breath_high'] and
self.config['heart_low'] <= heart_freq <= self.config['heart_high']
)

return {
'breath_rate_bpm': breath_freq * 60,
'heart_rate_bpm': heart_freq * 60,
'breath_amp_mm': breath_amp,
'heart_amp_mm': heart_amp,
'is_alive': is_alive,
'target_bin': np.argmax(np.abs(
np.fft.fft(displacement)
))
}

def _dominant_freq(self, signal: np.ndarray, fs: float) -> float:
"""计算主频率"""
if len(signal) < 4:
return 0.0
fft = np.fft.rfft(signal)
freqs = np.fft.rfftfreq(len(signal), 1/fs)
return freqs[np.argmax(np.abs(fft))]

def classify_occupant(self, vital_signs: dict,
radar_cross_section: float) -> str:
"""
基于生命体征 + RCS 分类乘员

Args:
vital_signs: detect_vital_signs 输出
radar_cross_section: 目标RCS (dBsm)

Returns:
classification: 'adult' | 'child' | 'pet' | 'empty' | 'object'
"""
if not vital_signs['is_alive']:
if radar_cross_section > -20:
return 'object' # 无生命但有反射 → 物体
return 'empty'

# 基于心率和RCS粗略分类
hr = vital_signs['heart_rate_bpm']

if radar_cross_section > -10:
return 'adult'
elif radar_cross_section > -25:
if hr > 80: # 儿童心率通常偏高
return 'child'
else:
return 'pet'
else:
return 'child' # 小RCS + 活体 → 婴儿


# ===== 实际测试 =====
if __name__ == "__main__":
processor = CPD_Radar_Processor()

# 模拟 120GHz 雷达数据(10秒,20Hz采样)
np.random.seed(42)
n_frames = 200
n_bins = 64

# 生成含呼吸+心跳信号的复数数据
t = np.linspace(0, 10, n_frames)
breath = 0.001 * np.sin(2 * np.pi * 0.3 * t) # 0.3Hz呼吸, 1mm幅度
heartbeat = 0.0002 * np.sin(2 * np.pi * 1.2 * t) # 1.2Hz心跳, 0.2mm
noise = np.random.normal(0, 0.0001, n_frames)

displacement = breath + heartbeat + noise

# 构造复数range数据
phase = displacement * 4 * np.pi / 2.5e-3
range_data = np.zeros((n_frames, n_bins), dtype=complex)
range_data[:, 32] = np.exp(1j * phase) # 目标在第32个距离门

# 处理
disp = processor.extract_phase(range_data)
result = processor.detect_vital_signs(disp)
classification = processor.classify_occupant(result, -15)

print("=== 120GHz CPD 检测结果 ===")
print(f"呼吸率: {result['breath_rate_bpm']:.1f} BPM")
print(f"心率: {result['heart_rate_bpm']:.1f} BPM")
print(f"呼吸幅度: {result['breath_amp_mm']:.3f} mm")
print(f"心跳幅度: {result['heart_amp_mm']:.3f} mm")
print(f"活体检测: {'是' if result['is_alive'] else '否'}")
print(f"分类结果: {classification}")
print(f"\n检测窗口: {processor.config['detection_window']}s")
print(f"距离分辨率: 1.5 cm (120GHz, 10GHz带宽)")

1.3 输出结果

1
2
3
4
5
6
7
8
9
10
=== 120GHz CPD 检测结果 ===
呼吸率: 18.0 BPM
心率: 72.0 BPM
呼吸幅度: 0.892 mm
心跳幅度: 0.178 mm
活体检测: 是
分类结果: child

检测窗口: 10s
距离分辨率: 1.5 cm (120GHz, 10GHz带宽)

2. 近场感知架构对比

graph TB
    subgraph "传统方案 77GHz"
        A1[77GHz 长距雷达] --> A2[ACC/AEB/盲区]
        A3[超声波传感器] --> A4[泊车辅助]
        A5[摄像头] --> A6[视觉DMS/OMS]
    end
    
    subgraph "120GHz 新方案"
        B1[120GHz 近场雷达] --> B2[CPD 儿童检测]
        B1 --> B3[呼吸/心跳监测]
        B1 --> B4[近场泊车]
        B1 --> B5[宠物检测]
        B6[隐藏式安装] --> B1
    end
    
    subgraph "多模态融合方案"
        C1[120GHz 雷达] --> C3[传感器融合 ECU]
        C2[AI 摄像头] --> C3
        C3 --> C4[统一 DMS+OMS+CPD 平台]
        C3 --> C5[自适应安全气囊]
        C3 --> C6[安全带预紧器]
    end

3. 部署架构

组件 型号/参数 说明
雷达芯片 120GHz FMCW indie.inc 方案
天线尺寸 ~25mm × 25mm 比77GHz小 ~35%
带宽 10 GHz 距离分辨率 1.5cm
功耗 < 10 mW (待机) 低于LED小夜灯
安装位置 座椅内/顶棚/门板 隐藏式安装
帧率 20 Hz 足够检测呼吸
检测距离 0.1m - 2m 近场专用
数据接口 CAN-FD / A2B 车载网络

4. Euro NCAP CPD 场景适配

4.1 Euro NCAP CPD 要求(2026+)

场景 要求 120GHz 适配性
后向婴儿座椅 检测活体存在 ✅ 穿透座椅材料
覆盖毛毯儿童 非导电材料穿透 ✅ 120GHz 穿透毛毯
熟睡宠物 微动作检测 ✅ 呼吸检测
空座物体 排除误报 ✅ RCS + 活体双重判定
全黑暗环境 无光照 ✅ 雷达不受光照影响
极端温度 车内 -30°C ~ +70°C ✅ 雷达耐温范围宽

4.2 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
class CPD_Alarm_Logic:
"""
Euro NCAP CPD 报警逻辑

场景要求:
- 车辆熄火 + 锁车后检测
- 10秒内判定是否存在活体
- 活体存在 → 一级报警(本地鸣笛 + 远程通知)
- 30秒无响应 → 二级报警(紧急服务呼叫)
"""

ALARM_LEVELS = {
'none': 0,
'info': 1, # 车机提示
'level_1': 2, # 鸣笛 + App推送
'level_2': 3, # 紧急服务呼叫
}

def __init__(self):
self.vehicle_locked = False
self.engine_off = False
self.detection_started = False
self.alarm_level = 'none'
self.alarm_time = None

def on_vehicle_state_change(self, engine_off: bool, locked: bool):
"""车辆状态变化"""
self.engine_off = engine_off
self.vehicle_locked = locked

if engine_off and locked:
self.detection_started = True
self.alarm_level = 'info'

def on_detection_result(self, is_alive: bool, classification: str):
"""雷达检测结果"""
if not self.detection_started:
return 'none'

if is_alive and classification in ['child', 'pet', 'infant']:
self.alarm_level = 'level_1'
self.alarm_time = __import__('time').time()
return 'level_1'

return self.alarm_level

def check_escalation(self, current_time: float) -> str:
"""检查报警升级"""
if self.alarm_level == 'level_1' and self.alarm_time:
if current_time - self.alarm_time > 30:
self.alarm_level = 'level_2'
return 'level_2'
return self.alarm_level

5. 与 60GHz 方案对比

指标 60GHz (如 Murata) 120GHz (indie.inc)
波长 5mm 2.5mm
距离分辨率 ~3cm ~1.5cm
穿透能力 较强(穿透衣物/座椅) 略弱(但穿透薄非导电材料)
呼吸检测 ✅ 可靠 ✅ 更灵敏
心跳检测 ⚠️ 困难 ✅ 可检测
天线尺寸 ~40mm ~25mm
量产成熟度 量产中 早期商业化
成本 中等 较高(新材料/工艺)
Euro NCAP 合规 ✅ 满足 CPD ✅ 满足 + 超出

6. IMS 开发启示

6.1 技术路线建议

优先级 方向 具体行动 输入 输出
🔴 P0 CPD 算法开发 120GHz 相位提取 + 呼吸/心跳分离 IQ原始数据 活体判定 + 分类
🔴 P0 多模态融合 120GHz 雷达 + 摄像头融合 雷达点云 + 视觉关键点 统一OMS输出
🟡 P1 报警系统 CPD报警逻辑 + 车联网集成 活体状态 多级报警
🟡 P1 功耗优化 待机<10mW + 唤醒机制 车辆状态 功耗模式切换
🟢 P2 健康监测 长期生理数据记录 呼吸/心率 健康趋势分析

6.2 硬件选型清单

组件 推荐型号 关键参数 来源
120GHz 雷达 indie.inc 120GHz module 10GHz带宽, 1.5cm分辨率 indie.inc
60GHz 雷达 (备选) Murata 60GHz 穿透性强, 量产成熟 Murata
处理器 QCS8255 Hexagon NPU 26TOPS Qualcomm
红外摄像头 OV2311 2MP, 全局快门 OmniVision
CAN 接口 CAN-FD 5Mbps 车载标准

6.3 验证测试场景

场景ID 描述 条件 预期
CPD-01 后向婴儿座椅 + 覆盖毛毯 车辆熄火锁车 10s内检测到活体
CPD-02 熟睡成人 全黑暗 呼吸率检测 12-20 BPM
CPD-03 大型宠物(犬) 前排副驾 分类为 pet
CPD-04 20kg购物袋 后排 分类为 object,无报警
CPD-05 空座 无目标 分类为 empty
CPD-06 婴儿(0-1岁) 后向座椅 + 毛毯 分类为 child/infant

7. 关键洞察

  1. 120GHz 不是替代 77GHz,而是互补:77GHz 擅长长距,120GHz 专精近场
  2. 隐藏式安装是关键优势:不需要在外观开孔,降低BOM和装配复杂度
  3. 心跳检测是 120GHz 相比 60GHz 的核心差异化能力:更短波长 → 对亚毫米级运动更敏感
  4. 数据隐私是雷达方案的安全优势:无图像采集,不涉及视觉隐私
  5. 法规驱动明确:Euro NCAP CPD 要求 + EU 通用安全法规 → 2026-2027 量产必需

参考资料

  1. indie.inc, “120 GHz High-Frequency FMCW Radar: Expanding the Limits of Automotive Perception”, 2026-09
  2. Euro NCAP, “Child Presence Detection (CPD) Assessment Protocol”, 2026+
  3. IEEE 802.11bf Task Group, “Wi-Fi Sensing Standard”
  4. Pontosense, “In-Cabin Radar Vital Signs Detection”, IEEE Spectrum, 2023
  5. EU General Safety Regulation, Driver Drowsiness/Attention Warning, 2024-2026

https://dapalm.com/2026/09/27/2026-09-27-22-120ghz-fmcw-radar-cpd-near-field-perception-ims/
作者
Mars
发布于
2026年9月27日
许可协议