【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】


Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收

 

一、实现目标

1、将我们要发送的文件封装成帧;

2、通过FSK调制与解调实现文件的传输;

3、将接受到的文件进行非实时的采样处理还原我们发送的文本文件;

二、实现过程

1、将我们要发送的文本文件封装成帧

(1)首先我们要选择文本文件,例如send.txt我们在文件中输入我们要发送的字符串,在本次实验中我输入的是“Hello World!Xiaoming”,输入完后保存文件并退出。

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第1张图片

(2)     利用自己编写的Python程序data_send.py将我们的要发送的文本文件send.txt封装成简单的数据帧

data_send.py的截图

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第2张图片

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第3张图片

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第4张图片

①首先在帧头写入同步序列

代码部分:

serial =[1,0,1,1,0,1,0,0]

serial=serial*2

for i inserial:

    f.write(chr(i))

通过代码可以看出,将[1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0]作为我们的同步序列(为了后面的帧同步),将同步序列以字节的形式写入code.txt文件中

②接着写入数据的大小长度(以字节为单位)

代码部分:

str1 =intTo2Str(length,8)

for i in range(8):

       temp = str1[i]

       temp = int(temp)

       f.write(chr(temp))

计算我们要发送文本文件的大小,此处我用一个字节表示文本的字节数,即在本次试验中我们最多能够发送256字节(稍稍改变代码,可实现更多字节的传输),本次实验的为20字节,并以追加的方式写入code.txt文件中。

③写入数据

源代码:

 for i in range(length):

       str1 = intTo2Str(ord(send[i]),8)

       for i in range(8):

              temp = str1[i]

              temp = int(temp)

              f.write(chr(temp))

通过循环,我们将要发送的字符串,依次转换为字节,并追加写入code.txt文件中。

④写入结束标志

源代码:

serial =[1,1,1,1,1,1,1,1]

for i inserial:

    f.write(chr(i))

f.close()

我们通过数据长度就可以确定数据的长度,所以结束标志并不是为了判断数据段的结束。我们知道我们的帧会被循环的发送出去,而我们的结束标志则是为了避免产生相同的同步序列。

⑤运行data_read.py,我们打开code.txt,因为我们发现会出现乱码,就说明我们基本正确。我们写入code.txt是0或1的字节,用数字的方式写入文件。

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第5张图片

2、将我们要发送的文本通过hackrf发送出去

(1)发送端的grc流程图

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第6张图片

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第7张图片

 

流程图介绍:

①通过File source模块读取我们的code.txt中以保存的数据,因为我们的0,1是以字节的方式存入,所以File source模块数据类型参数选择Byte,还有记住选择code.txt的文件路径。我们可以从Vector wave看出读取出来的是0,1序列。

②Char to Float模块将字节数据类型转变为Float,方便后面的数据操作,例如乘除。

③接着我们把0,1变为-0.5和0.5,接着在乘以2,即-1,1,接着在每个数字后年插入0,达到的效果是从[0,1,,,]序列变为[-1,0,1,0,,,,,]等。然后通过Repeat进行插值,即从[-1,0,,,]变为[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,,,,,],通过这一系列的变化,达到的效果就是把读取出来的[0,1]序列用双极性方波,即从vector wave 变为Bipolar wav。(选择双极性方波的原因是方便的抽样判决)。

④通过,通过FractionalInterpolator 模块,稍稍改变原有的波形的形状,使原来的波形更容易加载到载波上。

⑤将稍稍变化后的方波通过WBFM Transmit模块完成调制。当我们的将调制后的波形放大看,发现调制后的波形,不怎么的好,于是我们就可以利用Rational Resampler模块进行插入重采样,可以使原来的波形变得更好(更光滑)。(详细的效果参考实验1的效果图)。

⑥然后通过HackRf发送出去,这里的我们用的100M,如果效果不好,可以自己设置。

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第8张图片

 

发送端效果图

(2)接收端的grc流程图

 【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第9张图片

流程图介绍:

①通过osmocom Sink模块接收我们发送的的信息,其Freqency参数同发送端一样,同为100M,还有我们还以根据需要设置RF Gain,IF Gain,BBGain的值,来调节我们接收到波形的幅度的大小,本次实现依次设置的是12,10,10。

