【GNURadio实验报告】实验2-使用GNURadio模拟简易的OOK/ASK信号
本文在写作过程中,得到了开源SDR实验室https://blog.csdn.net/OpenSourceSDR?type=blog大佬们的悉心指导,在这里向你们的无私帮助表示感谢!
博主本人非通信专业出身,本文仅为个人学习GNU Radio和HackRF过程中的知识点笔记,难免会存在错误和疏漏,恳请走过路过的大佬不吝赐教斧正。
期待能够为GNU Radio中文社区增添一份贡献!
一、OOK是什么?
(一)简介
OOK(On-Off Keying),开关键控/通断键控。属于ASK幅移键控信号的一种,也即2ASK。这种调制方式常见于无线门铃、车库门遥控器、遥控车等,最为人们所熟知的就是大名鼎鼎的摩斯电码。作为数字调制的一种,OOK的历史比之AM、FM等模拟调制方式还要早。
OOK的抗噪声性能不如其他调制方式,所以该调制方式在卫星通信、数字微波通信中并没有被采用;但又由于该调制方式的实现简单,在光纤通信系统中,振幅键控方式却获得广泛应用。
【OOK传递信息的基本原理】将需要传递信息(例如“hello world”字符串、开门指令)用二进制0、1进行编码,形成二进制调制信号(基带信号),如上图第一行所示的
V
m
(
t
)
V_{m}\left ( t \right )
Vm(t);用于搭载信息的高频载波(载波信号),如第二行所示的
A
cos
(
2
π
f
c
t
)
A\cos \left ( 2\pi f_{c}t \right )
Acos(2πfct),在二进制调制信号控制下通断,1=通,0=断,这一过程即OOK调制;经调制后的携带信息的信号被称为已调信号,如第三行所示的
V
A
M
(
t
)
V_{AM}\left ( t \right )
VAM(t),此时即可发送至空间中进行传播。
(二)信号产生
OOK信号发生器由高频正弦波信号发生器、数字化形式的消息信息和带通滤波器组成。
如上图所示,开关根据数字化形式的消息信息的bit位进行开和关。当bit位为1时,开关闭合,允许载波被传输;反之,当bit位为0时,开关断路,不允许载波传输。输出后的波形经过带通滤波器进行滤波整型。
(三)数学公式
OOK信号
s
(
t
)
s\left ( t \right )
s(t)可视为一个单极性的矩形脉冲信号
m
(
t
)
m\left(t\right)
m(t)与一个载波
cos
(
ω
c
t
+
φ
c
)
\cos \left ( \omega_{c}t+\varphi _{c} \right )
cos(ωct+φc)相乘,即
s
(
t
)
=
m
(
t
)
cos
(
ω
c
t
+
φ
c
)
=
[
∑
k
=
−
∞
∞
a
k
g
(
t
−
k
T
s
)
]
cos
(
ω
c
t
+
φ
c
)
s\left ( t \right )=m\left ( t \right )\cos \left ( \omega_{c}t+\varphi _{c} \right )\\ =\left [ \sum_{k=-\infty }^{\infty} a_{k}g \left ( t-kT_{s} \right ) \right ]\cos \left (\omega_{c}t+\varphi _{c} \right )
s(t)=m(t)cos(ωct+φc)=[k=−∞∑∞akg(t−kTs)]cos(ωct+φc)
式中,
g
(
t
)
g\left ( t \right )
g(t)是持续时间为
T
s
T_{s}
Ts的矩形脉冲,
a
k
a_{k}
ak的取值服从下述关系
a
=
{
0
,
概率为
p
1
,
概率为
1
−
p
a=\begin{cases} 0,概率为p\\ 1,概率为1-p \end{cases}
a={0,概率为p1,概率为1−p
由频率卷积定理可得
s
(
t
)
s\left ( t \right )
s(t)的频谱为
s
(
ω
)
=
1
2
[
M
(
ω
+
ω
c
)
+
M
(
ω
−
ω
c
)
]
s\left (\omega \right )=\frac{1}{2} \left [ M\left ( \omega+\omega_{c} \right ) + M\left ( \omega-\omega_{c} \right ) \right ]
s(ω)=21[M(ω+ωc)+M(ω−ωc)]
由上式可知,由于基带矩形脉冲序列的频谱宽度是无限宽的,所以OOK信号的频谱宽度也是无限宽的。因此,为了避免干扰,通常需要在调制信号进入功放前增加一级带通滤波器,保证信号的绝大部分能量通过,同时滤除带外频率分量。OOK调制系统的模型如下图所示。
二、流图设计-发送端
对照前文的OOK调制系统模型,搭建发射机的仿真程序,即绘制grc流程图。
需要发送的信息可以以两种形式存储读取:
第一种是直接手动输入,使用【Vector Source】模块,修改起来比较方便。
第二种是从文件中读取,使用【File Source】模块,适用于固定的数据信息。
(一)信号源为Vector Source
grc流程图如上图所示。包括基带信号源(Vector Source)、载波信号源(Signal Source)、插值(Repeat)、值类型转换(Char To Float)、乘法器(Mutiply)、带通滤波器(Band Pass Filter)、时域示波器(QT GUI Time Sink)和频域示波器(QT GUI Frequency Sink)。
基本逻辑是:首先将需要传输的二进制数据以向量形式(在Python中,是括号+逗号,例如01001→**(0,1,0,0,1)**)填写进Vector Source模块,再与载波(上图为10kHz的余弦波)相乘,完成调制;经带通滤波器滤波后(由于带通滤波器的参数调试起来比较麻烦,我直接将该滤波器短路),分别在【QT GUI Time Sink】、【QT Frequency Sink】示波器上,以时间-幅度、频率-幅度的形式呈现。
先说仿真结果:
如下图所示,在时幅图(QT GUI Time Sink示波器)中可以看到,低电平代表0、高电平代表1,每个码元的持续时长为5ms(=1000ms*插值数Interpolation 100/采样率samp_rate 20kHz)。
在时频图(QT GUI Frequency Sink示波器)则可以看到,信号在5kHz的位置出现了一个峰值,这是因为载波信号fc的频率为5kHz;而在0-10kHz范围内分布着能量,表明实际贷款非常宽。
下面逐一解释每个模块的用法(按照从左至右的顺序)。
【Vector Sink】
矢量源,从1个向量中提取数据并输出。https://wiki.gnuradio.org/index.php/Vector_Source
Output type:输出数据的数据类型。包括complex、int、short、float、byte
Vector:数据。以向量Vector形式存储。下图所示输入的数据是01001
Repeat:一组数据结束后是否重复该组数据。如果选择No,就只会输出1轮01001,之后全0。
Tags:数据标签。在时域图的指定位置打上标签,便于事后分析。
Vector Length:矢量长度。默认值为1,代表输出普通的数据流(不需要修改)。
关于Tags参数的用法。如果想要标识出第1个、第2个、第4个码元的位置时,首先新建3个Tag Object模块,分别命名为a、b、c(如图左所示),将offset(偏移量)分别设置为0、1、3;然后将Vector Source的Tags属性改为[a,b,c](如图中所示)。运行后,时域图上将在相应的位置显示上述预设标签(如图右所示)。
【Repeat】
插值模块。将输入进该模块的值重复Interpolation次后输出,可达到拓宽码元宽度的效果。https://wiki.gnuradio.org/index.php/Repeat
Type:输出数据的数据类型。包括complex、int、short、float、byte
Interpolation:插值数。即每个码元重复的次数。
Vector Length:矢量长度。默认值为1,代表输出普通的数据流(不需要修改)。
关于Repeat延长码元宽度。假设向量Vector数据为(0,1,2),当Interpolation设为7,如下图所示(在时域图空白处单击鼠标中键,选择stem plot显示点),幅度值为0、1、2的点将扩展为7个,延长了每个码元的时间宽度,即码元宽度。
码元宽度、插值数、采样率的换算关系可如下公式计算
码元时长
=
插值数
I
n
t
e
r
p
o
l
a
t
i
o
n
采样率
S
a
m
p
l
e
R
a
t
e
∗
1
秒
码元时长=\frac{插值数Interpolation}{采样率Sample Rate} *1秒
码元时长=采样率SampleRate插值数Interpolation∗1秒
例如,采样率Samp Rate=20kHz,可以理解为计算机每秒输出20k个点。若需要每个码元持续时长为5ms,就设置Interpolation值为
5
×
1
0
−
3
×
2
0
3
=
100
5\times 10^{-3} \times 20^{3}=100
5×10−3×203=100,即每100个点组成1个码元。
【Char To Float】
Char型转Float型模块。将输入端进来的char类型流数据变为float类型的流数据。
Vector Length:同上文。
Scale:放缩因子。可以用于改变输入输出端的幅度比值。输出=输入/Scale关于Scale参数的作用。如下图所示,若输入端幅度值为1,当Scale分别设为0.1、0.2时,输出端的幅度值分别为1/0.1=10、1/0.2=5
【Signal Source】
信号源模块。可提供恒定波形(阶跃信号)、正弦信号、余弦信号、方波信号、三波信号、锯齿波信号。https://wiki.gnuradio.org/index.php/Signal_Source
Output type:输出端的数据类型。包括complex、int、short、float
Sample Rate:采样率。(注:下图中之所以写samp_rate,是因为我在grc流程图中定义了一个Variable参数模块,命名为samp_rate,可以理解为python语言传参赋值)
Waveform:选择信号源所用波形。包括恒定波形(阶跃信号)、正弦信号、余弦信号、方波信号、三波信号、锯齿波信号。
Frequency:频率。(下图中写的fc,原因同上)
Amplitude:幅度。信号最大幅度值的绝对值。
Offset:上下偏移量。 以余弦波为例,当幅度为1,偏移为0,则最大值为1,最小值为-1。
Initial Phase:相移。
关于输出信号类型
正弦波Cosine (complex) | ![]() |
恒定波形Constant | ![]() |
方波Square | ![]() |
三角波Triangle | ![]() |
锯齿波Sawtooth | ![]() |
关于输入端的cmd接口
注意到该模块左边还有1个灰色的cmd端口(GNU Radio 3.8版本以前另有1个freq端口,现已整合进cmd中),可用于在运行时通过传入pmt消息改变信号特征。可传入消息包括:
pmt.intern(“freq”)——频率
pmt.intern(“ampl”)——幅度
pmt.intern(“phase”)——相位
pmt.intern(“offset”)——偏移量
pmt.dict_add(pmt.make_dict(), pmt.intern("ampl"), pmt.from_double(0.5))
#将输出信号的幅度值调整为0.5
【Mutiply】
乘法器模块。将两个Input端口输入的数据流内积后输出。https://wiki.gnuradio.org/index.php/Multiply
IO Type:输入输出端的数据类型。包括complex、int、short、float。
Num Inputs:输入端口的数量。
Vector Length:Vector数据长度。同上文,设为1即可。
【QT GUI Time Sink】【QT GUI Frequency Sink】
可以当做示波器来使用,分别显示时间-幅度波形图、频率-幅度波形图。
可设置的参数很多,大部分用于调节示波器的显示,默认即可。需重点关注两个参数:
【QT GUI Time Sink】Sample Rate和【QT GUI Frequency Sink】Bandwidth:应当与流程图的采样率保持前后一致。
【QT GUI Frequency Sink】Center Frequency:中心频率。如下图所示,若输入信号的频率为5kHz,本应当在示波器中的5kHz位置出现单个波峰,但如果示波器的Center Frequency设置为5kHz,则示波器将显示信号频率为5+5=10kHz。
(二)信号源为File Source
尝试将需要发送的数据存入txt文档中,由File Source模块读取出来后发送。
grc流程图基本框架不变,仅仅将Vector Source改为File Source即可。
首先,利用python将待发送数据转换为二进制,存入二进制文档。
设待发送数据为01001
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
serial =[0,1,0,0,1]#待发送数据
f=open(r'test1.txt','wb')#以二进制形式打开文档
for i in serial:
f.write(i.to_bytes(1, 'big'))
#参数 ‘1’ :转为1个字节的bytes;
#参数 'big’ :byteorder
f.close()
注意,生成的文件,必须是以二进制形式存储数据的文件,当试图使用文档编辑工具打开时将呈现乱码,无法直接编辑。直接在txt文档里输入01001是错误的。
【File Source】
文件源。读取文件作为信源。https://wiki.gnuradio.org/index.php/File_Source
File:读取的文件路径。官网提示:文件大小应至少为8字节。
Output type:输出数据类型。包括complex、int、short、float、byte。(在本流程里,需要选择byte类型,这是因为我们上一步使用python记录的数据为01001,每一个0、1都是以byte形式存储的,只有1字节)
Repeat:是否重复。效果同Vector Source(如前文所述)
Vector length:矢量长度。默认值为1,代表输出普通的数据流(不需要修改)。
Offset:偏移量。从第N+1字节开始读取文档。
Length:读取字节数。从偏移点开始读取多少个字节。当设为0时,会一直读到文件结尾。
关于Output Type参数。假设发送数据为00110001,当我将File Source改为short,程序会每2个字节读取一次,即00=0,11=1,00=0,01=10=1,最终输出0101。如下图所示,由于采样率和插值数Interpolation都没变,码元宽度也就仍然是5ms,可以看到图中码元宽度刚好符合这一设定,并且幅度变化为低-高-低-高循环,即持续发送0101。
关于Offset参数。如果将Offset由0改为1,意味着跳过第0字节,从第1字节开始读取,则原始数据00110001变成了0110001,按照short类型每两个字节读取的规则来看,就变成了110(最后1个字节可能被舍弃了),下图可以验证这一猜想。
(三)采用硬件输出时
前文所述均为仿真模拟,现在准备使用HackRF无线电设备实际发送信号。流程图如下:注:实验过程中请遵守当地无线电法规。博主是将发射机和接收机用双绞线+负载直接对接进行的实验,没有实际发射电磁波。
与信号仿真的grc流程图相比,这里并没有使用乘法器,而是直接使用osmocom Sink进行了上变频。实际发射效果如下图所示,这里使用了RTL-SDR设备+sdrsharp软件完成信号采样,采样率设为2.048MSPS,带宽32kHz,设自动增益控制,解调方式选择了CW,录制内容为音频数据;录制的wav文件使用Adobe Audition进行分析。由图可知,RTL-SDR成功在409.750MHz接收到来自HackRF发送的01001。
下面具体介绍osmocom Sink模块的使用方法。
【osmocom Sink】
硬件模块。用于发射或接收信号。该模块最开始是为osmoSDR硬件开发的,目前它支持如HackRF、Ettus USRP等硬件。
Input Type:输入数据类型。只有Complex Float32一种。(这就是为什么上图所示的grc流程图里,其他模块的输入输出端口被统一修改为蓝色的comlex类型,否则就另需要部署若干XXX To Complex模块进行数据类型转换)
Device Arguiments:设备参数。根据需要填写设备的硬件地址或其他身份标识等。例如,当流图里有两个模块(Sink+Source)分别用于发射和接收设备时,这个参数就需要填写进去;只有一个设备时默认即可。
Sync:同步。包含Unknown PPS、PC Block、Don’t Sync。建议购买并连接外部时钟,否则会存在频偏。注:在该模块之前不建议加装Trottle模块,这样出现流程图里就将会存在2个时钟,网络上有一些流程图是不对的。
Number MBoard、MB0等:可能用于设置时钟设备参数。博主暂时还没实验过,默认即可。
Number Channels:信道数量。例如一个设备可能有两个发射机,就可以写2。
Sample Rate:采样率。应当与grc流程图内其他模块保持一致。注:根据博主经验,使用HackRF时,设置的采样率应当大于等于200kHz、小于等于18MHz,否则会造成失真,具体原因将在下一篇实验报告中详细阐述。
Frequency:频率。等效于上变频操作,原始信号将以该频率为中心频率发射。
Frequency Correction:频率修正。已知设备存在频偏时,可使用这一参数进行修正。
RF Gain:射频增益。在Software Defined Radio with HackRF Lesson系列课程中,该参数被Michael Ossmann用来控制接收机的信号强度。
IF Gain:中频增益。同上,被用来控制发射信号强度,据称HackRF最高可达到47dB。
BB Gain:基带增益。
BandWidth:带宽。设0即可,博主尚未实验该参数有什么作用。
关于上变频问题。如图所示,实际发射信号的grc流程图(下)和实验模拟信号的grc流程图(上),核心区别在于没有再额外乘以一个余弦波。这是因为osmocom模块的作用本身就在于上变频。当发射信号载波频率已经提高到了409.750MHz,就无需另行使用乘法器。
如果尝试增加乘法操作,你会发现实际接收信号相对于409.750MHz出现了频偏,频偏大小等于Signal Source的Frequency频率值,例如Vector Source乘以Signal Source输出的5kHz余弦波时,实际信号的频率值将为490.755MHz。注意:关于这一说法,博主尚未进行实验复现,有待后续论证。
三、流图设计-接收端(待完善)
未完待续,等我需要的时候在做咯!嘿嘿ヾ(o・ω・)ノ