一、简介

0x110 什么是GNU Radio

GNU Radio是一个设计框架,一个开源的无线电架构平台,用户可以用来设计、模拟和部署的真实高效无线电系统。GNU Radio是一个高度模块化,采用flowgraph流图形式的软件平台,它集成了处理各种信号的库,可以很方便的将各个模块结合到一起来处理复杂的信号。

GNU Radio已经被广泛应用于无线电领域,可以用电脑软件处理包括音频处理、移动通信、卫星跟踪、雷达系统、GSM网络、数字信号广播等等。

GNU Radio 硬件平台本身并不是非常特殊的硬件,也没有包含现成的通信协议和通信标准,比如802.11、Zigbee、LTE等,但它可以用于开发并实现任何频率、任何协议的无线电通信。

0x120 为什们要用GNU Radio?

以前,无线电通信方面的开发,工程师需要设计用于检测特定信号的信号检测电路,设计专用IC用来解码或者编码特定信号,才能进行数据通信和传输,整个调试过程成本很高而且很费时间。

Software-Defined Radio 软件无线电SDR使得开发变得非常简单,只要有钱买一块SDR板子并且有能力使用它,就可以用算法在计算机的软件上处理无线电信号。

当你的电脑连接了软件无线电设备,每次都从头开始编写一个用于处理各个算法和数据的程序,你会觉得非常麻烦:为什么每次都要重新实现一个标准的过滤器?为什么要关注数据在不同处理模块之间的通信?为什么不能用高度集成的模块进行实现,非得自己写?而且怎么才能让程序能更好的兼容各种平台,比如一个功率只有几W的嵌入式设备?

GNU Radio就具备这些功能。这是一个集成度非常好的信号处理模块框架,里面封装了非常多的可以重复使用的模块,而且扩展性非常好,提供了很多标准算法的扩展库,并且在各种平台上都有很大程度的优化,它还有很多很多例子让你可以很轻松的上手。

0x130 数字信号处理

作为一个软件框架,GNU Radio可以让通用的计算机平台进行数字信号处理。

0x131 小信号理论

用软件处理信号就是信号是数字信号,但什么是数字信号?

为了更好的理解,我们看一个很常见的信号处理场景:用麦克风录制语音并传输

从物理层面上讲,声音信号的信号:由人的声带产生的空气震荡波,这也是一个时变的物理量,比如空气震荡,就可以被定义为信号

当声波到达麦克风,麦克风将空气的震动变化转成电信号,表象是一个可变的电压值:

现在声音信号就是电信号了。计算机并不能处理原始的声音信号,因为它是模拟信号,而计算机只能处理数字信号。数字信号有两个基本特征:

  • 只能是有限数量的数值

  • 只有时间是变量

数字信号通常能够用一个数字序列来表示,我们称之为样本,样本之间的固定时间间隔就是采样频率。

通常将物理量(电压)转换成数字样本的采样动作,是由模拟/数字转换器(ADC)来完成,当然也有反向的数字/模拟转换器(DAC),可以将数字信号转换成模拟信号。

当我们有了这个数字序列,就可以用电脑来做任何事,比如可以用数字滤波器,压缩、语音识别或者用数字通信链路传输它。

0x132 用数字信号处理进行无线电传输

无线电信号和声音信号是同样的原理。

一个无线电信号,也是一个电磁波,同样可以通过天线将它转换成一个变化的电压。当然,这个电信号可能是在几M甚至几千M的载波上。

无线电信号可以利用不同类型的接收机来接收,例如超外差接收机、直通机或者中低频接收机等,也能用获得软件无线电支持的商业设备(比如连接到声卡的专业无线电接收机),也能用低成本消费者考虑的数字电视接收机(比如著名的RTL-SDR)

0x140 用模块化的流图进行数字信号处理

为了处理数字信号,可以将整个流程的各个处理阶段(滤波、调制解调、分析、检测等等)作为模块来使用,然后用简单的指示箭头表示流程方向:

当一个信号处理应用被创建时,一个完整的模块化流程图就建立起来了,这样的图在GNU Radio中称为flowgraph流图。

GNU Radio就是利用这些信号处理模块,创建flowgraph,用来处理无线电信号的应用程序框架。

作为GNU Radio用户,可以将现有的模块嵌入一个高层次的flowgraph流图用来处理更加复杂的数字信号,当所有模块和连线构建完毕,点击运行就能自动处理信号。

GNU Radio带有非常非常多的模块,这里就列出几个常见的类别和他们的成员:

Waveform Generators
  • Constant Source

  • Noise Source

  • Signal Source

Modulators
  • AM Demod

  • Continuous Phase Modulation

  • PSK Mod / Demod

  • DPSK Mod / Demod

  • GMSK Mod / Demod

  • QAM Mod / Demod

  • WBFM Receive

  • NBFM Receive

Instrumentation
  • Constellation Sink

  • Frequency Sink

  • Histogram Sink

  • Number Sink

  • Time Raster Sink

  • Time Sink

  • Waterfall Sink

Math Operators
  • Abs

  • Add

  • Complex Conjugate

  • Divide

  • Integrate

  • Log10

  • Multiply

  • RMS

  • Subtract

Channel Models
  • Channel Model

  • Fading Model

  • Dynamic Channel Model

  • Frequency Selective Fading Model

Filters
  • Band Pass / Reject Filter

  • Low / High Pass Filter

  • IIR Filter

  • Generic Filterbank

  • Hilbert

  • Decimating FIR Filter

  • Root Raised Cosine Filter

  • FFT Filter

Fourier Analysis
  • FFT

  • Log Power FFT

  • Goertzel collapse(Resamplers)

  • Fractional Resampler

  • Polyphase Arbitrary Resampler

  • Rational Resampler collapse(Synchronizers)

  • Clock Recovery MM

  • Correlate and Sync

  • Costas Loop

  • FLL Band-Edge

  • PLL Freq Det

  • PN Correlator

  • Polyphase Clock Sync

通过这些模块,很多标准处理流程,比如正交信号、同步、测量和可视化,都可以通过合适的模块连入流图来完成。

此外,你还可以自己编写模块,比如一些与逻辑处理相结合或者新的自动化处理流程,或者用自己编写的模块进行数据输入或者输出操作也可以。

所以,GNU Radio是主要用于信号处理的开发框架,它配备了很多标准模块库,供给开发人员建立各种通信或者信号处理系统。其实,GNU Radio本身并不是一个软件,你不能直接用它产生结果,它只是用来做准备工作,之后用户再用它来做自己想要做的事情,尽管它本身包含了很多案例,但可以只把它看成一堆模块就行了。

二、安装

安装方法有很多种,GNU Radio也支持Win、Linux和Mac,但这里只介绍最稳定的Linux下的安装。

0x210 二进制包安装

如果图省事,可以用发行版的源中带的gnuradio包,但GNU Radio更新很快,发行版提供的软件包很可能是过时的老版本(至少大版本一定要最新,也就是版本号的前两位),不然遇到了问题时候在官方的邮件列表支持中很少会有人回答。

ubuntu/debian/kali:

1
apt-get install gnuradio

fedora:

1
yum install gnuradio

对于其他的发行版,使用相应的包管理工具安装就行。

如果要更新的版本或者在特殊平台的安装,可以看看GNU Radio官方源

0x220 pybombs安装(推荐)

pybombs是封装好的自动化程序,会自动下载源码包然后编译安装,过程中会自己下载依赖包,比自己下载源码编译安装省事很多。官网https://github.com/gnuradio/pybombs

因为某些原因,安装GNU Radio时候最好翻墙,拨VPN或者用SS代理都行

安装pip和pybombs

1
2
3
4
5
apt-get install python-pip

pip install --upgrade pip

pip install git+https://github.com/gnuradio/pybombs.git

获取安装库

1
2
3
pybombs recipes add gr-recipes git+https://github.com/gnuradio/gr-recipes.git

pybombs recipes add gr-etcetera git+https://github.com/gnuradio/gr-etcetera.git

安装到/usr/local目录,安装目录下会有.pybombs目录,配置文件保存在用户目录的.pybombs文件夹

1
pybombs prefix init /usr/local -a myprefix -R gnuradio-default

默认会安装很多组件,如果安装到中途断了,再用上面的命令无法执行怎么办?