②首先还是通过波形进行RationalResampler模块进行抽取重采样,主要是与发送的端的Rational Resampler模块想对应,是发送信息和接受的信息的速率一样。

③接着我们通过一个低通滤波器模块Low PassFilter滤除高频部分,是波形变得平坦,有利于后面的抽样判决。

④接着我们就通过Float To Int 模块实现将数据进行量化,大于0.5取1,介于-0.5到0.5之间取0,小于-0.5取-1。(注意此处我们接收到的信号幅度在-1~1左右)

⑤ 接着我们将数据保存到文件中去,这里自己设置文件的保存路径,此次试验我们保存的文件的文件名是receive.txt。

 【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第10张图片

接收端效果图

(3)     将保存的文件转化为我们能操作的数据类型

使用的命令是:

gr_plot_int2  -B20000  /home/…./receive.txt

此处gr_plot_int2是一个编写python文件,由于代码太多,这里不再节后,详细的代码看后面的附录。

 化后我们保存到kk.txt这个文件中,打开文件我们可以看出,全是1,0,-1组成的序列。

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第11张图片

(4)     从kk.txt文件中解码出我们发送的文件信息。

源代码如下:

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第12张图片

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第13张图片

【Gnuradio结合hackrf 通过FSK调制实现文本文件的发送与接收】_第14张图片

①首先读取出文件,稍作处理,将数据加载到数组中去。

代码部分:

str_arry =[]

data_arry =[]

line =f.readline()

sign = line

line =line.split(', ')

printstr(line)

for str1 inline:

       str_arry.append(str1)

while   sign!='': 

       line = f.readline()

       sign = line 

       line = line.split(', ')

       for str1 in line:

              str_arry.append(str1)

f.close()

str_arry =str_arry[1:-2]

data_arry =str_arry

n =len(str_arry)

for i inrange(n):

       if data_arry[i] == '1':

              data_arry[i] = 1

       if data_arry[i] == '0':

              data_arry[i] = 0

       if data_arry[i] == '-1':

              data_arry[i] = -1

       过代码可以看出,我们是将0,1,-1一个字符串数组,变为数字形式的数字数组,这样可供我们后面进一步的分析处理。

②接着就是抽样判决

代码部分:

data = []

data.append(data_arry[0])

for i in range(1,n):

       ifdata_arry[i] != data[-1]:

                     data.append(data_arry[i])

data = data[20:-1]

此处我们通过判断数据跳变来确定采样时刻,这就是就是利用双极性方波特点,在每个周期内电平会跳变。

③确定同步序列

代码部分:

serialnumber= [1,0,-1,0,1,0,1,0,-1,0,1,0,-1,0,-1,0]

serialnumber= serialnumber*2

m =len(serialnumber)

index = 0

for i inrange(n-m):

       sign = 0

       for j in range(m):

              if data[i+j] != serialnumber[j]:

                     sign = 1

       if sign == 0:

              index = i+32

              break

print'i='+str(index)

data =data[index:-1]

print'ss'+str(len(data))

new_data =[]

for i inrange(len(data)):

       if i%2==0:

              new_data.append(data[i])

for i inrange(len(new_data)):

       if new_data[i] == -1:

              new_data[i] = 0

通过同发送端的同步序列对比,找到接收文件中的同步序列,即确定帧的开始地方。

④获取数据包的长度

代码部分:

sizeofdata = ''

for i in range(8):

   sizeofdata = sizeofdata+str(new_data[i])

sizeofdata =int(sizeofdata,2)

print str(sizeofdata)

new_data =new_data[8:-1]

上面确定好同步序列,知道帧的起始接着8位数据就是我们发送的字符串的长度,从而确定后面数据包的长度。

获取数据包并还原为字符串

代码部分:

rec_string = ''

for i in range(sizeofdata):

       index= i*8

       temp=''

       fori in range(8):

              temp= temp+str(new_data[index+i])

       rec_string= rec_string+chr(int(temp,2))

print 'receive:'+rec_string

