双HackRF搭建连续波多普勒测速雷达:原理、实现与实测
发布时间:2026/10/7 3:26:51 锦皓数字建站

先别急着质疑这个标题——两个HackRF做连续波测速雷达不是钱多烧的是因为HackRF本身就是半双工设备一个板子干不了雷达的活。这篇文章会把整套东西从原理、硬件、软件到实测标定讲透适合玩过一点SDR、想从被动接收跨到主动发射的爱好者也适合想理解多普勒雷达到底怎么把速度变成频谱峰的人。1. 为什么是两个HackRF半双工短板与CW雷达原理1.1 一个HackRF做不到同时收发很多人第一反应是用SDR做雷达那不就是发射一个信号再接收吗HackRF One理论上覆盖1MHz到6GHz发射接收都能干但它本质上是个半双工设备同一时刻要么在发射要么在接收不能同时进行。这个限制不是软件能绕开的模拟前端和基带处理都被设计成单方向通路硬要同时工作结果就是严重的自激、频谱污染和驱动不稳定。连续波雷达恰恰需要连续发射同步接收发射端一直输出单音接收端一刻不停地盯着回波。所以最直接的架构就是两块HackRF一块专职发射一块专职接收。这也是这个项目的核心思路。顺便说一句市面上有现成的雷达芯片比如英飞凌的BGT24LTR1124GHz频段非常小巧灵敏度还高。但用芯片的缺点是它把信号处理全封装在内部了你只能拿到一个测出来多少就是多少的结果看不到中间的频谱过程。而用双HackRF搭雷达整个链路的每一个环节都暴露在你面前发射信号长什么样、回波怎么被变频、多普勒频率怎么在FFT上拱出来。这种可观测性才是学习SDR和雷达信号处理真正值钱的地方。1.2 多普勒公式目标速度如何变成频移连续波测速的原理其实一句话就能讲完发射一个频率稳定的单音信号如果目标朝你运动反射回来的信号频率会变高如果远离你反射信号频率会变低。这个频率变化就叫多普勒频移和我们平时听救护车靠近时音调变尖、远离时音调变低沉是同一个物理现象。多普勒频移和径向速度的关系是fd 2 * v * f0 / c其中f0是发射频率v是目标相对雷达的径向速度c是光速。这个公式里的2是因为电磁波走的是双程路径先到目标再反射回来多普勒效应发生两次。以2.45GHz频点为例换算一下就知道这个频移有多小目标速度多普勒频移0.5 m/s8.2 Hz1 m/s16.3 Hz5 m/s81.7 Hz10 m/s163.3 Hz20 m/s326.7 Hz40 m/s653.3 Hz也就是说即使目标速度到了每小时144公里多普勒频移也只有六百多赫兹。这个数字决定了整套接收链路的处理方式我们根本不需要宽带宽而是需要把频率分辨率做得很细FFT窗口要够长采样率可以大幅降下来。这也是为什么两个HackRF用2MHz采样率就完全够用的原因听起来跟雷达两个字不太匹配但实际上CW测速雷达的核心就是窄带多普勒分析。1.3 系统参数设计发射2450MHz接收偏移1200Hz基于上面的计算我建议把整套系统的参数定成这样发射频率2450 MHz2.4GHz ISM频段内天线、功放、衰减器都好找接收中心频率2450 MHz 1200 Hz发射采样率2 MHz接收采样率2 MHz接收端做FFT前的信号带宽4~8 kHz为什么接收频率要故意比发射频率高1200Hz而不是直接用同一个频率这个问题放到后面第2.3节详细讲核心原因是HackRF的零中频架构在0Hz附近有很强的直流泄漏目标速度低时回波会直接淹没在直流里。偏移1200Hz之后静止目标的回波会出现在1200Hz附近运动目标的回波则围绕1200Hz上下移动彻底避开直流区。2. 硬件搭建与频率规划两个板子的时钟问题2.1 桌面试验台天线、馈线、USB供电与增益这套系统的硬件清单并不复杂但每一样都有讲究两块HackRF One一收一发两只同极化定向天线建议用2.4GHz的平板天线或喇叭天线增益在10~20dBi之间两根尽量短的SMA馈线最好用质量好一点的一个带外部供电的USB Hub一块0.5m见方的铝板或者锡箔纸板作为强反射体如果条件允许再准备一块吸波材料或者几片金属挡板天线的第一原则是极化匹配两天线极化方向要保持一致。第二原则是隔离发射天线和接收天线之间如果直接对视发射信号会通过空间直接耦合进接收机强度通常比目标回波大几十个dB接收前端很容易被推到非线性区8bit ADC的弱点这时候就暴露无遗。我的经验是两个天线并排放置目标在它们前方移动中间用金属挡板隔开直射路径或者让两天线错开一个小角度让直射波打不到接收喇叭的正面。USB供电是个经常被忽略的坑。HackRF工作电流并不小发射时尤其明显两块板子同时插在笔记本的两个USB口上遇到供电弱的机器轻则掉设备重则采样率突然卡顿频谱上出现一堆莫名其妙的毛刺。我建议用一个带独立电源的USB Hub把两块板子都接在Hub上而不是直接插电脑。具体到增益设置我的起始值是发射端关闭额外的功放-a 0VGA增益设为20dB左右接收端RF增益8~14dBIF增益20dB基带增益20dB发射端不建议一上来就把功率拉满。HackRF在2.4GHz的发射功率本来就不大但它的杂散和相位噪声水平比较高大功率发射对近距离实验没有明显好处反而把泄漏信号喂得又肥又大。我实际做下来0dBm上下的发射功率在3~5米距离上配合定向天线测一块金属板完全够用。2.2 时钟不同步问题固定频差其实是零速参考两块HackRF独立工作最大的麻烦不是半双工而是时钟不同步。每块板子都有自己的参考晶振频率精度通常在ppm量级。听起来ppm很小但换算到2.45GHz就不可忽视了如果两块板子晶振偏差1ppm接收机看到的零频和发射机的零频之间就差大约2450Hz。也就是说即使目标完全静止接收端也能在某个固定的非零频率位置看到一个强峰。这个现象对新手来说很容易造成困惑为什么静止目标会出现在一个稀奇古怪的频率上速度公式还算得出来吗其实这反而是好事。我们不需要让两块板子频率严格一致只需要把那个静止峰的位置当成零速参考点。具体操作是先用一个强反射体比如金属板放在目标区域让它静止不动记录此时频谱峰值的频率f_ref然后让目标运动记录新的峰值频率f_peak真正的多普勒频移就是f_peak减去f_ref。速度公式变成v (f_peak - f_ref) * c / (2 * f0)这个思路绕开了必须外接时钟同步的硬件改造属于用软件校准解决硬件的频率偏差做桌面实验完全够用。唯一要注意的是晶振频率会随温度缓慢漂移实验开始前校准一次连续长时间测试的话隔十几分钟重新校一次即可。如果你追求更干净的频谱和更准的绝对速度读数可以考虑拆机更换TCXO或者给两块板子接入同一个10MHz参考源。HackRF本身没有外部时钟输入接口需要自己动手改板焊接能力一般的朋友不建议一上来就折腾先用静止峰校准法跑通全链路再说。2.3 故意制造频率偏移让目标信号逃离直流区HackRF的接收前端是零中频架构意思是它直接把射频信号下变频到基带0Hz附近。这种架构有个天生的毛病本振泄漏会在0Hz附近产生一个又宽又强的直流分量再加上I/Q路径的不平衡往低频走的信号很容易被这团直流毛刺淹没。假设我们真的把接收频率设成和发射频率完全一样那么静止目标就落在0Hz附近低速目标比如0.5m/s对应的多普勒只有8Hz这个信号几乎肯定被直流分量压住FFT上啥也看不见。我一开始就这么干的结果在频谱上一顿找只能看到一团直流目标和底噪几乎分不开。解决办法就是前面提到的频率偏移接收中心频率设为2450MHz1200Hz让静止目标落在1200Hz的位置运动目标则出现在1200Hz加减多普勒频移的位置。这样一来低速回波脱离了直流区正负速度有明确方向目标靠近峰值频率高于参考频率目标远离峰值频率低于参考频率DC附近干扰和信号不再重叠那为什么偏移量选1200Hz而不是更大或者更小主要考虑是最大可测速度。以40m/s为例多普勒频移约653Hz1200Hz偏移之后最极端情况下目标峰还在547Hz到1853Hz之间正频率区域里离直流区和镜像区都有足够距离。如果目标速度还要更高可以把这个偏移量加大到2000Hz甚至3000Hz代价是接收端需要更大的分析带宽对FFT窗口没有本质影响。3. 软件实现从发射单音到FFT频谱3.1 工具链选型先离线再实时SDR相关的开源工具非常多但这个项目真正需要的就是三样hackrf_transfer命令行工具负责驱动HackRF收发数据GNU Radio可选的实时信号处理框架适合做频谱显示和动态调整Python NumPy离线处理IQ数据做FFT和速度标定我的建议是不要一上来就搭GNU Radio实时流图。先用hackrf_transfer把发射和接收的IQ数据录下来再用Python离线分析把整条链路的基本逻辑验证清楚。原因很简单实时流图里天线直射、泄漏、底噪、镜像各种问题同时出现很难判断是硬件问题还是软件问题。离线分析一次只处理一个环节出问题容易定位。等离线链路全部跑通理解了每个参数的含义再上GNU Radio做实时显示会顺手很多。这套思路不仅是测速雷达适用。平时做任意SDR信号分析解调比如常见的FM、数字集群信号解码学习最稳妥的路径都是先录一段IQ - 软件里反复分析 - 懂了再上实时。IQ数据是SDR世界的通用语言录下来之后怎么折腾都行。3.2 发射端生成一个单音并循环发出去连续波测速雷达的发射信号不需要任何调制就是一个纯净的基带单音。HackRF的发射链路会把基带信号搬移到你设定的中心频率上所以我们的IQ文件里只需要让I路为恒定正值、Q路为0代表一个0Hz的CW音。生成这个文件的Python代码很简单import numpy as np import struct fs 2_000_000 # 发射采样率 duration 1 # 生成1秒的数据循环播放 t np.arange(int(fs * duration)) i (100 * np.ones_like(t)).astype(np.int8) q (0 * np.ones_like(t)).astype(np.int8) with open(cw_tone.iq, wb) as f: for i_s, q_s in zip(i, q): f.write(struct.pack(bb, i_s, q_s))然后用hackrf_transfer循环发送hackrf_transfer -t cw_tone.iq -f 2450000000 -s 2000000 -a 0 -g 20 -R参数含义-t指定传输文件-f发射中心频率-s采样率-a 0关闭额外功放-g 20设置VGA增益-R循环发送这里为什么基带单音用恒定的I值而不是正弦波因为我们要发射的就是一个没有频率偏移的载波基带上是0Hz信号DAC在射频端直接输出2450MHz附近的单音。明白了这一点后面如果想把发射信号做成扫频的FMCW只需要把IQ文件里的相位控制起来让频率按线性规律变化即可那是进阶话题。3.3 接收端数字下变频、DC阻塞与FFT提取接收端有两种做法一种是用hackrf_transfer把IQ记录到文件另一种是直接在GNU Radio里实时处理。我先说离线路径。采集命令大概长这样hackrf_transfer -r rx.iq -f 2450001200 -s 2000000 -g 20 -l 8注意-f参数设成了2450001200这就是前面说的偏移量。保存下来的rx.iq是一个交织的int8 I/Q流采样率2MHz但我们关心的信号能量集中在1200Hz加减几百赫兹的范围所以需要先做数字下变频和抽取把采样率降下来再用FFT看频谱。Python处理的核心逻辑大致是这样import numpy as np iq np.fromfile(rx.iq, dtypenp.int8).astype(np.float32) iq iq[0::2] 1j * iq[1::2] fs 2_000_000 T len(iq) / fs t np.arange(len(iq)) / fs # 把感兴趣的1200Hz附近搬移到0Hz f_shift 1200.0 iq_shifted iq * np.exp(-2j * np.pi * f_shift * t) # 低通滤波并抽取降到4096Hz from scipy.signal import decimate iq_base decimate(iq_shifted, fs // 4096, ftypefir) # FFT N 8192 segment iq_base[:N] spectrum np.fft.fftshift(np.fft.fft(segment)) freqs np.fft.fftshift(np.fft.fftfreq(N, 1 / 4096))对于这个参数FFT频率分辨率是4096除以8192等于0.5Hz对应到2.45GHz的速度分辨率大约0.03m/s。这个精度对桌面测速实验来说非常够用。如果要用GNU Radio做实时版本流图核心节点就这几步OSMOSDR Source接收HackRF数据Frequency Xlating FIR Filter把1200Hz频段选出来并降到低采样率DC Blocker去掉直流残留然后接一个QT GUI Frequency Sink看频谱或者再接一个FFT和峰值提取模块得到实时速度。实际测试中我发现接收链路的基带增益不宜盲目调大。HackRF的8bit采样决定了它的大动态范围能力有限增益加得越高底噪抬升越快小信号的改善有限反而容易让强泄漏信号削顶。所以接收增益应该以静止泄漏峰不过分饱和为准先把静态峰调到一个合适高度再观察运动目标。4. 实测与标定把公式变成看得见的频谱峰4.1 标定目标不用滑轨金属板和电风扇就能干雷达标定最大的难题是目标速度到底是多少。真实的室外测速需要雷达测速枪和标准车速对照但我们桌面上没这个条件。我试过几种简便方法最靠谱的是下面两个一是金属板手动移动法。拿一块0.5m见方的铝板或者表面贴满锡箔的硬纸板垂直对着天线来回推。配合手机上秒表和卷尺可以算出一次移动的平均速度再和FFT峰值计算出的速度对照。缺点是手动推速度不稳频谱上的峰会展宽像个小鼓包而不是尖峰。这属于正常现象多普勒展宽本身就反映了加速过程不要当成故障。二是电风扇转速法。把家用电风扇放在天线前方风扇的转速可以用非接触式测速仪或者手机APP测出来。扇叶的线速度等于转速乘以半径而雷达能测到的是扇叶表面沿径向运动的分量叶尖部分贡献的速度信息是最丰富的。频谱上会出现一组有规律的峰其中最峰的位置对应叶尖的最大径向速度。这个方法的好处是目标持续运动信号非常稳定适合重复测试。4.2 完整实验流程一块金属板来回走一遍我的实测场景是这样布置的找一块相对空旷的走廊两张桌子相隔3米左右发射和接收天线并排固定在桌沿中间隔一块吸波海绵两个天线都稍微偏向目标通道方向。发射机用前面生成的单音文件循环发射接收机录IQ然后用Python做离线FFT分析。操作分四步金属板静止放在目标区域正中央观察FFT记录静止峰频率f_ref。按前面的参数设计这个峰应该出现在1200Hz附近但由于晶振频差可能会有几百到几千Hz的偏移以实际观测为准。保持金属板静止调整接收增益让静止峰不削顶、底噪不要抬得太离谱。手持金属板从3米外朝雷达方向匀速靠近速度控制在1m/s上下持续移动2~3秒。录完IQ。同样操作持板远离雷达再录一段。整个过程发射功率保持低档实验持续时间尽量短因为2.4GHz频段还有WiFi和其他设备在工作长时间大功率发射干扰别人不合适。我一般是先把频段扫一遍挑一个相对干净的频点然后快速完成测试。4.3 数据解读从频谱峰读出速度还有方向离线分析之后频谱上最明显的谱线就是目标的多普勒峰。假设实测静止峰f_ref出现在2380Hz处金属板靠近雷达时峰值跑到2500Hz那么v (2500 - 2380) * 3e8 / (2 * 2.45e9)计算结果约7.35m/s。这个值对应手动推板的速度属于正常范围。如果金属板远离雷达峰值会掉到2380Hz以下。这里有个容易犯错的地方FFT谱峰并不一定只有一根线。目标加速时不同时刻的速度不同频谱宽度会拉开目标比较大时雷达照射到的不同部位速度有差异谱峰也会略微展宽。我建议不要只看单条谱线而是把FFT结果按时间连续画成瀑布图观察峰值随时间的变化轨迹。轨迹明显向上移动就是靠近向下就是远离这个趋势比单帧数据可靠得多。5. 调试中的坑从无信号到幽灵峰5.1 低速目标信号消失通常是被直流淹了最常见的故障现象是目标明明动了FFT上除了直流啥也看不见。这种情况九成是因为接收频率和发射频率设成了完全一样目标速度又低多普勒频移只有几赫兹到几十赫兹信号能量整个埋在HackRF的直流泄漏里。处理办法就是第2.3节说的频率偏移没有别的捷径。另一种可能是天线极化不匹配。发射天线垂直极化接收天线水平极化交叉极化损耗会非常严重反射回波直接衰减掉几十dB。所以第一件事就是确认两个天线极化方向一致。我排查这类问题有个顺序先看静止峰在不在如果静止峰都找不到说明发射或接收链路本身有问题静止峰正常但运动峰弱再看极化和增益都正常但信号还是不好才考虑天线隔离不够导致接收机过载。5.2 强泄漏和镜像峰两个容易被误判的幽灵静止时频谱上出现一个巨大的峰其实不必担心那是直射泄漏信号正好可以作为零速参考。但泄漏信号太强时接收机进入非线性区会产生谐波和互调分量频谱上出现一堆来路不明的额外峰看起来就像是一个高速目标。另一个经典幽灵峰来自I/Q不平衡。HackRF的8bit采样和模拟I/Q混频不可能做到完美正交镜像抑制能力有限真实信号会在镜像频率位置出现一个弱一截的假峰。如果只看单帧频谱很容易把镜像峰当成第二个目标或者高速目标。我的判断方法是动起来看让目标改变移动方向真实多普勒峰会相应地左右移动镜像峰和泄漏产物则跟着真实峰值方向移动但幅度关系保持不变。用手持金属板慢慢靠近再远离看哪根谱线跟随动作变化那根就是真正的目标回波。如果实在要彻底处理镜像可以加gr-iqbal这类I/Q校正模块做平衡校正但对桌面测速实验而言理解正负频域、会区分真假峰更实用一些。5.3 USB带宽、采样率与供电三个最容易翻车的基础问题两个HackRF同时干活的时候USB带宽的压力会很明显。HackRF在20MHz采样率下USB 2.0接口的带宽已经被占掉大半两片板子同时跑20MHz带宽基本必翻车表现就是掉设备、采样数据断流、频谱粉碎。这个项目根本不需要那么高带宽发射2MHz、接收2MHz完全可以。接收链路后续低通抽取到4kHz即可USB那边非常轻松。供电是老生常谈但总有人踩。两块HackRF插在同一个供电能力弱的USB Hub上会遇到采样时钟抖动频谱边缘出现规律的杂散看起来像信号有问题。换一个带电源适配器的Hub问题立刻消失。我自己第一次搭这套系统时就经历过笔记本的USB口带一块板子还行带两块一发射就掉线折腾一晚上以为是天线问题最后排查到是供电。如果GNU Radio实时流图卡顿、CPU占用直升也别怀疑板子把实时分析改成离线处理后处理或者降低抽取前的信号带宽计算量一下就下来了。雷达信号处理里实时性要求高的话有专门的低成本做法但桌面实验不需要把自己逼到那个程度。6. 可以继续折腾的方向6.1 从CW到FMCW测速之外再测距离CW雷达只能测速度不能测距离因为连续波单频信号没有时间标记距离信息在频谱上是分不开的。想同时测距和测速可以升级到FMCW发射频率随时间线性扫频接收回波和当前发射频率混频后产生一个差频这个差频正比于目标距离。双HackRF做FMCW完全可行只是对发射端扫频的线性度和收发同步要求更高。我用CW版本把信号处理链路跑通之后再看FMCW的差频公式和实现思路会顺畅很多。6.2 实时测速显示与多目标跟踪在线版本加上QT GUI之后可以把FFT每一帧的峰值位置转成速度值显示成速度历史曲线。对低速目标做滑窗FFT对高速目标缩短FFT窗口兼顾频率分辨率和响应时间。多个目标在频谱上会呈现多个峰只要径向速度不同就能区分开。这个项目做到这一步基本就是把雷达信号处理从论文里的框图搬到了自己桌上。我搭这套系统最大的体会是连续波测速雷达的射频部分其实很简单真正的难点全在如何理解频谱上的每一根峰。手动金属板来回推一次看FFT上峰值跟着动作左右跑动那种直观的反馈比读十页公式都有效。这个项目不追求测速精确到小数点后两位它最大的价值是把多普勒效应从一个物理名词变成了你亲手调出来的一条谱线。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。