雷达文档
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_CHIRP128每个 chirp 的采样点数
chirps_per_frame4每帧的 chirp 数量
frames_per_group4每组的帧数
time_between_groups1 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. 相位波形

包含两个子图:

  • 解包裹相位:连续的相位曲线
  • 去趋势相位:最终的生命体征波形

注意事项

性能优化

  1. 预加载模式:设置 preload=True 可一次性加载所有帧,提升后续处理速度
  2. 批量解码:使用 NumPy 向量化操作,避免循环

数据质量

  1. 目标检测:确保目标 bin 选择正确,可通过距离热图验证
  2. 相位连续性:检查解包裹后的相位是否平滑连续
  3. 去趋势效果:去趋势后应保留周期性信号,去除低频漂移

参数调整

  • frames_per_group: 增大可提高 SNR,但降低时间分辨率
  • time_between_groups: 影响生命体征采样率,需满足奈奎斯特定理

源代码

完整的源代码实现请参考 GitHub 仓库:

On this page