
如果你接触过 TI 的毫米波雷达大概率会听过 IWR6843ISK 这块板子。它是一块 60GHz 频段的毫米波雷达评估板配合 DCA1000EVM 采集卡可以把原始 ADC 数据完整捞出来做后处理。我之前在实验室搭过一套基于这套硬件的生命体征检测demo目标就是把人体的呼吸和心跳信号从雷达回波里提取出来。这篇文章就把我从硬件连线到算法落地的全过程拆开讲一遍包括 FMCW 原理、数据采集、距离FFT、相位解缠、滤波分离这些核心环节以及实际调试中踩过的坑和排查思路。文章适合两类人看一类是刚拿到 IWR6843ISK 和 DCA1000EVM、打算做非接触式感知的开发者另一类是已经能跑通官方 demo但想深入理解生命体征信号提取算法细节、想把检测做稳的研究者。我会尽量把每个步骤背后的逻辑讲清楚而不是只给一段能跑的代码。1. 项目整体设计与原理拆解1.1 为什么用毫米波雷达做生命体征检测非接触式生命体征检测有很多技术路线常见的有摄像头光学方案利用面部肤色微变或胸口起伏、WiFi 信号感知、以及毫米波雷达。摄像头方案怕光照变化、怕遮挡还存在隐私问题WiFi 方案受环境干扰大、分辨率有限。毫米波雷达的优势在于不受光照影响、可以穿透一定遮挡物比如衣物和薄被、不采集面部图像因此隐私友好同时它对微小位移极其敏感。雷达测生命体征的核心物理量是胸腔表面的微动。人呼吸时胸廓起伏的幅度通常在 1 到 12 毫米之间心跳引起的胸腔表面振动则小得多典型幅度只有 0.1 到 0.5 毫米。这个量级用普通摄像头很难直接测量但对于毫米波雷达来说完全在检测范围内——因为毫米波波长在 4 毫米左右60GHz 对应波长约 5mm而雷达的相位测量精度可以达到波长的极小分数理论上能分辨亚毫米甚至更小的位移。所以这个项目的本质就是把“胸腔微动”从雷达回波中提取出来再通过频域特征区分呼吸和心跳。1.2 FMCW 雷达工作原理与距离-多普勒基础IWR6843ISK 采用 FMCW调频连续波调制方式。发射信号频率随时间线性增长遇到目标反射后接收天线采集到的回波与发射信号混频得到一个中频信号IF signal。中频信号的频率正比于目标的距离即f_b S * 2R / c其中 S 是调频斜率Hz/sR 是目标距离mc 是光速。对中频信号做 FFT就能得到目标的距离分布这就是“距离维 FFT”。如果一个目标有微小的径向位移比如胸腔随呼吸起伏那么回波中频信号的相位会随之变化。具体来说距离变化 ΔR 引起的相位变化是Δφ 4πΔR / λλ 是雷达波长。以 60GHz 雷达为例波长约 5mm如果胸腔位移 1mm相位变化约为 2.5 弧度完全能够被检测出来。这就是为什么雷达能以毫米甚至亚毫米精度感知呼吸心跳。距离维 FFT 之后每个距离门range bin得到一个复数。该复数的相位随时间的变化就包含了目标微动信息。慢时间维上对同一距离门做 FFT可以进一步得到微多普勒谱用于分析频率特征。1.3 硬件平台选型IWR6843ISK 与 DCA1000EVM 的搭配逻辑IWR6843ISK 是 TI 的 60GHz 毫米波雷达评估板内部集成 3 发 4 收天线实际可用配置常见为 1 发 3 收或 2 发 4 收支持 FMCW 调制。它的主要优势是集成度高板载了天线、射频前端、ADC 和一个 C674x DSP 核心可以独立运行处理算法。但在早期算法验证阶段我们往往需要原始 ADC 数据这时候板载 DSP 就不够用了——需要把原始数据导出来用 MATLAB 或 Python 做离线分析。DCA1000EVM 就是干这个的。它通过 LVDS 接口从 IWR6843ISK 读取原始 ADC 数据再通过千兆以太网传送到 PC 端。两者配合相当于把雷达前端和数据处理链路分开IWR6843ISK 负责射频收发和信号采集DCA1000EVM 负责数据搬运PC 端负责算法验证和参数调优。这套组合最大的好处是灵活。你可以先用 DCA1000 采集大量数据离线优化好算法和参数再移植到 IWR6843ISK 的 DSP 上做实时处理实现“离线验证、在线部署”的开发流程。很多 TI 的参考设计也是这么干的。2. 开发环境搭建与原始数据采集2.1 软件工具链从 mmWave Studio 到 MATLAB做这个项目需要准备以下软件环境mmWave StudioMMWAVE-STUDIOTI 官方的雷达配置与数据采集工具用于配置 chirp 参数、控制 DCA1000 采集数据。它自带图形界面可以实时查看距离-多普勒热图非常方便。mmWave SDK包含驱动、例程和 CCS 工程文件。虽然用 DCA1000 离线采集不一定要用 SDK 写代码但 SDK 中的文档和示例对理解寄存器配置很有帮助。Code Composer StudioCCS如果后续要在 DSP 上做实时处理需要 CCS 来编译和调试。MATLAB 或 Python负责核心算法实现。我习惯用 MATLAB 做离线验证因为 TI 官方提供了一些处理脚本可以参考后期转 Python 做实时原型也很方便。安装顺序建议是先装 mmWave Studio再装 SDK最后装 CCS。注意 mmWave Studio 和 SDK 的版本要匹配否则可能出现设备识别不到的问题。我用的版本是 mmWave Studio 2.1 和 SDK 3.5整体比较稳定。2.2 硬件连接与 DCA1000 模式设置硬件连接看起来简单但有几个细节容易出错IWR6843ISK 的 SOP 跳线要设置为“Functional Mode”即 SOP[2:0] 001即 SOP1 跳线短接SOP0 和 SOP2 断开。如果 SOP 设置不对雷达不会输出数据。DCA1000EVM 通过一个 60 针的高密度连接器与 IWR6843ISK 连接注意对齐方向不要插反。插好后用螺丝固定避免松动导致 LVDS 传输错误。DCA1000 的以太网口直连 PCPC 的 IP 地址要设置为静态 IP和 DCA1000 在同一个网段。DCA1000 的默认 IP 一般是 192.168.33.180PC 设成 192.168.33.30 之类的同一网段即可。给 IWR6843ISK 供电时推荐使用 5V 2.5A 以上的电源适配器不要只靠 USB 供电。因为雷达发射时瞬时电流较大USB 供电可能导致电压跌落影响 ADC 数据质量。在 mmWave Studio 中选择“DCA1000”作为采集模式连接设备后首先加载配置文件.cfg 文件然后执行“Trigger Frame”开始采集。DCA1000 会把原始数据通过以太网发送到 PC 端保存为 bin 文件或直接流式传输。2.3 Chirp 参数设计对生命体征检测的影响Chirp 参数是影响生命体征检测效果的关键。下面是我在实验中用的参数参数数值说明起始频率60 GHzIWR6843 的工作频段调频斜率 S50 MHz/μs决定距离分辨率ADC 采样率5 Msps决定最大可测距离采样点数128每 chirp 采样点数Chirp 周期100 μs由斜率和采样时间决定Chirp 数 / 帧64 或 128影响多普勒分辨率帧周期50 ms即 20 Hz 帧率带宽 B约 2 GHz距离分辨率约 7.5cm帧率 20Hz 是生命体征检测的硬性要求。呼吸频率一般在 0.1~0.5Hz6~30 次/分钟心跳在 0.8~2Hz48~120 次/分钟。根据奈奎斯特定理采样率即帧率至少要大于最高信号频率的两倍所以 20Hz 帧率可以覆盖到 10Hz 以内的信号完全满足呼吸和心跳的频带需求。距离分辨率的计算公式是 ΔR c / (2B)。带宽 2GHz 对应距离分辨率约 7.5cm这个精度足够把目标从环境中区分出来。如果带宽太小目标距离门选择不准后面提取的相位信号会混入更多噪声。3. 呼吸与心跳信号提取核心算法实现3.1 数据预处理从原始 ADC 数据到距离-慢时间矩阵DCA1000 导出的数据是 FPGA 采集的原始 ADC 数据格式为 I/Q 两路交织排列通常是 16 位有符号整数或 16 进制格式。首先要做的就是把 I/Q 分开组成复数数组。假设一个 chirp 的 ADC 采样点数为 N_sample一帧内有 N_chirp 个 chirp那么一帧的原始数据长度为 2 × N_sample × N_chirp因为 I/Q 两路。读取后先 reshape 成复数矩阵再做距离维 FFT。这一步在 MATLAB 里就是一行 fft 的事。处理完成后会得到一个三维矩阵距离维 × 慢时间维chirp 数× 多普勒维如果不做多普勒 FFT。对于单目标生命体征检测我们关注的目标通常静止坐在雷达前方位置固定所以正确的流程是对每个 chirp 做距离维 FFT得到距离谱。选择目标所在距离门range bin取出该距离门在慢时间维上的复数序列。对这个复数序列的相位进行时间序列分析提取微动信号。如果环境中有多个静止物体距离谱上会出现多个峰值。人体目标的特点是距离谱峰值的幅度会随呼吸周期性变化因为胸腔微动导致回波相位变化与静态杂波干涉以及存在一定的微多普勒展宽。可以通过设置幅度阈值和距离范围来粗选目标。3.2 目标距离门选择与静态杂波抑制选择目标距离门是一个看似简单但很影响结果的操作。我的做法是做一帧内所有 chirp 距离 FFT 后的幅度平均得到平均距离谱。排除距离过近小于 0.3m避免近场耦合干扰和过远超过 3m超过雷达有效测量范围的距离门。在有效范围内寻找最大峰值。如果有多个相近峰值优先选择距离谱峰值为整体最大或与人体预期位置接近的那个。但这里有个坑胸腔表面并不是一个理想的点目标而是多个散射点的集合。不同距离门上提取的相位信号可能不同甚至有的距离门相位噪声很大。所以我通常会将目标距离门及其相邻 1~2 个距离门的数据都提取出来对比它们的相位信号质量选择信噪比最高的那个。另外建议做静态杂波抑制。方法很简单对慢时间维上每个距离门的复数序列减去其时间均值。这样可以把静态物体的反射成分相对于雷达径向静止的墙、桌椅等去掉保留运动目标呼吸引起的胸腔微动的信息。3.3 相位提取与相位解缠最容易出错的一步距离门上的复数序列每个复数都有幅度和相位。目标的微小位移体现为相位的变化所以核心思路是提取相位序列phase angle(complex_signal)但 angle 函数返回的相位范围是 [-π, π]当真实相位变化超过这个范围时就会出现跳变表现为相位波形上突然的 2π 跳跃。如果不做相位解缠unwrapping后面滤波时会产生严重的伪频成分。MATLAB 里可以直接用 unwrap 函数解缠。Python 里可以用 numpy.unwrap。但这里要特别注意相位解缠并不是万能的如果信号噪声较大或者相位变化速率太快导致相邻采样点之间的相位差超过 π解缠就会失效。我有一次实测时发现被测人呼吸幅度较大胸腔位移接近 3mm对应相位变化约 3.8 弧度如果帧率只有 10Hz那么相邻帧之间相位变化很大解缠容易出错。所以帧率建议不低于 20Hz并且解缠后要做平滑滤波比如滑动平均或低通滤波来抑制残余的跳变噪声。解缠后的相位序列就近似正比于胸腔位移随时间的变化d(t) λ × phase_unwrapped(t) / (4π)3.4 呼吸与心跳信号分离滤波器设计的取舍提取到的相位信号是呼吸和心跳的叠加。呼吸信号幅度大、频率低心跳信号幅度小、频率高。要分离它们最直接的方法是带通滤波呼吸带通0.1 ~ 0.5 Hz心跳带通0.8 ~ 2 Hz滤波器设计推荐使用 FIR 带通滤波器或 Butterworth IIR 滤波器。我在实验中用的是 MATLAB 的 designfilt 函数设计等纹波 FIR 滤波器阶数选 1000 左右因为采样率 20Hz 且通带很低需要较长的滤波器阶数才能有好的频率选择性。需要注意的是滤波器的过渡带和通带纹波会影响波形形状。过渡带太宽会导致呼吸的谐波漏到心跳频段通带纹波太大会让心跳波形幅度失真。建议呼吸滤波器过渡带设为 0.05Hz 左右心跳滤波器过渡带设为 0.2Hz 左右。实际操作中我推荐先对相位信号做去趋势和带通滤波提取出相对干净的胸腔位移信号再分别做呼吸和心跳的带通滤波。3.5 自适应滤波与改进方案如果被测人呼吸比较急促呼吸的谐波会跨入心跳频段单纯带通滤波很难干净分离。这时候有两个改进方向一是使用自适应滤波。把呼吸带通信号作为参考信号用 LMS 或 RLS 算法从原始信号中减去呼吸成分剩下的就是心跳成分。这个方法在呼吸谐波较强时效果明显但需要小心调节步长参数否则会滤波过度把心跳也去掉。二是使用变分模态分解VMD或经验模态分解EMD。这类方法可以把信号分解成不同频率中心的模态分量然后根据模态的中心频率选择呼吸和心跳对应的分量。VMD 比 EMD 更稳定不容易出现模态混叠但需要预先指定模态个数实际使用中要调试参数。我个人的建议是先用常规带通滤波跑通整个链路确认目标选择和相位提取没问题后再尝试自适应或 VMD 提高抗干扰能力。不要一开始就上复杂算法否则问题定位会很痛苦。4. 实测过程与波形结果解读4.1 测量场景部署与人员要求实测场景的部署直接影响数据质量。我的测试环境是一个普通办公室人员坐在椅子上距离雷达约 0.8~1.2m正对雷达天线。雷达放在桌面上高度大致与人的胸部平齐。被测人员要求尽量保持静止不要大幅晃动身体。正常呼吸不要故意深呼吸或屏息。穿着薄衣服即可不要太厚的羽绒服会衰减信号。在雷达前方留出一定的空间避免其他人在雷达视场内走动。雷达参数和上一节提到的配置一致帧率 20Hz每帧采集 64 个 chirp。每个测量段持续时间 60 秒足够获取 12 个以上完整的呼吸周期和 60 次以上心跳周期。4.2 从距离谱到相位波形的完整处理流程演示我用 MATLAB 写了一个完整的处理脚本核心流程如下% 读取原始数据并reshape raw readBinFile(adc_data.bin, numChirps, numSamples); % raw: [numSamples * 2, numChirps] I/Q交织 % 分离I/Q rawI raw(1:2:end, :); rawQ raw(2:2:end, :); complexData rawI 1j * rawQ; % [numSamples, numChirps] % 距离维FFT rangeProfile fft(complexData, [], 1); % 选择目标距离门假设在第k个距离门 targetSignal rangeProfile(k, :); % 静态杂波抑制 targetSignal targetSignal - mean(targetSignal, 2); % 提取相位并解缠 phase unwrap(angle(targetSignal)); phase phase - mean(phase); % 呼吸和心跳带通滤波 fs 20; breathSignal bandpass(phase, [0.1 0.5], fs); heartSignal bandpass(phase, [0.8 2], fs);这里有个细节就是关于选择距离门后对慢时间维做 FFT也可以得到微多普勒谱。但直接用相位方法其实更简单、更直观尤其在单目标场景下效果很好。4.3 结果判定怎么看波形是有效的拿到滤波后的波形首先要判断信号是否有效。我的经验是看三点波形周期性呼吸波形应该有明显的周期性每分钟大约 12~20 个波峰。心跳波形应该呈现规律的小幅波动每分钟约 60~100 次。幅度合理性呼吸引起胸腔位移在毫米级对应相位信号解算出的位移一般在 1~10mm 范围。如果幅度超过 20mm很可能是目标选择错了或相位解缠有误。心跳信号幅度极小通常只有 0.1~0.5mm 量级。频谱特征对滤波后的信号做 FFT呼吸频谱应该在 0.1~0.5Hz 有明显的单峰心跳频谱应该在 0.8~2Hz 有明显的单峰。如果频谱杂乱无章说明信号质量不好。用一个简单的方法验证心跳信号让被测人自己同时用手指按着脉搏计数或者用指夹式血氧仪做对照对比雷达估计的心率是否一致。我做过多次对照实验在静止状态下雷达估计的心率误差基本在 ±3 bpm 以内呼吸频率误差在 ±1 次/分钟 以内。4.4 参数调整对检测效果的影响有一个实际经验是chirp 数越多距离维信噪比越高但帧率会降低。为了兼顾帧率我选的 chirp 数是 64每帧耗时约 6.4ms帧周期 50ms 还有足够余量。如果有读者想提高距离分辨率或信噪比可以增加 ADC 采样点数但要相应降低帧率确保不低于 15Hz。雷达的发射功率也会影响检测距离。IWR6843ISK 的发射功率默认配置是 10dBm 左右在 1m 以内检测生命体征绰绰有余但超过 2m 后信噪比明显下降。如果要做远距离检测3~5m需要增加发射功率通过配置寄存器提高 TX 功率并使用更大增益的天线。5. 常见问题与排查技巧实录5.1 数据采集中遇到的典型问题在调试过程中我遇到了几个比较常见的问题整理成了速查表问题现象可能原因解决办法mmWave Studio 连不上设备SOP 跳线错误 / 驱动未装好 / USB 线质量问题检查 SOP 拨码、重装驱动、换高质量 USB 线采集数据全为 0DCA1000 的 FPGA 固件未启动 / LVDS 连接松动重新上电 DCA1000、检查连接器、确认 mmWave Studio 状态距离谱上找不到目标峰值发射功率太低 / 目标距离太远 / 天线方向不对增大发射功率、靠近目标、调整雷达朝向相位波形出现大量 2π 跳变帧率太低或呼吸幅度过大提高帧率到 25Hz 以上、确认解缠函数参数正确心跳频率总是跟随呼吸频率的整数倍呼吸谐波太强加自适应滤波或 VMD 分离提高带通滤波器阶数5.2 相位跳变与解缠失败的深层原因相位跳变是生命体征雷达最容易出的问题。我第一次调试时呼吸波形看起来像锯齿状频率分析出来是乱的折腾很久才发现是相位解缠的问题。这里有一个关键点unwrap 函数的假设是相邻采样点之间的真实相位差小于 π。如果帧率不够或者目标呼吸幅度太大相邻帧之间的相位差就可能超过 π导致 unwrap 无法正确还原真实相位。解决方案有两个方向一是提高帧率到 25~30Hz让相邻帧的间距缩短二是对距离门信号先做复数乘法来得到相位差然后用累加的方式还原相位。第二种方法本质上等同于相位差分但需要注意累积误差。另外相位信号中有直流偏置和线性趋势时也会干扰解缠。建议在解缠之前先对复数序列做去均值处理并检查是否有较强的高频噪声。先用一个简单的滑动平均滤波器把高频噪声压一压再解缠效果会好很多。5.3 呼吸谐波干扰心跳频段怎么办这是做生命体征检测后期必然会遇到的问题。呼吸频率一般是 0.2~0.4Hz二次谐波在 0.4~0.8Hz三次谐波在 0.6~1.2Hz。如果呼吸波形不是标准的正弦波实际上往往不是谐波就会落到心跳频段附近导致心跳频谱被污染。我的处理经验是分三步走先去趋势消除相位信号中的缓慢漂移。做带通滤波分离出初步的呼吸和心跳信号。如果发现心跳频谱中有明显的呼吸谐波峰就用梳状滤波器或自适应噪声对消。梳状滤波器在频域上把呼吸频率及其谐波对应的频点置零。这个方法实现简单但在呼吸频率不稳定时效果会变差。自适应噪声对消更通用一些——将呼吸带通信号作为参考信号通过自适应算法估计呼吸谐波在心跳频段的泄露分量然后从原始信号中减去。5.4 多目标场景下的目标选择策略如果雷达视场内只有一个人目标选择很简单。但实际场景中可能有其他人走动或者有其他运动的物体比如风扇转动、窗帘飘动这会干扰目标距离门的选择。几个实用的策略在距离维上限制候选区域比如只检测 0.4~1.5m 范围内。人坐的位置通常固定在这个范围。对于每个距离门计算慢时间信号的方差。静止物体墙、桌子的方差很小有微动的目标方差较大。方差最大的距离门通常是人体目标。如果被测人呼吸微弱比如睡眠状态方差法可能失效可以结合距离谱幅值先选几个候选距离门再对比每个距离门相位信号的频谱峰度选出频谱最干净的目标。这些策略在我的实验中效果都不错至少把误判的概率降到很低。5.5 算法往嵌入式端移植时的注意事项如果算法验证通过后续想部署到 IWR6843ISK 的 DSP 上做实时处理有几个坑要提前注意DSP 上做 FFT 要使用 TI 的 DSP 库dsplib直接调用 fft 函数即可但要注意数据格式是 Q15 或浮点需要和算法里的精度要求匹配。相位解缠和带通滤波在 DSP 上实现时建议使用定点数或单精度浮点。C674x 对浮点运算支持不错但滤波器系数较多时要注意内存占用。实时处理时帧率可能受算法耗时限制。带通滤波器的阶数如果太高DSP 会算不过来。我在移植时把 FIR 滤波器阶数从 1000 降到了 256用多相结构实现效果影响不大但实时性提高了不少。我个人建议先把这个算法在 MATLAB 里跑通确认每个环节的中间结果都符合预期再考虑移植到 DSP。跳过验证步骤直接写嵌入式代码调试成本会成倍增加。最后分享一个实际调试中的小体会生命体征信号提取这种项目最大的瓶颈往往不在算法本身而在“脏数据”处理。DCA1000 采集的数据里如果混入了以太网丢包、LVDS 传输误码或者射频自干扰后续再牛的算法都救不回来。所以每到一个新的测试环境我建议先花十分钟在 mmWave Studio 里看看距离谱原始输出确认噪声底和静态杂波的情况再开始跑算法。这一步能帮你省下后面至少一个小时的玄学排查时间。另外如果条件允许多采集几段不同时长的数据对比算法的稳定性比只跑一段完美数据更有说服力。