从零构建SDR系统:USRP硬件与GNU Radio软件协同实战
2026/4/17 15:47:27 网站建设 项目流程

1. 为什么你需要一套SDR系统

我第一次接触软件无线电(SDR)是在大学实验室里,当时看到学长用一台电脑和一个小黑盒子就能接收卫星信号,简直像变魔术一样。后来才知道,这套设备的核心就是USRP和GNU Radio的组合。简单来说,USRP负责把无线电波转换成电脑能处理的数字信号,GNU Radio则是处理这些信号的"大脑"。

你可能要问:现在到处都是现成的无线设备,为什么还要自己搭建SDR系统?我举几个实际例子你就明白了。去年有个做物联网的朋友,需要测试一种新型的LoRa通信协议,市面上根本没有现成的测试设备,他们就是用USRP搭建了一个测试平台。还有个做天文观测的团队,用这套系统接收到了脉冲星的信号。我自己则用它来监测家里的智能设备通信,发现有几个设备在偷偷上传数据。

USRP和GNU Radio的组合之所以强大,是因为它把硬件和软件的优势都发挥到了极致。USRP的硬件可以覆盖从几乎直流到6GHz的频率范围,这意味着它能处理从AM广播到5G信号的几乎所有无线通信。而GNU Radio提供了上百种现成的信号处理模块,从简单的滤波到复杂的5G信号解码都能实现。

2. 硬件选型:USRP设备选购指南

2.1 母板选择:从入门到专业

USRP的母板就像是电脑的主板,决定了系统的整体性能。对于初学者,我强烈推荐B210这个型号。它价格适中(约3000美元),支持双通道收发,频率范围70MHz-6GHz,完全能满足大部分实验需求。我自己用的就是这款,已经稳定运行三年多了。

如果你预算有限,可以考虑更便宜的N210,但要注意它需要额外的子板才能工作。而专业用户可能会考虑X310,它支持更高的带宽和MIMO(多天线)应用,但价格也飙升至1万美元以上。

这里有个容易踩的坑:USB3.0接口的型号(如B210)对电脑要求较高,我遇到过不少因为电脑USB控制器性能不足导致数据丢失的情况。建议使用Intel芯片组的主板,并关闭USB省电模式。

2.2 子板搭配:频率覆盖的关键

子板决定了你的系统能接收/发送哪些频段的信号。常用的有:

  • SBX子板(40MHz-4.4GHz):适合移动通信、WiFi等应用
  • LFRX/LFTX子板(DC-30MHz):适合短波、业余无线电
  • CBX子板(1.2GHz-6GHz):适合5G、卫星通信实验

我建议初学者先从SBX开始,它的频率覆盖范围最实用。有个客户曾经为了省钱买了不带子板的二手USRP,结果发现根本收不到信号,最后反而多花了冤枉钱。

3. 软件环境搭建:GNU Radio入门

3.1 安装避坑指南

GNU Radio的安装曾经是个噩梦,特别是驱动问题。现在最简单的方法是使用预装好的Live DVD镜像,或者用PyBOMBS工具一键安装。我在Ubuntu 20.04上的安装命令如下:

sudo apt-get install gnuradio sudo pip install pybombs pybombs auto-config pybombs install gnuradio

常见问题排查:

  • 如果遇到UHD驱动问题,试试uhd_find_devices命令
  • 图形界面打不开?可能是缺少QT库,安装gnuradio-dev
  • 实时调度问题会导致数据丢失,可以设置sudo sysctl -w kernel.sched_rt_runtime_us=-1

3.2 你的第一个流图:FM收音机

让我们用GNU Radio Companion(GRC)图形化工具创建一个简单的FM收音机。这个例子我给学生演示过无数次,每次都能收获"哇"的惊叹声。

  1. 打开GRC,新建一个流图
  2. 添加这些模块:
    • UHD USRP Source(设置中心频率为当地FM电台频率)
    • QT GUI Frequency Sink(用于频谱显示)
    • WBFM Receive(宽频FM解调)
    • Audio Sink(输出到声卡)
from gnuradio import gr from gnuradio import analog from gnuradio import audio from gnuradio import uhd from gnuradio import blocks class fm_receiver(gr.top_block): def __init__(self): gr.top_block.__init__(self) # 设置采样率 samp_rate = 2e6 # USRP源 self.usrp_source = uhd.usrp_source( ",".join(("", "")), uhd.stream_args( cpu_format="fc32", channels=range(1), ), ) self.usrp_source.set_samp_rate(samp_rate) self.usrp_source.set_center_freq(98.5e6, 0) # FM解调 self.wbfm_receive = analog.wfm_rcv( quad_rate=200e3, audio_decimation=10, ) # 音频输出 self.audio_sink = audio.sink(44100, '', True) # 连接模块 self.connect(self.usrp_source, self.wbfm_receive) self.connect(self.wbfm_receive, self.audio_sink) if __name__ == '__main__': tb = fm_receiver() tb.start() input('按回车键退出...') tb.stop()

这个例子中,USRP负责接收98.5MHz的FM信号,GNU Radio进行解调,最后通过电脑声卡播放出来。第一次运行时可能需要调整增益参数才能获得清晰的声音。

4. 实战项目:搭建数字信号发射链路

4.1 设计你的第一个发射器

接收信号只是SDR的一半乐趣,更刺激的是发射信号。但请注意,未经许可发射无线电信号在很多地区是违法的!我们这里只讨论在实验室环境下的合法频段实验。

让我们创建一个简单的数字信号发射器,可以发送文本信息。这个项目我曾在公司内部培训中使用过,效果很好。

关键模块:

  • File Source(读取文本文件)
  • Packet Encoder(将文本转换为二进制)
  • GMSK Mod(高斯最小频移键控调制)
  • UHD USRP Sink(发送信号)
from gnuradio import gr from gnuradio import digital from gnuradio import blocks from gnuradio import uhd class text_transmitter(gr.top_block): def __init__(self): gr.top_block.__init__(self) # 参数设置 center_freq = 433e6 # ISM频段 samp_rate = 1e6 tx_gain = 30 # 读取文本文件 self.file_source = blocks.file_source(gr.sizeof_char*1, 'message.txt', True) # 打包编码 self.packet_encoder = digital.packet_encoder( samples_per_symbol=2, bits_per_symbol=1, preamble='', access_code='', pad_for_usrp=True ) # GMSK调制 self.gmsk_mod = digital.gmsk_mod( samples_per_symbol=2, bt=0.35, verbose=False, log=False, ) # USRP发送 self.usrp_sink = uhd.usrp_sink( ",".join(("", "")), uhd.stream_args( cpu_format="fc32", channels=range(1), ), '', ) self.usrp_sink.set_samp_rate(samp_rate) self.usrp_sink.set_center_freq(center_freq, 0) self.usrp_sink.set_gain(tx_gain, 0) # 连接模块 self.connect(self.file_source, self.packet_encoder) self.connect(self.packet_encoder, self.gmsk_mod) self.connect(self.gmsk_mod, self.usrp_sink) if __name__ == '__main__': tb = text_transmitter() tb.start() input('发送中...按回车键停止') tb.stop()

4.2 调试技巧:示波器不会告诉你的秘密

在实际调试中,我总结出几个实用技巧:

  1. 增益设置:先设低增益,慢慢调高直到看到信号
  2. 时钟同步:多设备系统一定要用外部10MHz参考时钟
  3. 采样率匹配:确保所有模块的采样率设置一致
  4. 缓冲区大小:大带宽应用需要调整UHD缓冲区

有个常见的坑是采样率不匹配导致的信号失真。比如USRP设置的是1Msps,但调制模块输出的是500ksps,这时就需要加入重采样模块。我曾经花了整整两天时间才排查出这个问题。

5. 进阶应用:从理论到实践

5.1 实时频谱分析仪

将USRP和GNU Radio变成专业级的频谱分析仪是完全可行的。关键模块是FFT和瀑布图显示。这个项目特别适合用来分析无线环境中的信号分布。

from gnuradio import gr from gnuradio import uhd from gnuradio.qtgui import qtgui from PyQt5 import Qt class spectrum_analyzer(gr.top_block): def __init__(self): gr.top_block.__init__(self) # 参数设置 samp_rate = 20e6 center_freq = 2.4e9 fft_size = 1024 # USRP源 self.usrp_source = uhd.usrp_source( ",".join(("", "")), uhd.stream_args( cpu_format="fc32", channels=range(1), ), ) self.usrp_source.set_samp_rate(samp_rate) self.usrp_source.set_center_freq(center_freq, 0) # FFT和瀑布图 self.qtgui_freq_sink = qtgui.freq_sink_c( fft_size, window.WIN_BLACKMAN_hARRIS, center_freq, samp_rate, "", 1 ) # 连接模块 self.connect(self.usrp_source, self.qtgui_freq_sink) # 显示设置 self.qtgui_freq_sink.set_update_time(0.1) self.qtgui_freq_sink.set_y_axis(-140, 10) self.qtgui_freq_sink.enable_autoscale(False) if __name__ == '__main__': tb = spectrum_analyzer() tb.start() input('按回车键退出...') tb.stop()

5.2 自定义信号处理模块

当内置模块不能满足需求时,你可以用Python或C++开发自己的处理模块。我曾经为某个项目开发过一个特殊的信道编码模块,过程比想象中简单。

Python模块示例:

import numpy as np from gnuradio import gr class my_block(gr.sync_block): def __init__(self): gr.sync_block.__init__( self, name="My Custom Block", in_sig=[np.float32], out_sig=[np.float32] ) def work(self, input_items, output_items): in0 = input_items[0] out = output_items[0] # 简单的信号处理:放大2倍 out[:] = in0 * 2 return len(output_items[0])

把这个模块保存为my_block.py,然后在GRC中就能像内置模块一样使用了。

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

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

立即咨询