f = open(r'/home/cyp/myfile/decode.txt','wb')

f.write(rec_string)

上面确定数据包的长度长度,我们直接读取指定长度的数据部分,并还原为字符串形式,保存到decode.txt文件中。

⑥使用命令

  在终端中运行:./data_read.py

将解码获取的字符串信息保存到decode.txt文件中。通过对比发现同发送的文件字符串一样,证明我们正确的实现文本文件的传输。

总结

 通过这次实本文件的发送与接收,我们对hackrf和gnuradio有了一个更深的理解,同时让我们切实体会到帧结构,同步序列,调制与解调的原理,让我们学到的理论知识在实践中得以验证。

展望:通过对代码进一步的修改,帧结构的进一步完善,就可以实现图片,甚至视频的传送。

附录:

gr_plot_int2文件的源代码如下:

#!/usr/bin/envpython

#

#Copyright 2007,2008,2011 Free Software Foundation, Inc.

#

#This file is part of GNU Radio

#

#GNU Radio is free software; you can redistribute it and/or modify

#it under the terms of the GNU General Public License as published by

#the Free Software Foundation; either version 3, or (at your option)

#any later version.

#

#GNU Radio is distributed in the hope that it will be useful,

#but WITHOUT ANY WARRANTY; without even the implied warranty of

#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

#GNU General Public License for more details.

#

#You should have received a copy of the GNU General Public License

#along with GNU Radio; see the file COPYING. If not, write to

#the Free Software Foundation, Inc., 51 Franklin Street,

#Boston, MA 02110-1301, USA.

#

"""

Utilityto help plotting data from files.

"""

 

try:

    import scipy

exceptImportError:

    print "Please install SciPy to runthis script (http://www.scipy.org/)"

    raise SystemExit, 1

 

try:

    from pylab import *

exceptImportError:

    print "Please install Matplotlib torun this script (http://matplotlib.sourceforge.net/)"

    raise SystemExit, 1

 

fromoptparse import OptionParser

 

classplot_data:

    def __init__(self, datatype, filenames,options):

        self.hfile = list()

        self.legend_text = list()

        for f in filenames:

            self.hfile.append(open(f,"r"))

            self.legend_text.append(f)

 

        self.block_length = options.block

        self.start = options.start

        self.sample_rate = options.sample_rate

 

        self.datatype = datatype

        self.sizeof_data =datatype().nbytes    # number of bytesper sample in file

 

        self.axis_font_size = 16

        self.label_font_size = 18

        self.title_font_size = 20

        self.text_size = 22

 

        # Setup PLOT

        self.fig = figure(1, figsize=(16, 9),facecolor='w')

        rcParams['xtick.labelsize'] =self.axis_font_size

        rcParams['ytick.labelsize'] =self.axis_font_size

 

        self.text_file_pos = figtext(0.10,0.88, "File Position: ", weight="heavy",size=self.text_size)

        self.text_block    = figtext(0.40, 0.88, ("Block Size:%d" % self.block_length),

                                    weight="heavy", size=self.text_size)

        self.text_sr       = figtext(0.60, 0.88, ("SampleRate: %.2f" % self.sample_rate),

                                    weight="heavy", size=self.text_size)

        self.make_plots()

 

        self.button_left_axes =self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)

        self.button_left =Button(self.button_left_axes, "<")

        self.button_left_callback =self.button_left.on_clicked(self.button_left_click)

 

        self.button_right_axes =self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)

        self.button_right =Button(self.button_right_axes, ">")

        self.button_right_callback =self.button_right.on_clicked(self.button_right_click)

 

        self.xlim = self.sp_f.get_xlim()

       print 'start!'

        self.manager = get_current_fig_manager()

        connect('key_press_event', self.click)

        show()

 

    def get_data(self, hfile):

        self.text_file_pos.set_text("FilePosition: %d" % (hfile.tell()//self.sizeof_data))

        try:

            f = scipy.fromfile(hfile,dtype=self.datatype, count=self.block_length)

        except MemoryError:

            print "End of File"

        else:

            self.f = scipy.array(f)

            self.time =scipy.array([i*(1/self.sample_rate) for i in range(len(self.f))])

          fhh2 = open(r'/home/cyp/myfile/kk.txt', 'w')

            print str(len(self.f))

          data = []

          for j in range(len(self.f)):

              data.append((self.f[j]))

          fhh2.write(str(data))

            fhh2.close()

 

    def make_plots(self):

        self.sp_f = self.fig.add_subplot(2,1,1,position=[0.075, 0.2, 0.875, 0.6])

       self.sp_f.set_title(("Amplitude"),fontsize=self.title_font_size, fontweight="bold")

        self.sp_f.set_xlabel("Time(s)", fontsize=self.label_font_size, fontweight="bold")

        self.sp_f.set_ylabel("Amplitude(V)", fontsize=self.label_font_size, fontweight="bold")

        self.plot_f = list()

 

        maxval = -1e12

        minval = 1e12

 

        for hf in self.hfile:

            # if specified on the command-line,set file pointer

           hf.seek(self.sizeof_data*self.start, 1)

 

            self.get_data(hf)

 

            # Subplot for real and imaginaryparts of signal

            self.plot_f += plot(self.time, self.f,'o-')

            maxval = max(maxval, self.f.max())

            minval = min(minval, self.f.min())

 

        self.sp_f.set_ylim([1.5*minval,1.5*maxval])

 

        self.leg =self.sp_f.legend(self.plot_f, self.legend_text)

 

        draw()

 

    def update_plots(self):

        maxval = -1e12

        minval = 1e12

        for hf,p inzip(self.hfile,self.plot_f):

            self.get_data(hf)

            p.set_data([self.time, self.f])

            maxval = max(maxval, self.f.max())

            minval = min(minval, self.f.min())

 

        self.sp_f.set_ylim([1.5*minval,1.5*maxval])

 

        draw()

 

    def click(self, event):

        forward_valid_keys = [" ","down", "right"]

        backward_valid_keys = ["up","left"]

 

        if(find(event.key,forward_valid_keys)):

            self.step_forward()

 

        elif(find(event.key,backward_valid_keys)):

            self.step_backward()

 

    def button_left_click(self, event):

        self.step_backward()

 

    def button_right_click(self, event):

        self.step_forward()

 

    def step_forward(self):

        self.update_plots()

 

    def step_backward(self):

        for hf in self.hfile:

            # Step back in file position

            if(hf.tell() >=2*self.sizeof_data*self.block_length ):

               hf.seek(-2*self.sizeof_data*self.block_length, 1)

            else:

                hf.seek(-hf.tell(),1)

        self.update_plots()

 

 

deffind(item_in, list_search):

    try:

       return list_search.index(item_in) != None

    except ValueError:

       return False

 

try:

    import scipy

exceptImportError:

    print "Please install SciPy to runthis script (http://www.scipy.org/)"

    raise SystemExit, 1

 

fromoptparse import OptionParser

defmain():

    usage="%prog: [options] input_filenames"

    description = "Takes a GNU Radiointeger binary file and displays the samples versus time. You can set the blocksize to specify how many points to read in at a time and the start position inthe file. By default, the system assumes a sample rate of 1, so in time, eachsample is plotted versus the sample number. To set a true time axis, set thesample rate (-R or --sample-rate) to the sample rate used when capturing thesamples."

 

    parser =OptionParser(conflict_handler="resolve", usage=usage,description=description)

    parser.add_option("-B","--block", type="int", default=1000,

                      help="Specify theblock size [default=%default]")

    parser.add_option("-s","--start", type="int", default=0,

                      help="Specify where to start in the file[default=%default]")

    parser.add_option("-R","--sample-rate", type="float", default=1.0,

                      help="Set thesampler rate of the data [default=%default]")

 

    (options, args) = parser.parse_args ()

    if len(args) < 1:

        parser.print_help()

        raise SystemExit, 1

    filenames = args

 

    datatype=scipy.int32

    dc = plot_data(datatype, filenames,options)

 

if__name__ == "__main__":

    try:

        main()

    except KeyboardInterrupt:

        pass

 

 

 

你可能感兴趣的:(linux)