可以删掉/usr/local下的.pybombs,然后整个重新安装,提示配置文件直接覆盖就行,如果只是个别组件导致的中断,可以先用pybombs卸载该组件,再重新安装,比如安装rtl-sdr出错:

1
2
pybombs remove rtl-sdr
pybombs install rtl-sdr

安装完成后检查组件,再加上一些没有自动安装的组件:

1
pybombs install osmo-sdr rtl-sdr gnuradio dump1090 hackrf bladeRF airspy gr-iqbal libosmo-dsp gr-osmosdr gqrx
GNSS-SDR在Ubuntu 16.04直接安装可能会出错,因为安装gloggflags时候可能会因autoconf版本较高而导致编译错误,所以用pybombs将几个依赖包先装上再安装gnss-sdr即可:
1
2
pybombs install armadillo gflags glog gnutls
pybombs install gnss-sdr

安装完成后,执行环境变量脚本,然后执行gnuradio-companion就能打开界面,gnuradio-config-info可以查看版本修改配置:

1
2
3
4
cd /usr/local
./setup_env.sh
gnuradio-config-info -v
gnuradio-companion

三、GRC的使用

0x310 准备工作

在开始之前,先说说后面2-7小节,每个图片、grc文件和模块文件,都已经放到了github,可以下载下来作为参考,用两个目录分区分自己的目录和参考目录:

1
2
3
/root/tutorials/solutions

/root/tutorials/work

0x311 下载示例

用git下载示例

1
git clone https://github.com/gnuradio/gr-tutorial

之后如果找不到相应案例的教程,就去github上找

0x312 编译安装

下载后进入目录编译安装即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
cd gr-tutorial

mkdir build

cd build

cmake ..

make -j8

make install

ldconfig

如果要卸载,也很简单:

1
2
3
4
5
cd gr-tutorial

make uninstall

ldconfig

0x320 了解GRC

在第一章我们了解到GNU Radio可以用来开发无线电系统中的软件,而不是完全运行在硬件上。在这里我们介绍如何使用GNU Radio的图形化工具GNU Radio Companion(GRC)来创建不同的信号,我们可以使用GRC可以图形化创建Python文件,而不是在代码字符中编写,GRC是为了简化GNU Radio的使用而存在的。

首先我们先了解下GRC界面,它由模块库工具栏终端工作区四部分组成:

0x321 搜索模块

模块库里面的模块太多了,找一个模块一个个看太慢,点击工具栏的放大镜图标或者Ctrl+F快捷键,就能在模块库里面搜索自己需要的模块:

找到了自己想用的模块,比如QT GUI Time Sink单击模块名然后拖到工作区或者直接双击模块名也能将模块添加到工作区。

0x322 修改模块属性

双击工作区的模块或者在工作区的模块上右键-属性,进入到模块属性界面,比如工作区的Option模块:

对于不同的任务可以修改不同的属性,当我们修改参数后,前面的名称就会变成蓝色,表示内容已经修改,但还没有保存,Canvas Size表示的是工作区大小,比如改成300,300,然后OK就可以看到工作区变得特别小,用Ctrl+ZCtrl+Y可以撤销或者重做,或者点击工具栏按钮也可以。

我们打开Option模块属性中的说明,上面有说到,定义的ID就是模块保存python文件的名称。

如果我们删除ID内容,再Apply应用,可以看到下面的错误提示信息,整个模块的标题变成红色,然后ID也变成红色,提示我们哪里有错:

这里我们改成tutorial_two_1,确保Generate Options设置为QT GUIOK保存:

设置完成后,点击工具栏)或者Ctrl+S快捷键保存,将GRC流图保存为t1.grc,然后点击工具栏的或者F5生成Python文件,调用*Generate* flowgraph,在终端可以看到输出:

GRC只是一个图形化编辑器,通常情况下GNU Radio可以使用Python进行编程,但使用GRC图形化编辑更加简洁直观,F5会在GRC保存的目录生成以ID为名的py文件,之后点击工具栏的或者F6运行,其实就是执行之前生成Python文件,调用*Execute* flowgraph,可以看到终端输出:

在桌面会出现这个程序生成的QT窗口:

直接关闭窗口,或者点击工具栏按钮或者F7快捷键可以关闭窗口。

关闭GRC编辑器后,直接执行生成的tutorial_two_1.py也能打开这个QT窗口。

1
python /root/tutorials/work/tutorial_two_1.py

所以GRC的本质只是一个Python的IDE。事实上,在模块属性或者模块的变量输入框都是Python生成的,也就是说,我们可以直接将Python调用作为输入,比如说调用一个numpy或者其他的GNU Radio函数作为输入。一个很常见的应用就是调用filter.firdes滤波器设计工具来构建我们自己的滤波器。

还有就是,在设置窗口中,不同颜色的数据输入区域对应不同类型数据,在Help->Type可以看到对应:

0x323 第一个Flowgraph

为了更容易理解,我们构建一个Flowgraph流图,首先按照下图将各个模块添加到工作区,然后按照图示修改模块属性,再点击工具栏或者直接点击模块上突出的小方块进行连接。

这里先说下Throttle模块,具体作用是啥以后再说,现在你只需知道这个模块可以确保这个Flowgraph不会将你的CPU跑到100%,防止你的电脑跑死。

工具栏上的图标功能依次如下:

新建 打开 保存 关闭 连线 打印 剪切 复制 粘贴 删除 撤销 重做 查错 生成 执行 关闭 逆时针旋转90° 顺时针旋转90° 启用模块 禁用模块 跳过模块 隐藏禁用模块 查找 重载 打开源码

0x324 查错

如果有错,点击Generate按钮会在终端输出log,包括错误和警告。出现错误时候,工具栏查错按钮会显示出来,同时生成和执行按钮都变灰无法使用,点击查错按钮能够看到错误信息,比如我们在Option选项中设置为WX GUI,但我们的工作区放了一个QT GUI的模块,就可以看到模块标题变红,然后查错按钮显现,点击出现错误信息:

0x325 执行

执行程序,可以看到两个正弦波输出,上面的ReIm可以切换实数虚数的输出显示。鼠标左键在图形上圈选可以放大,鼠标右键缩小。

这是一个复杂的ejwt傅立叶变换正弦波,这里就不讨论复杂的信号了,只讲简单的操作。

在模块的选项可以看到数据类型,如果将Complex Float 32数据类型改为Float,可以看到输入输出的颜色接口变成了橙色,

如果变更了超过两个模块的数据格式,却没有做到数据格式统一,就会报错,可以看到错误信息提示的出错地方:

全部修改完毕后,命名为tutorial_two_2,生成后执行,可以看到就只有一个实数正弦波了:

0x330 使用Companion

现在已经能够创建flowgraphs流图了,那么可以开始使用flowgraphs研究GNU Radio中其他有用的功能了。

0x331 时间 & 频率 Flowgraph

创建一个Flowgraph流图:

  • OptionsIDtutorial_two_3

  • QT GUI Tab WidgetIDtabNum Tabs2Label 0TimeLabel 1Frequency

  • QT GUI RangeIDsamp_rateDefault Value5*freqStart0.5*freqStop20*freqStep200

  • VariableIDfreqValue2e3

  • Signal SourceSample Ratesamp_rateFrequencyfreqWaveformSine

  • ThrottleSample Rate32e3 (为什么要这么多后面会讲)

  • QT GUI Time SinkGUI Hinttab@0QT GUI Frequency SinkGUI Hinttab@1

这个流图会绘制正弦波,并且有时间和频率滑块,使我们在保持频率不变的情况下能够动态调整采样率。

0x3311 采样率

我们勾选4ms的波形,可以看到在10k采样率下的正弦波行非常糟糕,我们可以通过移动滑块或者直接改输入框修改采样频率,不需要修改流图重新生成,比如调到最大40k,然后再用鼠标选4ms波形:

0x3312 Nyquist Frequency 奈奎斯特速率

10k采样率,我们可以得到初始频率2 KHz,提高采样率,我们仍然会在2 KHz得到高峰,奈奎斯特采样定理告诉我们,如果采样率低于2*original_signal_freq,波形将会失真,我们将无法再现信号波形,虽然教科书上这么说,但我们不相信,让我们将采样率下调到3.85 KHz,看看时间波形是什么?

看起来不像一个正弦波,而且我们的眼睛会被欺骗,让我们转向FFT得到其他频率。

我们看到的频率不再是2 KHz,也不像我们输入的信号,而且,也高于奈奎斯特率0.15 KHz,这是因为信号具有折叠性,所以0.15 KHz低于实际频率。这就是利用GNU Radio 模拟DSP进行的一次信号完整性检查。

更详细的解释请看采样率FFT快速傅氏变换

0x3313 关于Resampling重采样

现在我们已经知道了奈奎斯特,也知道了问题是怎么出现的,如果我们不考虑速率的话,可以了解下Resampling重采样。重采样用于改变信号的采样率,用于满足另一个系统的要去,比如声卡的采样率。重采样有两个重要方面:插值抽取插值增加采样点,抽取删除采样点。这里我们用一个例子来理解它们:

  • OptionsIDtutorial_two_4

  • VariableIDsamp_rateValue48e3

  • Signal SourceFrequency1e3WaveformCosine

  • Rational Resampler,都改成Float-->Float,一个Interpolation4,一个Decimation4

  • ThrottleSample Ratesamp_rate

  • QT GUI Time SinkGUI Hint清空,Number of Inputs3Config栏目打开,Line 1 LabelNormalLine 2 LabelInterpolatedLine 3 LabelDecimated

默认情况下,Line 1蓝色Line 2红色Line 3绿色,颜色和线宽都可以在Config中调整,让我们看看输出的波形是咋样的?

我们可以看到,通过重采样/抽取/插值的方法,可以改变原始信号的采样速率。所以,我们在一个非标准采样率的信号上进行标准采样率的信号采集,可以得到比原始信号更高或者更低的频率。

当我们设计硬件接口或者调制解调器的时候如果想要提高工作效率,这一点非常重要。

#####注意:尽管这个程序能运行并得出结果,但可能会意外停止或者假死,因为QT Sink不允许同时绘制不同采样率信号波形图,所以最好是每一个采样率的信号都用一个单独的QT Sink。这里只是一个简单样例用于对比。

0x340 如何使用INSERT_BLOCK_NAME_HERE

如果要显示多个图形有很多种方法,比如说我们有一个大屏幕,我们可以用GUI Hint中的Grid Position网格表示法来划分,或者给每个输入创建一个不同的sinks

0x341 Grid Position

GRC提供了好几种图形sink和图形空间来创建wx-gui流图(scope sink, fft sink, number sink, waterfall sink, constellation sink, slider control, and chooser control) ,每个图形元素都有精确定位的网格位置参数。

网格位置参数形式是4个整数(行,列,行宽,列宽)。行和列指定图形元素左上角的位置,最小位置0,0,指定网格的左上角。

如果参数留空,这个网格参数指定的图形元素会按照从上到下竖直排列,大小为前面图形最大大小,如果不想让你的图形竖着排列,请不要将参数留空。

行宽和列宽指定拉伸程度,或者说图形所占据的行宽和列宽,行宽从行号开始向下占据的总行数,列宽从列号开始向右占据的总列数,因此,行宽和列宽最少是1,1,占据一个网格单元。每一

比如说,用户希望放置一个位2行2列的滑块,占据2行4列,再放一个文本框在5行0列,占据4行2列:

WX GUI中新的图形的行号和列号必须大于前一个图形行+行宽列+列宽,不然会报错。QT GUI中的GUI Hit属性类似,但QT GUI可以被覆盖,也就是说,行号和列号设置不当不会报错,只会让结果图形出现覆盖现象。

QT GUI Time SinkGUI Hit分别为:0,0,2,2 1,1,3,2 0,1,1,2,运行效果如下:

有很多种方法用于改变参数变量比如Chooser,也有不同的信号显示方法比如Waterfall Sink,现在我们从最基础的开始学习,我们可以选择任何模块,然后看它的文档,再找出使用的方法。

0x342 检查Probe Signal Block

当我们在mail list被问到怎么用Probe Signal Block时候,可以先添加一个Porbe Signal模块,将ID设置为probe_signal,然后将数据格式设置为Float,请看下面的属性和文档:

通过文档可以知道,这个模块的函数是level(),需要和Function Probe模块一起使用:

首先,我们同样要给它一个ID,叫probe_var,再看看文档,要求Block ID必须是流图中另一个模块的ID,所以我们将Block ID设置为Probe Signal模块的ID也就是probe_signal。文档还是告诉我们,Function Name必须是那个模块的类``class method,而且这个函数需要传递参数,如果没有参数,就将函数参数位置留空,前面看到Probe Signal模块的函数是level(),没有参数,所以这里就将Function Name设置为level即可。

0x343 显示文本信息

如果加上Signal SourceThrottle,然后执行上面的流图会发现什么输出都没有,弹出的窗口里面是空的。所以,我们还需要一种方法来显示数据。我们不能再加一个Sink,因为Probe Signal这个模块本身就是一个Sink,这时候我们就需要搜下QT找找能用的显示模块:

可以看到有一堆Sink,但在这里选择要用的就行。可以看到QT GUI有8个模块可以选用,前后那6个看着像数据输入用的,这里也需要(可以自己都试试),所以这里使用QT GUI EntryQT GUI Label来显示数据,我们将Default Value改成Function Probe模块的ID,也就是probe_var,数据格式改为Float,输出结果如下:

0x344 Throttle模块

这里我们讲一下,为什么所有的流图都要用Throttle模块,先看下用与没用Throttle模块的正弦波流图上的系统资源监控对比:

CPU i7-4790,分给虚拟机双核四线程

很明显可以看到,没有连接硬件的情况下,CPU基本跑满了,在整个流图中,只需要有一个Throttle模块就行,哪怕有很多个sources/sinksThrottle模块的作用可以理解为限速:速度越高我们流图运行的速度越高,速度越低流图运行的速度越低。我们如果将Throttle模块的采样率调到1e10比调到1e8(CPU配置低就调的更低一些防止跑死)的CPU负载要高很多。

再就是Throttle模块会强加给硬件一个吞吐率的限制,所以在使用硬件的时候,不要使用Throttle模块。

1
2
3
4
5
6
7
if hardware:

     do_not_use_throttle

else:

     use_one_throttle

0x345 采样率不匹配

之前说过很多硬件需要正确的采样率才能正常运行,这里讲讲采样率不匹配的例子。我们建立如下流图:

  • Chooser,配置3个不同采样率的采样,分别为4800024000160000,数据类型Float

  • VariableIDaudio_rateValue48000

  • Signal SourceSampling Rate都为samp_rate

  • 所有的sinks (audio, time, frequency)Sampling Rate都为audio_rate

我们可以看到没有Throttle模块,并且注意到,虽然将audio音频采样率设置为变量,但在流图运行时是无法改变的,这是因为这个xml文件没有合适的回调来支持这个功能(具体在下一章会讲)

当我们将采样率设置为48000时候,可以听到熟悉的电话拨号音,也能看到FFT频率在350Hz到440Hz之间。

如果采样率不管是高于或者低于音频采样率,使声卡收到的信号频率较高或者较低,都无法听到拨号音。

所以,请确保采样率总保持一致,否则会导致我们的数据中存在频率的升降。关于采样率更多的介绍可以看附录。

0x346 唱歌的正弦波

之前学习了这么多,现在我们可以结合probesoundcard以及QT Instrumentation Sinks制作一个会唱歌的正弦波,流图如下:

  • VariableIDsamp_rateValue48000

  • Porbe SignalIDprobe_signal

  • Signal SourceSampling Rate都为samp_rate,一个WaveformTriangle,频率为100e-6,另一个频率为20e3*probe_varAmplitude500e-3

  • QT GUI Tab WidgetID改为tab,另外两个QT GUI SinkGUI Hint分别为tab@0tab@1

其他如图设置即可,在这里,我们能够通过观察这个流图来创建它(仅仅只是一个测试)。不要忘了修改Audio Sink的采样率,因为声卡只能输出特定的频率。当设置好全部,打开音箱,运行,看看有什么效果?瀑布图是咋样的?

0x350 小结

在学习python之前,先要学习GRC,这一章讲的就是GRC的用法。

文章参考

http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorials