Notes
雷达数据预处理流程
毫米波雷达生命体征数据预处理的完整流程图和代码说明
雷达数据预处理流程
本文档详细介绍毫米波雷达生命体征数据的预处理流程。
流程概览
处理步骤详解
1. 数据加载 (Load Frames)
从二进制文件中读取雷达原始数据帧。
代码实现:
def load_all_frames(self) -> np.ndarray:
# 搜索帧标记
START_MARKER = b'\xDC\x0A\xDC\x0A\xDA\x0C\xDA\x0C'
HEADER_END_MARKER = b'\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F'
PAYLOAD_SIZE = 2048
# 解析每一帧
all_frames = np.zeros((n_frames, 4, 128), dtype=np.complex64)数据格式:
- 每帧包含 4 个 chirp
- 每个 chirp 有 128 个采样点
- 数据类型:复数(I/Q 数据)
2. 数据重组 (Reshape & Group)
将连续的帧重组为分析单元(group)。
代码实现:
# 配置参数
frames_per_group = 4 # 每组包含4帧
chirps_per_frame = 4 # 每帧包含4个chirp
# 重组数据
reshaped = valid_data.reshape(
num_groups, # 组数
frames_per_group, # 4
chirps_per_frame, # 4
SAMPLES_PER_CHIRP # 128
)维度说明:
- 原始:
(N_frames, 4, 128) - 重组后:
(N_groups, 4, 4, 128)
3. 数据累加 (Sum Data)
对每组内的所有 frame 和 chirp 进行累加。
代码实现:
# 累加:沿 frame 和 chirp 维度求和
sum_data = reshaped.sum(axis=(1, 2))
# 结果维度:(num_groups, 128)目的:
- 提高信噪比(SNR)
- 减少数据维度
- 增强目标信号
4. 加窗 (Windowing)
应用汉宁窗减少频谱泄漏。
代码实现:
window = np.hanning(SAMPLES_PER_CHIRP) # 128点汉宁窗
windowed_data = sum_data * window窗函数特性:
- 类型:Hanning Window
- 长度:128
- 作用:抑制旁瓣,减少频谱泄漏
5. 距离 FFT (Range FFT)
执行快速傅里叶变换,将时域信号转换到距离域。
代码实现:
# FFT:沿距离维度 (axis=1)
fft_data = np.fft.fft(sum_data * window, n=128, axis=1)
# 取正频部分
fft_range_bins = fft_data[:, :64] # (num_groups, 64)频率分辨率:
距离分辨率 = c / (2 * B)
其中:c = 光速,B = 带宽6. 目标检测 (Target Detection)
通过能量分析找到目标所在的距离门(range bin)。
代码实现:
# 计算平均频谱
mean_spectrum = np.mean(np.abs(fft_range_bins), axis=0)
# 找到最大能量的 bin
target_bin = int(np.argmax(mean_spectrum))可视化:
plt.imshow(np.abs(fft_range_bins.T),
aspect='auto', cmap='jet')
plt.ylabel('Range Bin')
plt.xlabel('Group Index')7. 相位提取 (Phase Extraction)
从目标距离门提取复信号的相位信息。
代码实现:
# 提取目标 bin 的复信号
complex_signal = fft_range_bins[:, target_bin]
# 计算相位角
raw_phase = np.angle(complex_signal) # 范围:[-π, π]物理意义:
- 相位变化反映目标位移
- 微小位移(呼吸、心跳)导致相位变化
8. 相位解包裹 (Phase Unwrapping)
消除相位跳变,得到连续相位。
代码实现:
unwrapped_phase = np.unwrap(raw_phase)解包裹原理:
原始相位:... 3.0, -3.0, -2.8, ... (跳变)
解包裹后:... 3.0, 3.3, 3.5, ... (连续)9. 去趋势 (Detrending)
移除低频漂移和趋势项,保留生命体征信号。
代码实现:
from scipy.signal import detrend
detrended_phase = detrend(unwrapped_phase)效果:
- 去除低频漂移
- 突出周期性信号(呼吸、心跳)
- 改善后续频谱分析
数据流转示意
原始帧数据 (N, 4, 128)
↓
重组 (N_groups, 4, 4, 128)
↓
累加 (N_groups, 128)
↓
加窗 + FFT
↓
距离频谱 (N_groups, 64)
↓
目标检测 → 选择 bin
↓
复信号序列 (N_groups,)
↓
相位提取 → 原始相位
↓
相位解包裹 → 连续相位
↓
去趋势 → 生命体征波形关键参数
采样参数
| 参数 | 值 | 说明 |
|---|---|---|
SAMPLES_PER_CHIRP | 128 | 每个 chirp 的采样点数 |
chirps_per_frame | 4 | 每帧的 chirp 数量 |
frames_per_group | 4 | 每组的帧数 |
time_between_groups | 1 ms | 组间时间间隔 |
派生参数
# 生命体征采样率
fs_vital = 1.0 / time_between_groups # 1000 Hz
# 有效帧数
valid_frames = total_frames - 1
# 组数
num_groups = valid_frames // frames_per_group结果数据结构
预处理完成后返回 VitalSignsResults 对象:
@dataclass
class VitalSignsResults:
detrended_phase: np.ndarray # 去趋势相位(最终波形)
unwrapped_phase: np.ndarray # 解包裹相位
raw_phase: np.ndarray # 原始相位 (-π ~ π)
target_bin: int # 检测到的目标距离门
fs_vital: float # 生命体征采样率 (Hz)
num_groups: int # 有效组数
sum_data: np.ndarray # 累加后数据 (num_groups, 128)
fft_range_bins: np.ndarray # 距离FFT结果 (num_groups, 64)
first_frame_fft_mag: np.ndarray # 第一帧FFT幅度 (64,)使用示例
基础使用
from radar import RadarProcessor
# 初始化处理器
processor = RadarProcessor(
file_path='data/data.bin',
frames_per_group=4,
chirps_per_frame=4,
time_between_groups=0.001,
preload=True
)
# 执行预处理和生命体征分析
results = processor.analyze_vital_signs(plot=True)
# 访问结果
vital_sign_waveform = results.detrended_phase
sampling_rate = results.fs_vital
target_distance_bin = results.target_bin
print(f"检测到目标位于距离门: {target_distance_bin}")
print(f"采样率: {sampling_rate} Hz")
print(f"波形长度: {len(vital_sign_waveform)} 个采样点")绘制波形
import matplotlib.pyplot as plt
# 绘制生命体征波形
plt.figure(figsize=(12, 4))
plt.plot(results.detrended_phase)
plt.title('Vital Signs Waveform')
plt.xlabel('Sample Index')
plt.ylabel('Phase (rad)')
plt.grid(True)
plt.show()频谱分析
# 对生命体征波形进行FFT
from scipy import signal
f, Pxx = signal.welch(
results.detrended_phase,
fs=results.fs_vital,
nperseg=256
)
# 绘制功率谱
plt.figure(figsize=(10, 4))
plt.semilogy(f, Pxx)
plt.title('Power Spectral Density')
plt.xlabel('Frequency (Hz)')
plt.ylabel('PSD')
plt.grid(True)
plt.show()可视化输出
预处理过程会生成以下可视化图表(当 plot=True 时):
1. 第一帧单通道 FFT
显示第一帧第一个通道的频谱,用于初步观察目标。
2. 距离-时间热图
二维热图显示所有组的距离频谱,横轴为组索引,纵轴为距离门。
3. 相位波形
包含两个子图:
- 解包裹相位:连续的相位曲线
- 去趋势相位:最终的生命体征波形
注意事项
性能优化
- 预加载模式:设置
preload=True可一次性加载所有帧,提升后续处理速度 - 批量解码:使用 NumPy 向量化操作,避免循环
数据质量
- 目标检测:确保目标 bin 选择正确,可通过距离热图验证
- 相位连续性:检查解包裹后的相位是否平滑连续
- 去趋势效果:去趋势后应保留周期性信号,去除低频漂移
参数调整
frames_per_group: 增大可提高 SNR,但降低时间分辨率time_between_groups: 影响生命体征采样率,需满足奈奎斯特定理
源代码
完整的源代码实现请参考 GitHub 仓库: