☰
双HackRF搭建连续波多普勒测速雷达:原理、实现与实测
2026/10/7 3:26:36 网站建设 项目流程

先别急着质疑这个标题——两个HackRF做连续波测速雷达,不是钱多烧的,是因为HackRF本身就是半双工设备,一个板子干不了雷达的活。这篇文章会把整套东西从原理、硬件、软件到实测标定讲透,适合玩过一点SDR、想从"被动接收"跨到"主动发射"的爱好者,也适合想理解多普勒雷达到底怎么把速度变成频谱峰的人。

1. 为什么是两个HackRF:半双工短板与CW雷达原理

1.1 一个HackRF做不到"同时收发"

很多人第一反应是:用SDR做雷达,那不就是发射一个信号再接收吗?HackRF One理论上覆盖1MHz到6GHz,发射接收都能干,但它本质上是个半双工设备,同一时刻要么在发射,要么在接收,不能同时进行。这个限制不是软件能绕开的,模拟前端和基带处理都被设计成单方向通路,硬要同时工作,结果就是严重的自激、频谱污染和驱动不稳定。

连续波雷达恰恰需要"连续发射+同步接收":发射端一直输出单音,接收端一刻不停地盯着回波。所以最直接的架构就是两块HackRF,一块专职发射,一块专职接收。这也是这个项目的核心思路。

顺便说一句,市面上有现成的雷达芯片,比如英飞凌的BGT24LTR11,24GHz频段,非常小巧,灵敏度还高。但用芯片的缺点是它把信号处理全封装在内部了,你只能拿到一个"测出来多少就是多少"的结果,看不到中间的频谱过程。而用双HackRF搭雷达,整个链路的每一个环节都暴露在你面前:发射信号长什么样、回波怎么被变频、多普勒频率怎么在FFT上拱出来。这种"可观测性"才是学习SDR和雷达信号处理真正值钱的地方。

1.2 多普勒公式:目标速度如何变成频移

连续波测速的原理其实一句话就能讲完:发射一个频率稳定的单音信号,如果目标朝你运动,反射回来的信号频率会变高;如果远离你,反射信号频率会变低。这个频率变化就叫多普勒频移,和我们平时听救护车靠近时音调变尖、远离时音调变低沉是同一个物理现象。

多普勒频移和径向速度的关系是:

fd = 2 * v * f0 / c

其中f0是发射频率,v是目标相对雷达的径向速度,c是光速。这个公式里的"2"是因为电磁波走的是双程路径,先到目标再反射回来,多普勒效应发生两次。

以2.45GHz频点为例,换算一下就知道这个频移有多小:

目标速度多普勒频移
0.5 m/s8.2 Hz
1 m/s16.3 Hz
5 m/s81.7 Hz
10 m/s163.3 Hz
20 m/s326.7 Hz
40 m/s653.3 Hz

也就是说,即使目标速度到了每小时144公里,多普勒频移也只有六百多赫兹。这个数字决定了整套接收链路的处理方式:我们根本不需要宽带宽,而是需要把频率分辨率做得很细,FFT窗口要够长,采样率可以大幅降下来。这也是为什么两个HackRF用2MHz采样率就完全够用的原因,听起来跟"雷达"两个字不太匹配,但实际上CW测速雷达的核心就是窄带多普勒分析。

1.3 系统参数设计:发射2450MHz,接收偏移1200Hz

基于上面的计算,我建议把整套系统的参数定成这样:

  • 发射频率:2450 MHz(2.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 0),VGA增益设为20dB左右
  • 接收端:RF增益8~14dB,IF增益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上啥也看不见。我一开始就这么干的,结果在频谱上一顿找,只能看到一团直流,目标和底噪几乎分不开。

解决办法就是前面提到的频率偏移:接收中心频率设为2450MHz+1200Hz,让静止目标落在+1200Hz的位置,运动目标则出现在1200Hz加减多普勒频移的位置。这样一来:

  • 低速回波脱离了直流区
  • 正负速度有明确方向:目标靠近,峰值频率高于参考频率;目标远离,峰值频率低于参考频率
  • DC附近干扰和信号不再重叠

那为什么偏移量选1200Hz而不是更大或者更小?主要考虑是最大可测速度。以40m/s为例,多普勒频移约653Hz,1200Hz偏移之后,最极端情况下目标峰还在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', dtype=np.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, ftype='fir') # 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分析。

操作分四步:

  1. 金属板静止放在目标区域正中央,观察FFT,记录静止峰频率f_ref。按前面的参数设计,这个峰应该出现在1200Hz附近,但由于晶振频差可能会有几百到几千Hz的偏移,以实际观测为准。
  2. 保持金属板静止,调整接收增益,让静止峰不削顶、底噪不要抬得太离谱。
  3. 手持金属板,从3米外朝雷达方向匀速靠近,速度控制在1m/s上下,持续移动2~3秒。录完IQ。
  4. 同样操作,持板远离雷达,再录一段。

整个过程发射功率保持低档,实验持续时间尽量短,因为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上峰值跟着动作左右跑动,那种直观的反馈比读十页公式都有效。这个项目不追求测速精确到小数点后两位,它最大的价值是把"多普勒效应"从一个物理名词变成了你亲手调出来的一条谱线。

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

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

立即咨询