☰
用USRP X310自制脉冲线性调频雷达:从波形生成到距离-多普勒实测
2026/11/2 1:00:36 网站建设 项目流程

去年冬天整理实验室,我从铁皮柜子里翻出一台已经半年多没通电的USRP X310,面板上的灰厚得能写字。当时犹豫了半天,最后决定给自己布置一个课题:把这台吃灰的软件无线电设备,变成一台真正能看见室内移动目标的雷达。项目代号就叫PLFM_RADAR,PLFM拆开是Pulsed Linear Frequency Modulation,脉冲线性调频。写这个代号时我还跟团队开玩笑说,也可以理解成“Project LFM Radar”,反正两种念法最后指向的都是同一套东西。如果你也想折腾软件无线电,或者正在为雷达课程里的匹配滤波、距离-多普勒处理找不到实物练手而发愁,这篇记录应该能给你一份完整的参考。不含虚的,就是波形生成、射频链路、数字信号处理到实测踩坑的全过程,以及我踩完之后得出的结论。

1. 为什么非要自己从头搭一台PLFM雷达

1.1 从吃灰设备出发:真正的信号处理不在仿真里

在学校和研究所做信号处理这么多年,我必须老实说,用仿真工具做一套雷达回波是件非常容易的事。发射chirp、加延时、加噪声、匹配滤波,一套流程下来,输出的距离像漂亮得可以直接打印出来挂墙上。但一旦把算法接到真实天线和射频前端上,教科书里没有的细节全都会冒出来:发射泄漏、本振相位噪声、采样时钟抖动、接收机直流偏置、天线之间的耦合,每一个都能让你的漂亮仿真图瞬间变成一团乱麻。

所以我把PLFM_RADAR定位成一次“回到物理世界”的练习。目标不是做出一台指标多先进的雷达,而是把最经典的LFM脉冲体制从头到尾亲手打通一遍。从DAC出来的基带波形是什么样的,经过天线辐射到空气里又变成什么样,被目标反射回来之后经过下变频、ADC,最后落到Python里是什么样——我要亲眼看一遍,而不是在MATLAB里脑补。

1.2 PLFM名字的来历与雷达体制选择

PLFM的全称,我一般按Pulsed LFM来理解。它本质上是脉冲雷达加线性调频波形的组合:雷达每隔一个脉冲重复周期(PRI)发射一个chirp脉冲,脉冲内部的频率随时间线性上升或下降。这个组合解决的是一个很直接的矛盾——如果单靠窄脉冲测距,想提高距离分辨率就必须把脉冲压得很窄,但脉冲越窄,能量越少,探测距离就越近;而单用连续波雷达虽然能测速度,却完全没有距离分辨能力。

用一个大时宽、大带宽的chirp脉冲,再在接收端通过匹配滤波把能量“压”回一个窄峰,就能同时拿到远探测距离和高距离分辨率。这就是脉冲压缩的基本思想,也是PLFM_RADAR的核心体制。整套原理教科书里都有,但我建议所有人都亲手实现一遍,因为“看懂公式”和“看着频谱图调参数”完全不是一回事。

1.3 项目定位:低功率教学验证平台

这里要先把话说清楚:PLFM_RADAR不是一个军用或者安防取向的项目,从头到尾就是一套低功率、短距离、用于教学和算法验证的实验平台。它的典型使用场景是:在实验室走廊里测量一个人走过时的距离-多普勒特征,或者坐在椅子上呼吸时胸腔微动带来的相位变化。

整个系统的发射功率被我控制在很低的水平,信号源输出大约10dBm,配合天线增益后等效全向辐射功率也在ISM频段的常见限值以内。不同地区对ISM频段的具体管理规定不一样,动手之前一定要先查清楚当地规则。我之所以强调这一点,是因为软件无线电设备非常容易把功率调大,但雷达实验真没必要,低功率近距测试一样能把算法验证得很透彻。

2. 硬件链路与选型:从5.8GHz频段到USRP双通道方案

2.1 频段选择的理由

做雷达第一件要定的事就是频段。我考虑过2.4GHz、5.8GHz和24GHz三档。2.4GHz最便宜、设备最多,但WiFi和蓝牙都在这个频段里,频谱环境实在太脏,做实验容易被干扰源带着走。24GHz无论是天线还是射频前端,成本都高一大截,而且信号衰减快,对实验场地要求高。

最后选5.8GHz,理由有三个:一是ISM频段,低功率实验合法合规;二是波长只有5.17厘米,天线的物理尺寸和增益很好平衡,一个巴掌大的贴片天线就能做到8dBi;三是可用带宽充裕,100MHz带宽对应1.5米的距离分辨率,对室内人体、车辆级别的目标来说正好够用。如果真想做到0.3米甚至更高的分辨率,带宽要加到500MHz以上,那在5.8GHz频段就很难操作,只能往毫米波方向走。

2.2 USRP X310双通道相参方案

硬件平台我最终选的是USRP X310加两块UBX-160子板。选它的核心原因只有一个:双通道相参。雷达要相干处理,接收信号必须和发射信号共用一个本振和采样时钟,否则回波相位是乱的,多普勒处理直接没法做。X310的两个射频通道共享时钟,天然满足这个要求,不需要外接额外的同步板卡。

UBX-160子板能覆盖DC到6GHz的射频范围,瞬时带宽160MHz,我的100MHz发射带宽在它能力之内。采样率定在100MSps,复采样,刚好覆盖100MHz带宽的基带信号。有人可能问为什么不用更便宜的B210,B210确实也能做双通道,但最大带宽只有56MHz,距离分辨率会掉到2.7米左右,对人体的分辨能力弱了不少。预算紧张的情况下B210并非不能玩,只是PLFM_RADAR想验证100MHz带宽下的处理流程,X310是当时最稳的选择。

2.3 与现成雷达开发套件的对比

动手之前我也认真考虑过直接用毫米波雷达开发套件,比如市面上常见的AWR1443Boost之类的板子。这类套件的好处是集成度高、价格相对便宜,而且厂商提供了不少现成demo,开箱就能看到点云。但它们的处理链路通常是黑盒或者半黑盒,射频前端内部做了大量固化处理,最终给你的只是点云结果,而不是干净的IQ流。

我想要的恰恰是另一头:从IQ数据开始,自己写匹配滤波,自己搭距离-多普勒图,自己观察每个中间环节的频谱。SDR方案的缺点也很明显,射频性能不如专用雷达芯片,噪声系数、相位噪声指标都更差,但这对于教学验证来说反而是优点——处理流程中每一个失真都会暴露出来,逼着你去理解它的来源。下面这个表格是我当时做选型对比时整理的,不一定适用于所有人,但能说明我为什么最后选了SDR路线:

方案成本带宽可编程性适合场景
USRP X310 + UBX-160高160 MHz高,IQ全开放雷达信号处理算法验证
USRP B210低56 MHz高,IQ全开放预算有限的原理验证
AWR1443等毫米波套件中4 GHz中,内部处理固化毫米波算法研究、点云应用
自研射频板低取决于器件低,需要射频设计能力有射频设计经验的团队

如果你的目标只是快速拿到点云做应用层开发,那现成毫米波套件是更理性的选择;但如果你想真正理解雷达信号链的每一个环节,SDR路线提供的透明度和自由度是无法替代的。

3. 波形生成与数据采集:先离线搞定,再谈实时

3.1 线性调频脉冲的生成

生成线性调频脉冲在数学上非常直接:基带信号的相位是时间的二次函数,瞬时频率随时间线性变化。频率从起始频率线性扫到终止频率,扫过的总范围就是发射带宽B,扫完整个带宽所需的时间就是脉冲宽度Tp,两者的比值K=B/Tp称为调频斜率。

我用的参数是B=100MHz、Tp=10微秒。这意味着时宽带宽积是1000,也就是说这个chirp脉冲经过匹配滤波后,理论上可以获得10*log10(1000)=30dB的处理增益。别小看这个数字,在没有额外功率放大器的前提下,这30dB是把回波从噪声里捞出来的关键。10微秒的脉冲在100MSps采样率下就是1000个采样点,生成这段波形只需要一小段numpy代码:

import numpy as np fs = 100e6 # 采样率 100 MSps Tp = 10e-6 # 脉冲宽度 10 us B = 100e6 # 发射带宽 100 MHz K = B / Tp # 调频斜率 t = np.arange(0, Tp, 1/fs) tx_chirp = np.exp(1j * np.pi * K * t**2) # 基带复chirp信号

这里有个很容易忽略的细节:基带chirp的表达式是exp(jπKt²),而不是exp(j2πKt²),系数差一倍。很多人第一次写的时候都会在这里出错,因为教材里通常写的是带通信号形式。基带复信号只要记住“瞬时频率是相位的导数”这句话,自己推一遍就不会错。

3.2 GNU Radio里的发射链路

波形生成之后,发射链路我走的是“先离线、后实时”的路线。所谓离线,就是先把一段包含多个脉冲重复周期的完整IQ波形生成好,存成二进制文件,然后用GNU Radio的File Source循环播放,再送给UHD Sink发射。这样做的好处是调试时不用反复改流图,波形是确定的,出问题更容易定位。

一个脉冲重复周期PRI我定为200微秒,对应的PRF是5kHz。发射脉冲占10微秒,剩余190微秒是静默期。这里静默期不是浪费,它是留给回波的时间窗口,也是慢时间采样率的基础。波形文件里我一次性生成了32个PRI的样本,File Source设置Repeat为Yes,就能让USRP持续循环发射这段序列。

GNU Radio流图结构很简单:File Source(复数float32)直接接到UHD USRP Sink。UHD Sink里设置中心频率5.8GHz、采样率100MSps、发射增益15dB。要注意的是,发射链路的采样率必须和波形文件生成时的采样率一致,否则发射出去的声音会变调——在雷达里,这直接导致回波频率偏移,距离像整体偏移。

3.3 接收数据的格式与切帧方法

接收端用的是同一台X310的另一个射频通道,同样设成5.8GHz、100MSps,接收增益我一开始给的35dB,后来根据回波强度慢慢往下调。接收到的IQ数据通过UHD Source接入GNU Radio,直接写进文件。

UHD默认输出的复数数据是单精度浮点型,一个采样点8字节。100MSps跑一秒就是800MB数据,所以采集时不能太贪心,我一般每次只采2秒左右,足够做256个脉冲的多普勒积累了。事后用Python读二进制文件,用np.fromfile(..., dtype=np.complex64)就能直接恢复出IQ数据。

切帧是整个数据处理的开头,也是决定结果好坏的隐藏因素。每个PRI对应int(pri * fs)个采样点,也就是200微秒乘以100MSps等于20000个点。我把数据按这个长度切成二维矩阵,行是脉冲序号,列是快时间。两个维度的专业叫法需要记住:行方向叫慢时间,对应脉冲间的时间变化,用来提取多普勒;列方向叫快时间,对应单个脉冲内的时间变化,用来提取距离。

4. 距离-多普勒处理:核心算法的落地与参数权衡

4.1 匹配滤波:从chirp到尖峰

匹配滤波的原理可以用一个特别生活化的类比解释:你冲着一座山喊一声长音,回声是平的,听不出距离;但如果喊的是“从低音快速滑到高音”的口哨,因为声音传播有延时,回口哨和你正在吹的口哨之间会有一个音调之差,这个差值就携带了距离信息。线性调频雷达做的就是这件事,只不过把听觉上的音调差换成了电信号里的频率差。

具体的实现方式有两种:一种是直接做匹配滤波,把发射chirp的共轭翻转作为滤波器系数,对每个脉冲的回波做卷积;另一种是去斜处理,用同一个chirp信号做本振,把回波频率变成与延时成正比的一个单音。PLFM_RADAR里我用的直接匹配滤波,因为它的流程更直观,也更容易观察中间结果。

在离散实现中,匹配滤波器系数就是发射chirp的共轭倒序。代码写出来只有几行:

mf = tx_chirp[::-1].conj() range_profile = fftconvolve(frames[i], mf, mode='same')

