简介:本资源是一套面向嵌入式与雷达信号处理初学者的实践型学习材料,聚焦IWR1843毫米波雷达在FMCW-MIMO体制下的多模态应用开发,解决从原始数据采集到高级感知任务(如人体点云追踪、热力图定位、手势识别及非接触式生命体征检测)的技术落地问题。压缩包共39个文件,涵盖24个MATLAB核心算法脚本(如CFAR检测、RD/DOA成像、呼吸心跳提取)、4份技术文档(含TI官方雷达基础与实操教程PDF)、3份README说明及6个备份文件,总大小5.71MB,结构按“数据采集→仿真建模→人体定位→生理监测→手势识别”模块组织,便于分阶段学习与复现。已有135人下载学习,提供完整可运行的MATLAB工程框架、参数配置模板、信号处理链路脚本及典型场景demo,覆盖从ADC原始数据读取、距离多普勒谱生成、点云构建到时频域生理特征提取的全栈流程,是理解毫米波雷达底层原理与工程实现的理想入门实践包。 去年把 IWR1843+DCA1000 这套 FMCW-MIMO 毫米波雷达平台完整跑通的时候,我最大的感受是:整条链路其实不复杂,但每一个环节都有自己的脾气。DCA1000 的网口配置不对,采回来的原始数据直接是乱的;chirp 参数没算好,CFAR 之后要么把静止墙面当成目标,要么人体反射被噪声淹没;到了生命体征检测,又要在点云追踪的基础上往相位域里深挖一层,幅度信息根本不够用。这篇文章就是我整个项目从零到一的完整复盘,覆盖 IWR1843DCA1000 硬件环境搭建、数据采集、点云生成、人体追踪、生命体征检测这几个核心模块,适合正在用这套平台做课程设计、课题研究或者产品原型验证的同学参考。我会把踩过的坑、调过的参数、最后能稳定跑通的方案全部写出来,尽量做到你对着文章就能复现。
这套平台最大的价值在于,它把雷达信号处理链路完整地开放给了开发者。IWR1843 芯片内部集成了射频前端、ADC 和 DSP,本身可以通过串口输出处理后的点云结果;但如果你只想用它的点云输出做应用,那其实是把最核心的信号处理部分当成了黑盒。DCA1000 采集卡的作用就是绕过板载 DSP,把 LVDS 接口上的原始 ADC 数据直接搬到电脑上,让开发者自己实现距离维 FFT、多普勒维 FFT、DOA 估计、CFAR 检测这一整条算法链路。这也是我选择这套组合的原因——它能让我真正理解 FMCW 雷达的点云是怎么从原始波形里长出来的。
1. 为什么是 IWR1843+DCA1000:硬件平台选型与整体链路拆解
1.1 单芯片雷达与数据采集卡的分工
IWR1843 是 TI 推出的一款 76-81GHz 毫米波雷达 SoC,单颗芯片集成了 3 个发射通道、4 个接收通道,内部还有 DSP 子系统、MCU 子系统和一片不小的 RAM。它可以在板子上直接完成从 ADC 数据到目标点云的整个处理流程,甚至还能跑一些简单的追踪算法。但实际做算法研究时,这块芯片的板载处理能力反而成了瓶颈——你没法在 DSP 里插桩看中间数据,没法灵活调试 CFAR 阈值和 FFT 点数,更别提把原始 ADC 数据拿出来做离线算法验证了。
DCA1000 解决的正是这个问题。它通过 LVDS 接口和 IWR1843 连接,把 ADC 采样后的原始数据实时搬运到以太网口,再用网线传到电脑上。你可以把它理解成一个高速数据采集外设,雷达芯片负责发射波形、接收回波、完成模数转换,DCA1000 负责把这些十六进制的采样值原封不动地送到 PC 上做保存。这样的分工非常干净:射频前端和信号调理由专用芯片完成,算法验证和数据处理完全由开发者掌控。
1.2 天线、MIMO 与虚拟孔径的基本逻辑
IWR1843 搭载的天线阵是 3 发 4 收。如果只用单发单收,角度估计就只能依赖一个收发通道的相位信息,分辨率非常有限。这里用到的是 FMCW-MIMO 雷达里最核心的思路——通过多发多收构建虚拟阵列,用较小的物理孔径获得更大的等效阵列长度。
发射天线按时间依次发射(TDM-MIMO),接收天线同时接收,每一对收发组合都对应一个虚拟阵元。3 发 4 收在理想布局下可以形成 12 个虚拟通道,相当于把原本 4 个物理接收天线扩展成了 12 个等效接收通道。这样做的直接收益是角度分辨率显著提升。虚拟阵列的等效孔径越大,测角精度越高,对后续人体追踪来说,意味着目标在空间中的横向位置稳定度会好很多。
我实测下来的经验是:天线布局对点云质量的影响非常大,这也是为什么我建议不要在拆掉天线罩或者移动天线位置的情况下做高精度测角实验。毫米波波长只有 4mm 左右,天线的位置偏差直接决定相位误差,进而影响角度估计。如果你有条件,最好在固定支架上使用原厂 EVM 板,不要频繁拆装。
1.3 项目整体处理链路
整个项目的处理链路可以分成四段。第一段是数据采集,通过 mmWave Studio 配置 IWR1843 的参数,包括 chirp 起始频率、扫频带宽、ADC 采样率等,然后通过 DCA1000 采集原始 bin 文件。第二段是数据预处理与点云生成,读入原始数据后按 LVDS 协议解析出各通道的复数采样值,再做距离维 FFT、多普勒维 FFT、静态杂波滤除、CFAR 检测和角度估计,最终输出每个目标的距离、速度、角度、强度信息。第三段是人体追踪,对点云做聚类和关联,用卡尔曼滤波输出稳定的目标轨迹。第四段是生命体征检测,在距离-角度定位到人体目标后,从目标的复数信号中提取相位信息,通过滤波分离出呼吸和心跳信号。
这四个阶段对工具的需求也不一样。数据采集阶段用的是 TI 官方的 mmWave Studio 和 DCA1000 固件,配置起来相对固定;点云生成阶段我主要用 MATLAB 离线处理,因为数据解析和 FFT 调试在 MATLAB 里最直观;人体追踪和生命体征检测阶段我迁移到了 Python 环境,利用 numpy、scipy 和滤波库,方便工程化部署。
2. DCA1000 数据采集:从 mmWave Studio 配置到原始 bin 文件解析
2.1 环境准备与常见连接方式
DCA1000 的硬件连接比较固定,需要注意几个容易被忽略的细节。IWR1843 EVM 板通过一个 60-pin 的高速连接器与 DCA1000 相连,连接时务必断电操作,带电插拔有概率损坏 FPGA 的 IO 口。网线一端接 DCA1000 的千兆网口,另一端直接连电脑网口,不要经过路由器或者交换机,这样最稳。
上电之后,需要把电脑的有线网卡 IP 手动改成静态地址。DCA1000 的默认 IP 是 192.168.33.180,所以电脑 IP 可以设置为 192.168.33.30,子网掩码 255.255.255.0,网关可以不填。最容易被忽略的是 Windows 防火墙设置,尤其是有多个网卡或者装了虚拟机的电脑,DCA1000 的 UDP 数据流如果被防火墙拦下来,mmWave Studio 里会出现连接正常但采不到数据的现象。我建议在做采集的电脑上直接把防火墙关闭,或者至少把私有网络的防火墙关掉。
2.2 参数配置里的几个关键决策
在 mmWave Studio 里配置参数时,有几个决策会直接影响后续算法实现。先说我最终采用的配置,你再根据自己的应用场景调整:
- 起始频率:77GHz
- 扫频带宽:1.5GHz
- 斜率:约 30MHz/us
- ADC 采样率:4Msps
- 采样点数:256
- 每帧 chirp 数:128
- 帧周期:50ms
距离分辨率由带宽决定,计算公式是 δR = c/(2B)。B=1.5GHz 时,距离分辨率约为 0.1m,这个分辨率对于人体追踪足够了。如果你要做更精细的生命体征检测,可以考虑把带宽调大,距离分辨率越高,选距离单元时的回波隔离度越好。不过带宽增大会导致 ADC 采样率需求上升,数据量也随之增大,DCA1000 的网口传输带宽是有限的,需要做取舍。
每帧 128 个 chirp 是我反复调试后确定的数量。帧周期 50ms 意味着帧率是 20fps。对于呼吸和心跳检测,奈奎斯特采样率要求采样频率至少是待测信号最高频率的两倍。心跳频率通常在 1-1.7Hz 之间,20fps 的帧率相当于 20Hz 的相位采样率,远高于心跳频率的两倍,所以这个帧率是够用的。
2.3 LVDS 原始数据的存储格式与解析
DCA1000 采集完成后会生成一个 .bin 文件,这个文件里的数据格式相当有迷惑性,我第一次解析时在这里卡了很久。默认配置下,DCA1000 输出的原始数据是 LVDS lane 按实部虚部分离存储的格式。
为了说清楚,假设单帧单 chirp 的 ADC 采样点数是 N,接收通道数是 4。那么每个 chirp 的数据排列是:
先排 RX1 的实数部分 N 个点,再排 RX1 的虚数部分 N 个点,然后 RX2 实部 N 个点,RX2 虚部 N 个点,依次类推,直到 RX4。每个点是 16bit(两个字节),低字节在前,高字节在后。
用 Python 解析时,可以直接用 numpy.fromfile 按 uint16 读入,然后 reshape。核心代码思路如下:
import numpy as np data = np.fromfile('adc_data.bin', dtype=np.uint16) num_chirps = 128 num_samples = 256 num_rx = 4 num_tx = 3 # 如果是 TDM 模式,实际每个 chirp 只有一路 TX 有效 # 每个 chirp 的数据长度 chirp_len = num_rx * 2 * num_samples # 先按 chirp 切分 frame_data = data.reshape(num_chirps, chirp_len) adc_mat = np.zeros((num_rx, num_chirps, num_samples), dtype=complex) for ch in range(num_rx): re = frame_data[:, ch * 2 * num_samples : (ch * 2 + 1) * num_samples] im = frame_data[:, (ch * 2 + 1) * num_samples : (ch * 2 + 2) * num_samples] adc_mat[ch] = re + 1j * im注意一点:DCA1000 在配置界面里可以选择 LVDS lane 的数目,默认是双 lane 模式。我上面的解析方式是针对单 lane 模式的,如果你用的是双 lane,数据会交叉存储,需要按 lane 做反交错,在 mmWave Studio 配置时记得保持一致。
2.4 数据校验:拿到 bin 文件后第一件事
每次采完数据,我都建议先做一个快速校验,确认数据没采歪之后再进入后续处理。校验的方法很简单:对任意一个接收通道的第一个 chirp 做一次 FFT,看看距离谱上有没有明显的峰值。如果房间里没有任何目标,距离谱应该是噪声;如果放了一块角反射器或者一面金属板,距离谱上应该在对应距离处出现明显的尖峰。
如果频域看不到尖峰,最可能的原因是数据解析维度搞错了,比如实部虚部的顺序反了、LVDS lane 数没对上、或者 chirp 数切分错误。我有一个很笨但很有效的排查方法:先不 parse 成复数,直接看原始 uint16 数据的均值。如果均值明显偏离 ADC 的中点(比如接近满量程或者接近 0),说明数据很可能不对。正常的雷达回波数据均值应该接近 ADC 中值附近,动态范围不会铺满整个量程。
3. 点云生成链路:距离、速度、角度的三维估计
3.1 距离维 FFT:把 ADC 采样变成目标距离
FMCW 雷达测距的本质是把时间差转换成频率差。发射信号频率随时间线性变化,回波信号相对发射信号有一个时间延迟 τ,混频之后的中频信号频率 f = Sτ,其中 S 是扫频斜率,τ = 2R/c。所以目标距离 R = f·c/(2S)。中频信号经过 ADC 采样后,对每一路接收到的复信号做 FFT,频谱峰值对应的频率就是中频频率,再换算成距离。
在实现上,对解析出的 adc_mat 的第一个维度做距离维 FFT。我的做法是对每个 chirp、每个通道分别做 N 点 FFT,N 就是采样点数 256。FFT 之后,每个 bin 对应的距离可以由下面的公式计算:
range_bin = arange(0, num_samples) * c / (2 * B)这里 B 是扫频带宽。注意 FFT 的每一点对应一个距离单元,距离分辨率是 δR,所以第 k 个 bin 代表的距离就是 k × δR。实际在代码里,我们可以先计算频率轴,再映射到距离轴,也可以直接用点数乘距离分辨率。
做完距离维 FFT 之后,数据维度是 num_rx × num_chirps × num_range_bins。如果每个 chirp 是独立的,这个距离谱就是慢时间-距离二维矩阵的一列。下一步的多普勒维 FFT 就是在 chirp 方向上做的。
3.2 多普勒维 FFT 与静态杂波滤除
多普勒维 FFT 的本质是对同一个距离单元上、多个 chirp 之间的相位变化做频谱分析。目标径向运动会导致相邻 chirp 之间产生相位偏移,这个相位差的频率就是多普勒频率,对应目标的速度。
对距离维 FFT 结果在 chirp 维度上再做一次 FFT,就得到距离-多普勒二维谱。这个二维谱是雷达信号处理里最核心的中间结果。人体目标的能量会出现在某个距离单元、某个多普勒频率附近,而静止的墙、桌子、地面等物体的能量集中在零多普勒附近。
静态杂波滤除是点云生成里非常关键的一步。如果没有滤除静态杂波,墙壁和家具的反射会形成大量虚假点云,后续聚类追踪会非常痛苦。最简单的静态杂波滤除方法是在 chirp 维度上减去均值。具体做法是:对距离-多普勒谱里的每个距离单元,计算其在所有 chirp 上的均值,然后每个 chirp 减去这个均值。
等效的频域操作是直接把零多普勒附近的能量置零,但减均值的方法更平滑,不容易引入频谱泄漏。我实际推荐的是两步结合:先做减均值,再做二维 CFAR 检测。减均值之后,人体这类运动目标的能量保留,静止背景的能量大幅削弱,CFAR 阈值可以定得比较低也不会出现满屏虚警。
# 距离-多普勒谱生成 range_doppler = np.fft.fft(range_profile, axis=1) range_doppler = np.fft.fftshift(range_doppler, axes=1) # 静态杂波滤除:chirp 维度减均值 static_removed = range_profile - np.mean(range_profile, axis=1, keepdims=True) rd_after = np.fft.fft(static_removed, axis=1)这个静态滤除步骤对室内场景尤其重要。IWR1843 在室内测试时,墙体反射的能量可能比人体反射强一个数量级,如果不做滤除,距离维 FFT 之后满距离轴都是强反射,CFAR 检测基本没法用。
3.3 角度估计与点云输出
距离和速度都确定之后,还差目标的方位角。角度估计依赖多个接收天线之间的相位差。目标从不同方向返回时,到达相邻天线的波程差不同,相位差也不同,通过相位差反推角度。这里用到的核心公式是:
Δφ = 2πd·sin(θ) / λ
其中 d 是天线间距,θ 是目标方向与法线的夹角。对 12 个虚拟通道做 FFT,峰值对应的谱线位置就是目标角度。这个处理方式叫角度维 FFT,或者叫数字波束成形。
实现时,要把每一对收发通道的数据按虚拟阵元顺序排列。TDM-MIMO 模式下,3 个发射天线分时发射,所以每一帧数据里,前若干个 chirp 对应 TX1 发射,第二批对应 TX2 发射,最后一批对应 TX3 发射。角度估计时需要把相同距离单元、相同多普勒 bin 下、对应同一虚拟阵元的数据抽取出来,组成一个 12 维的矢量,再做 FFT 或 MUSIC 类超分辨算法。
我在项目里做的是:先在距离-多普勒谱上做二维 CFAR 检测,得到目标的距离和速度;然后在目标所在的距离-多普勒单元上,提取 12 个虚拟通道的数据,做角度 FFT,找到峰值位置和对应角度。最后输出点云数组,每个点包含距离、速度、方位角、俯仰角(IWR1843 的虚拟阵列同时支持方位和俯仰估计)以及信号强度。
到这里,从原始 ADC 数据到点云的完整链路就走通了。实际处理时还会遇到不少细节,比如窗函数的选择会对旁瓣抑制有明显影响,CFAR 的训练单元和保护单元设置需要根据场景微调。这些参数没有绝对正确的值,必须在自己的场景里反复试。
4. 从点云到人体目标:聚类与追踪的工程化处理
4.1 雷达点云的独特性与预处理
雷达点云和激光雷达点云有一个很大的区别:激光雷达点云是一个个真实的反射点,空间位置精确;雷达点云是检测目标之后生成的检测点,每个点都带有距离、速度、角度和强度的估计误差。而且同一个物理目标可能出现多个点云,比如人体手臂和躯干反射强度不同,可能产生多个距离相近的点。
在做追踪之前,我先对点云做一遍预处理。第一步是剔除单帧点数过少的帧,如果一帧只有一两个点,大概率是噪声或者旁瓣,直接丢弃。第二步是按信噪比阈值过滤,点云数据里通常带每个点的 SNR 信息,我一般保留 SNR 大于某个经验的点,这个阈值我常用 8dB。第三步是速度筛选,人体运动速度通常不会超过 3m/s,超过这个速度的点云极大概率是虚假检测。
预处理之后,点云质量明显干净很多。这一步看起来简单,但对后续追踪稳定性的提升是非常直接的。
4.2 DBSCAN 聚类和参数调节
聚类的作用是把属于同一个人体的多个点云合并成一个目标。我用的算法是 DBSCAN,因为它不需要预先指定类别数量,而且能处理任意形状的点云簇,这两点都很贴合雷达场景。
DBSCAN 有两个核心参数:邻域半径 eps 和最小样本数 min_samples。eps 设置太小,同一个人的点云会被拆成多个目标;设置太大,靠近的两个人会被合并成一个目标。对于室内人体追踪场景,我实测下来 eps 取 0.3-0.5m 比较合适,min_samples 取 3-5。具体值跟你雷达的距离分辨率有关,如果你的距离分辨率是 0.1m,把人体的胸腔、手臂、腿反射的点云聚成一簇,0.4m 左右的邻域半径基本够用。
聚类之后,每个簇的中心可以视为一个候选目标。这里有一个经验:不要简单地用所有点云的均值作为目标位置,因为人体躯干反射强、点云密集,四肢反射弱、点云稀疏,均值会把目标中心拉向躯干方向,这其实是好的。但如果有两个目标靠近,均值会被拉偏,这种情况下可以考虑用加权平均,权重用 SNR 或者点云强度。
4.3 简单好用的卡尔曼跟踪框架
聚类得到的目标位置是存在闪烁的,每一帧的检测结果会跳动,直接使用会导致轨迹抖动。我用卡尔曼滤波对目标位置和速度进行平滑和预测。对于人体运动,匀速模型在这类近匀速室内场景下效果足够好,状态向量取 [x, vx, y, vy, z, vz],观测向量是 [x, y, z]。
数据关联我用匈牙利算法,以预测位置和实际检测位置之间的欧氏距离作为代价矩阵。看起来很简单,但有一个细节很关键:只有当连续多少帧都关联到同一个目标时才确认轨迹,当连续多少帧丢失时才删除轨迹。我的经验值是确认 3 帧,删除 8 帧。这个机制能过滤掉大量偶发的虚假点云,避免轨迹碎片化。
from filterpy.kalman import KalmanFilter kf = KalmanFilter(dim_x=6, dim_z=3) kf.F = np.array([[1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1]]) kf.H = np.array([[1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0]])卡尔曼滤波的核心是调过程噪声 Q 和观测噪声 R。Q 调大了,滤波器反应快、但是轨迹抖动;Q 调小了,轨迹平滑但延迟变大。我一般先设 R 为一个较小的对角阵,代表雷达测距测角的精度,再根据实际跟踪平滑度去调 Q。
5. 生命体征检测:相位域里的呼吸与心跳分离
5.1 相位为什么能测出呼吸和心跳
人体呼吸和心跳会引起胸壁有节律的微小位移。呼吸时胸廓起伏的幅度大约 4-12mm,心跳引起的胸壁振动幅度更小,约 0.2-0.5mm。这个级别的位移用幅度信息根本测不出来,因为在距离维 FFT 谱上,这个位移远小于距离分辨单元。但相位对微小位移非常敏感。
雷达发射波长为 λ 的电磁波,目标位移 ΔR 会引起回波相位变化 Δφ = 4πΔR/λ。以 77GHz 为例,波长约为 3.9mm,胸壁位移 1mm 对应的相位变化约为 1.6 弧度,这个数值完全可以通过数字信号处理检测出来。所以生命体征检测的核心思路是:先通过点云追踪锁定人体目标所在的距离单元,然后提取该距离单元内复数信号的相位,最后对相位序列做滤波处理,分离出呼吸和心跳成分。
5.2 目标距离单元的选取与相位解缠
目标距离单元的选取直接决定了信号质量。如果选错了距离单元,叠加了其他反射体的回波,相位信号会严重失真。我的做法是:在追踪稳定之后,取目标点云中 SNR 最高的那个点对应的距离索引作为生命体征检测的距离单元。
但这个做法有个问题——人体呼吸时胸壁位移 1cm 左右,有可能导致目标从一个距离单元跳跃到相邻的距离单元。所以我在追踪时同时记录目标距离索引的变化,并做一个滑动窗口,在窗口内统计该距离索引上信号的幅度稳定性,选择幅度最大且稳定的距离单元。
提取相位之后,第一件事是相位解缠。atan2 函数返回的相位值在 [-π, π] 之间,如果真实相位是连续变化的,在跨越边界时会出现跳变,跳变幅度超过 π 就需要把相位修正到连续。Python 里 numpy.unwrap 可以完成这个工作,但要注意解缠后的相位仍然含有由目标整体位移引起的低频分量,比如人身体不自觉的晃动。
5.3 呼吸心跳分离的滤波设计
解缠后的相位序列包含了多种成分:呼吸引起的低频成分(约 0.2-0.5Hz)、心跳引起的较高频成分(约 1-1.7Hz)、身体缓慢晃动带来的极低频分量,以及高频噪声。分离的关键是设计两组带通滤波器。
我先用零相位滤波(filtfilt)做处理,避免相位偏移影响信号时序。呼吸通道的带通范围设置为 0.1-0.6Hz,心跳通道设置为 0.8-2.0Hz。这里的心跳范围向上放宽到 2.0Hz,是为了覆盖运动后心率升高的情况。
from scipy.signal import butter, filtfilt fs = 20 # 帧率 20fps # 呼吸带通 0.1-0.6Hz b_breathe, a_breathe = butter(3, [0.1, 0.6], btype='bandpass', fs=fs) breathe_signal = filtfilt(b_breathe, a_breathe, phase_unwrapped) # 心跳带通 0.8-2.0Hz b_heart, a_heart = butter(3, [0.8, 2.0], btype='bandpass', fs=fs) heart_signal = filtfilt(b_heart, a_heart, phase_unwrapped)滤波之后,需要把相位信号转换为位移信号。位移 ΔR = λΔφ/(4π)。我把处理后的呼吸和心跳信号都乘以 λ/(4π),得到以毫米为单位的位移波形,这样在展示和评估时更直观。
实测下来,呼吸信号的检测非常稳定,因为呼吸引起的胸部位移量大,相位变化显著。心跳信号要难一些,因为它的幅度只有 0.2-0.5mm,对应的相位变化很小,很容易被身体微动和雷达的相位噪声淹没。一个有效的优化是在多个距离单元上做加权平均:如果人体胸腔在多个距离单元都有能量,把每个单元的相位信号经过带通滤波后按幅度加权叠加,能够提升信噪比。但加权平均在个体位置上效果不一样,需要针对具体测试对象微调。
6. 调试复盘:我遇到过的坑和解决思路
6.1 DCA1000 连接失败与数据异常
DCA1000 最常见的坑是 mmWave Studio 连接失败。我遇到过的情况是:固件加载成功,但点击 Trigger 按钮后数据文件一直是空的,或者只有几 KB。排查过程是先检查电脑网卡 IP 是否为 192.168.33.x 段,然后确认 DCA1000 板卡上的网口指示灯是否亮起,最后检查 Windows 防火墙。有一次折腾了一个多小时,最后发现是电脑上装的虚拟机网卡把 UDP 组播包给吃了,禁用虚拟网卡后一切正常。
还有一个经常忽略的问题:DCA1000 一次只能和一个串口会话绑定,如果之前 mmWave Studio 异常退出导致进程没有完全释放串口资源,需要先在任务管理器里把相关进程结束掉,再重新打开。IWR1843 板上的 SOP 开关状态也会影响连接模式,刷写固件和运行数据采集时 SOP 模式需要不同,注意查看板卡丝印说明。
数据采回来全是零或者乱码的问题,我遇到过一次,原因是 LVDS lane 配置不对。mmWave Studio 里选双 lane,但实际板子上走的是单 lane 模式,数据格式完全错乱了。这类问题通过修改 DataConfig 或者 UART 配置可以解决,但更快的排查方式是找一份已知正确格式的参考数据,对比某个固定位置的值是否合理。
6.2 点云质量问题的排查链路
点云质量差是最磨人的问题,因为涉及环节太多。我总结出一个排查顺序:先看距离谱是否正常,再看多普勒维是否成功测到人体运动,最后看角度估计是否稳定。
如果距离谱上找不到人体目标,先检查雷达放置高度和辐射方向。毫米波雷达波束范围较窄,我一开始把雷达放在桌面上朝前扫,人体站在侧面,结果点云几乎看不到目标。后来调整雷达高度到 1.5m 左右,俯仰角稍微往下压,人体目标在距离谱上就非常明显了。
如果距离谱正常但速度维测不到人体,常见原因是人在雷达前保持静止或者只有微动。多普勒维 FFT 测的是径向速度,如果人体正好垂直于雷达波束方向移动,径向速度分量很小,多普勒频移也很小,目标能量会落在零多普勒附近,和静态杂波混在一起。这种情况有两个解法:一是把人和雷达的角度拉开,保证有径向速度分量;二是可以用微多普勒特征做目标检测,因为即使人站着不动,呼吸和轻微晃动也会产生微小的多普勒调制,但这需要更高的多普勒分辨率,也就是更多的 chirp 积累。
如果距离和速度都对,但角度抖动大,基本是角度估计的相位校准问题。IWR1843 的虚拟阵列在出厂时有校准参数,但如果你用了非标准的 MIMO 模式,或者没有正确设置天线的收发顺序,角度估计就会出错。这种情况下检查 TDM 模式下 TX1、TX2、TX3 对应的 chirp 索引分配是否正确。
6.3 生命体征检测精度提升的几个细节
生命体征检测对目标静止的要求很高,但这和人体呼吸之间天然存在矛盾——人越是深呼吸,胸腔位移越大,信号越强,但身体也越容易晃动。我测试时的做法是让人坐在椅子上,背部靠墙,尽量保持自然呼吸,双手放在膝盖上。这样的姿态能把身体整体的机械晃动降到最低,呼吸引起的胸壁位移又能被稳定捕获。
另一个细节是距离单元的选取可以动态调整。当人呼吸幅度大时,胸壁位移可能达到 1cm 以上,距离单元会随之跳变。如果一开始固定的距离单元在某个时间点失配,后续所有相位提取都会失败。我的做法是在每一帧都检查相邻距离单元的能量分布,如果目标能量峰值已经迁移到另一个距离单元,就切换过去,而不是仍然用旧的距离单元。这种动态跟踪方式实测能显著提升长时间监测的稳定性。
还有一点是关于相位噪声的。77GHz 雷达的相位噪声在高频段比较明显,对心跳这种微动信号的干扰比呼吸信号大得多。如果你观察心跳波形总是淹没在噪声里,可以尝试多积累几个 chirp,把同一个距离单元上多个 chirp 的相位做平均。这里的平均不是直接对相位平均,而是对复数信号平均后再取相位,等效于提高信噪比。
最后再分享一个小技巧:生命体征检测里,呼吸信号和心跳信号在频谱上不是完全分开的。呼吸的谐波可能会泄漏到心跳频带内,尤其是呼吸频率偏快的时候。如果在 1Hz 附近看到一个很强的狭窄尖峰,先别急着认为是心跳,可以对比一下它和呼吸基频之间是否成整数倍关系。如果成倍数关系,多半是呼吸谐波,可以在心跳通道里加一个梳状滤波器或者自适应滤波器把它消掉。我在实际处理里就遇到过呼吸频率 0.3Hz、三次谐波 0.9Hz 正好落在心跳频带里的情况,一开始误报心率异常,查了很久才意识到是谐波干扰。
本文还有配套的精品资源,点击获取