这里的fftconvolve是SciPy里的快速卷积实现,用FFT把卷积变成频域乘法,比直接逐点卷积快得多。匹配滤波完成后,chirp被压缩成一个窄峰,峰值位置对应目标的延时,峰值幅度里带着目标的散射强度。

4.2 距离维窗函数与旁瓣抑制

第一次跑出距离像的时候,我心里还挺得意,因为目标峰值很清楚。但很快发现了问题:目标旁边大概1.5米和3米的位置,各有一个不应该存在的假峰。后来查资料才意识到,LFM信号经过匹配滤波后输出的是sinc函数形状,第一旁瓣只比主瓣低约13.2dB。强目标的第一旁瓣幅度,完全可能盖过一个真实的弱目标。

解决办法就是加窗。在匹配滤波之前对发射chirp乘一个窗函数,或者在匹配滤波器系数上加一个窗,都能压低旁瓣。我用的是Hamming窗,可以把第一旁瓣压到-40dB以下,但代价是主瓣会稍微变宽,距离分辨率会损失大约1.5倍。这是雷达处理里一个永恒的权衡:旁瓣抑制和分辨率不可兼得。

实际测试中,对于走廊里人体级别目标的检测,我倾向于加Kaiser窗,参数beta取6到8之间,旁瓣在-50dB左右,主瓣展宽还在可接受范围内。如果你的场景里目标强弱悬殊,比如一个金属角反射器旁边站一个人,加窗几乎是一定的;如果所有目标强度接近,不加窗换来更锐的距离峰也是合理选择。

4.3 慢时间FFT与速度维参数

距离维处理完之后,得到的是一个脉冲×距离的二维矩阵,每一行是某个脉冲的距离像,每一列是某个距离单元上随脉冲数变化的复数值。静止目标在这一列上保持不变,运动目标则会让这一列的相位随时间线性变化,变化速率正比于径向速度。

对每一列再做一次FFT,就把“随时间变化的相位”变成了“频率”,也就是多普勒频率。多普勒频移和径向速度的关系是fd=2v/λ,我工作在5.8GHz,波长0.0517米,所以1m/s的径向速度对应大约38.7Hz的多普勒频移。慢时间维的采样率就是PRF,也就是5kHz,那么按奈奎斯特定理,最大能无模糊测量的多普勒频率是±2.5kHz,对应最大径向速度约±64.6m/s,也就是约±232km/h。对我的室内场景来说完全够用,甚至余量很大。

速度分辨率由慢时间总时长决定。我用256个脉冲做FFT,慢时间采样率5kHz,频率分辨率约19.5Hz,换算成速度大约是0.5m/s。这个分辨率让人体走路(约1-2m/s)能明显区分出来,但对慢速呼吸(约0.01m/s级)就不够看了。如果要做呼吸检测,得增加积累脉冲数或者降低PRF,但那样又会影响最大不模糊速度。参数之间都是连着的,动一个就要重新评估其他几个。

4.4 完整的测量参数表

我把自己最后定下来的一套参考参数整理成了表格,后续所有实测和踩坑都是在这一组参数下完成的:

参数数值说明
中心频率5.8 GHzISM频段,低功率实验
发射带宽100 MHz理论距离分辨率1.5 m
脉冲宽度10 μs时宽带宽积1000,匹配滤波增益30 dB
脉冲重复周期200 μsPRF=5 kHz
距离窗Kaiser(beta=6)旁瓣约-50 dB
慢时间FFT点数256速度分辨率约0.5 m/s
发射功率约10 dBm等效全向辐射功率在ISM限值内
天线两个8 dBi定向贴片天线收发分置,空间隔离
采样率100 MSps复采样

这套参数不是优化的结果,而是权衡的结果。比如100MHz带宽让距离分辨率刚够分离一个人体目标,如果把脉冲宽度增加到20微秒,处理增益能再高3dB,但近距离盲区会变大,因为发射占空比太高了。参数的每一次调整背后都有一组物理约束,这也是实物雷达和仿真最大的区别。

5. 实测记录与踩坑复盘:理论之外的真实信号

5.1 走廊里的人形目标测试

第一次比较完整的实测是在实验室走廊里做的。发射天线和接收天线并排放在三脚架上,间距大约0.5米,距离地面1.2米左右。目标是一个人,从5米外以正常步速横向走过波束主轴。采集2秒数据,处理完距离-多普勒图,图上能明显看到两个特征:一个在距离约5米、多普勒约0Hz的位置,那是走廊墙面的静态反射;另一个是从5米距离逐渐靠近再远离、多普勒频率先正后负的动态亮点,那就是人体目标。

让人意外的东西也有——人体目标在多普勒维上并不是一个干净的亮点,而是一片展宽的小峰群。这是因为人走路时手臂和腿在摆动,身体不同部位有不同的径向速度,这就是微多普勒效应。我原来以为微多普勒是毫米波雷达的专属功能,没想到普通的LFM雷达只要多普勒分辨率足够,也能看到这个现象。这个发现后来变成我们团队做人体活动识别的一个起点。

5.2 坑一:零中频接收机的DC偏置与距离近端污染

第一次跑RD图时,图左边缘零距离处有一条刺眼的竖直亮线,把所有近距离目标全盖住了。这条亮线不是真实目标,而是零中频接收机的直流偏置。UBX子板内部把射频信号直接下变频到基带,本振泄漏会混出一个直流的成分,在距离维上表现为零距离附近的巨大峰值。

解决它我用了两步。第一步,在处理链路上把距离近端前20个距离门直接清零,因为这些距离对应的是收发天线之间的直射波和近区耦合,本来就不是我关心的目标区域。第二步,如果做运动目标检测,可以对每个距离单元的慢时间序列做均值相减,这其实就是最简单的MTI对消,能把所有静止杂波和直流偏置一起滤掉,只留下运动目标。但要注意,均值相减会连真实静止目标一起消掉,如果我想看静态场景,就不能用这一步。这两个模式可以在同一个处理程序里切换,看你想看什么。

5.3 坑二:IQ不平衡带来镜像假目标

还有一个很隐蔽的坑:IQ不平衡。接收机正交下变频需要两路严格正交的本地信号,但实际电路里幅度和相位很难做到完全一致,两个通道之间会串扰。效果是真实目标在多普勒维上会多出一个位于镜像频率的假目标,幅度比真目标低一些,位置关于零多普勒对称。

第一次看到这个现象时我还以为是真实目标,因为旁边确实没有反射体。后来把天线对准一个静止的金属板,发现假峰还在,才确定是IQ不平衡。UHD驱动里其实有IQ校正选项,打开能改善一部分;更彻底的办法是离线用校正算法,通过一段已知信号估计幅度误差和相位误差,然后补偿。实测下来离线补偿效果最好,能把镜像峰压到-40dB以下,但每次更换射频频率或采样率后都要重新校准一次,这个不能偷懒。

5.4 坑三:脉冲起始错位导致距离像漂移

另一个让我折腾了两天的问题是距离像的漂移。同样是5米处的静止角反射器,不同时间采集的数据处理后,峰值位置会偏移好几个距离门,换算成距离差有3到7米,完全不在误差可接受范围内。

排查下来,根源在采集数据的切帧对齐。GNU Radio里UHD Source和Sink同时运行,但两者之间的时间基准并不是绝对对齐的,每次启动采集,接收数据流和发射数据流之间存在一个随机的起始延迟。这个延迟反映到切帧上,就导致每个回波在矩阵里发生水平平移。

我的解决办法是用直射波做锚点。接收数据里除了目标回波,还有从发射天线直接漏到接收天线的强信号,它在距离像上表现为一个固定的尖峰。每帧数据先找到这个直射波峰值的位置,以此为零点重新对齐所有脉冲,再取后面的数据段做处理。这个办法简单粗暴,但非常有效,对齐后距离量测的重复性从米级提升到了亚米级。

5.5 坑四:相位噪声对低速目标多普勒谱的展宽

还有一个必须直面但很难根治的问题:相位噪声。USRP里集成本振的相位噪声比专用雷达芯片差不少,表现为强目标在多普勒谱上的峰会被展宽,形成一种“裙边”效应。静态的墙面反射本来应该在0Hz处是一个极窄的峰,但实际测量时会在零频附近铺开一片频谱,把低速目标淹没在里面。

我试过在信号处理层面做补偿,最简单的是采用相位梯度自聚焦算法,估计并去除相位误差,效果有一些,但对低信噪比目标不稳定。更实用的做法是在硬件上改善:把USRP的外部10MHz参考输入接一台低相噪的恒温晶振(OCXO),实测相位展宽明显变小。如果你的SDR支持外部参考输入,强烈建议接一个,对雷达实验的帮助比想象中大得多。

6. 从单通道到阵列:项目扩展与几点心得

6.1 从单通道走向MIMO阵列

PLFM_RADAR跑通单通道之后,我做的第一个扩展是往MIMO方向走。雷达要给目标测角,就得有多个空间位置不同的接收通道。用现成的多通道USRP成本太高,所以我用了时分MIMO的方案:发射端接一个SPDT射频开关,在两个发射天线之间轮换,接收端两个通道同时接收。这样两个发射位置加两个接收位置,就组成一个2×2的虚拟阵列,等效于4个接收阵元。

时分MIMO的代价是PRF会减半,因为每个目标要完成一组完整的发射-接收序列,需要的时间翻倍。最大不模糊速度也会跟着减半。对于室内低速目标这个代价可以接受,但如果要测高速目标,就得换用正交波形MIMO方案,每个发射天线同时发不同编码的波形,接收端用匹配滤波分离。那个方案的信号处理复杂度会高很多,目前还在实验室迭代中。

6.2 与外部传感器的时间同步

第二个我在意的扩展方向是和外部传感器的同步。比如想同时录一个人走路时的视频和雷达回波,来分析姿势变化对应的微多普勒特征,就需要保证每一帧雷达数据和每一帧视频在时间上严格对应。

USRP的GPIO接口可以用来做外部触发:把GPIO配置成输出模式,在每帧数据开始时输出一个脉冲沿,接一个LED指示灯或者直接接摄像头的外部触发线,就能实现逐帧对齐。如果没有硬件触发条件,也可以用软件方案,在采集数据的同时记录计算机的系统时间戳,再用视频里的动作时刻做离线对齐。实话说软件方案省事但精度有限,追求准确还是得走硬件触发。

6.3 几点个人经验

项目做到这个阶段,我想把几个对后来人最有用的经验写下来,都是靠时间和踩坑换来的。

第一,先离线,后实时。千万不要一上来就追求实时信号处理。先把数据采集下来,存在硬盘里,用Python慢慢处理,把每一级中间结果都画出来看一遍。等确认离线处理流程完全没有问题,再考虑往GPU或者更高效率的框架上迁移。实时不是目的,理解信号才是目的。

第二,每次只改一个变量。我吃过亏,为了追求更好的距离像,同时改了窗函数和脉冲宽度,结果目标峰确实变窄了,但我说不清是哪个改动贡献了效果。雷达系统是一环扣一环的,保持其他参数不变,一次只动一个,记录每次的结果,这种看起来笨的方法反而最快。

第三,波形文件和参数一定要保存归档。我有一段时间经常改完参数忘记保存配置,过了两天想回看某个结果,死活想不起来当时用的是哪组参数。后来每次采集我都在文件名里带上中心频率、带宽、采样率、脉冲宽度、PRI这五要素,彻底告别了这个问题。

做PLFM_RADAR这件事让我重新理解了一个道理:雷达系统里每一个模块单独拿出来都不难理解,难的是它们之间的耦合。频段选择影响天线尺寸,天线尺寸影响隔离度,隔离度影响接收机动态范围,最终又影响你能看到的距离像质量。这种全局视角,靠仿真和读文档是得不到的,只能手上有一套能自由折腾的设备,在一次次改参数、看频谱、踩坑、复盘的过程中慢慢建立起来。如果你手里也有一台吃灰的SDR,我建议可以试试从最简单的LFM脉冲雷达做起,成本不高,收获却不少。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询