GNU RADIO软件无线电benchmark程序发送接收文件测试笔记
在GNU RADIO软件无线电程序中,benchmark程序可以发射900MHZ,接收900MHZ的无线电信号。具体做法是,把两台装有Basic子板的USRP1母板分别连上两台电脑的USB端口上,接通电源,在ubuntu操作系统下,在其中一台电脑的终端提示符下键入:
“ cd /usr/local/share/gnuradio/example/digital/"
进入benchmark程序的目录, 再键入:
“./benchmark_tx.py -f 900M"
这时候,和这台电脑USB端口连接的USRP母板上的LFTX子板通过电线就会发送一个900MHZ的无线电信号,电脑显示器显示:
“…”
表示正在发射无线电信号。这时,在另外的一台电脑上的终端提示符下键入:
“ cd /usr/locaul/share/gnuradio/example/digital/"
进入benchmark程序的目录, 再键入:
“./benchmark_rx.py -f 900M"
这时候,和这台电脑USB端口连接的USRP母板上的LFTX子板通过电线就会收到一个900MHZ的无线电信号,电脑显示器显示:
ok=True pktno=1202 n_rcvd=1 n_right=0
表明接收信号正常。
现在的问题是要从这个电脑发送一个文件到另外一个电脑,我查找了相关资料发现,benchmark具有发送文件的功能,但是开源程序里没有这项功能,需要用户根据自己的需要修改程序来达到发送接收文件的功能。我通过研究发现,修改程序后,可以把这台电脑的aa.txt文件的“hello“字符发送到另外一台 电脑的tt.txt文件中。具体做法是,在发送端电脑的"/usr/local/share/gnuradio/example/digital"目录下新建aa.txt,tt.txt两个文本文件,在aa.txt中输入"hello"并保存,然后在终端下输入:
“vi benchmark_tx.py"
在vi编辑器下打开benchmark_tx.py程序,在第124行
" tb.start() # start flow graph",
后输入
“f=open("/usr/local/share/gnuradio/examples/digital/aa.txt",“r”)”
“lines=f.readlines()”
两行新程序,第一行程序是以只读方式打开aa.txt文件,第二行程序的作用是以每行阅读的方式读出aa.txt中的文本内容,然后再赋值给"lines"数组,接着把第140行程序
“payload = struct.pack(’!H’, pktno & 0xffff) + data "
改为
" payload = str(options.num ) + str(lines) "
这步的作用是,去掉了打包发送pkno函数的功能,而加入发送lines函数和options.num函数的功能。
现在说一下options.num函数是从哪来的。首先把程序的第95行至第100行,改为
parser.add_option(”-E","–discontinuous", action=“store_true”, default=False,
help=“enable discontinous transmission (bursts of 5 packets)”)
parser.add_option("-W","--from_file",dest="from_file", default=None,
help="use intput file for packet contents")
parser.add_option("-T","--to_file",dest="to_file", default=None,
help="Output file for modulated samples")
parser.add_option("-n","--num",type="int",dest="num",default=1000,
help="send message")
parser.add_option("-e", "--file",dest="filename",
help="write report to FILE",metavar="FILE")
parser.add_option("-p", "--pdbk", action="store_true",
dest="pdcl",
default=False,
help="write pdbk data to oracle db")
parser.add_option("-z", "--zdbk", action="store_true",
dest="zdcl",
default=False,
help="write zdbk data to oracle db")
简单说一下,在终端输入“benchmark_tx -f 900M -n 1500”时,程序以900MHZ的频率发送数组options.num中的数字1500和lines数组,因为
parser.add_option("-n","–num",type=“int”,dest=“num”,default=1000,
help=“send message”)
定义了一个属性是num的option.num函数通过提示符"-n xxx"来返回一个值给option.num数组, 上面其他程序的作用是定义了在终端提示符下发送文件"-W",接收文件"-T",写入给数据库"-p",读取数据库"-z", 其他功能这里暂时不讨论。修改完成后保存文件,退出vi编辑器。
下来在接收端的电脑上的"/usr/local/share/gnuradio/example/digital/narrowband"目录下新建aa.txt,tt.txt两个空白文本文件,然后在终端下输入:
“vi benchmark_rx.py"
在vi编辑器下打开benchmark_rx.py程序,把第79行到第98行的内容改为
global n_rcvd, n_right
global n_data
def main():
global n_rcvd, n_right
global n_data
n_rcvd = 0
n_right = 0
n_data = str()
def rx_callback(ok, payload):
global n_rcvd, n_right
global n_data
(pktno,) = struct.unpack(’!H’, payload[0:2])
n_data = payload[0:4096]
f=open("/usr/local/share/gnuradio/examples/digital/tt.txt",“w”)
f.write(payload)
n_rcvd += 1
if ok:
n_right += 1
print "ok = %5s pktno = %4d n_rcvd = %4d n_right = %4d n_data = %5s" % (
ok, pktno, n_rcvd, n_right, n_data)
其中,
n_data = payload[0:4096]
定义变量n_data用来显示接收的options.num数组和lines数组。 还有上述
f=open("/usr/local/share/gnuradio/examples/digital/narrowband/tt.txt",“w”)
f.write(payload)
两行程序实现了以写入方式打开tt.txt文本文件,然后把接收的payload数组写入tt.txt中。
保存修改退出vi编辑器后,在发送端的电脑/usr/local/share/gnuradio/example/digital的目录下键入
./benchmark_tx.py -f 900M -n 1900
后,电脑显示
“…”
表示发送正常,然后在接收端电脑/usr/local/share/gnuradio/example/digital的目录下键入
./benchmark_tx.py -f 900M
电脑显示
ok = True pktno = 12598 n_rcvd = 458 n_right = 458 n_data = 1900[‘hello\n’]
表示接收正常。用“ctrl+c”键停止接收,打开接收端电脑/usr/local/share/gnuradio/example/digital/的目录下的tt.txt文件,发现原来是空文件的tt.txt,出现’[‘hello\n’]显示,表示发送接收正常.说明发送端电脑上的aa.txt文件中的“hello”字符已经传送到接收端电脑的tt.txt文件中。
给发送端电脑的aa.txt文件中添加字符,如把“hello”改为“hello python”,接收端点脑上的tt.txt文件中显示“[‘hello python\n’]",表明接受正常,当aa.txt中字符的长度超过3571个字节时,接收端就会显示乱码,因为每次程序只能发送低于3571字节的 文本,一旦文本超过了3571字节,发送的信息量太大就会使程序读入数据出错,接收端就会收到乱码,要传送更多字节的文本就要修改程序,这个问题还在研究,现在不做讨论。
下面测试一下能不能用其他子板正常发送接收文本。把上面的两个Basic子板换成两个WBX子板,WBX子板上都连有天线。测试后发现接收端的tt.txt就会显示乱码和误码。例如 原来发送aa.txt文本中的"hello",接收到的tt.txt文本却是为"\welp&*%"。造成这个结果的原因是WBX子板靠天线发送 信号,而LFRX子板是通过屏蔽线传输信号。WBX子板发送无线电后,由于空间中的干扰,无线电信号在传输中会产生衰减和变化,另外的WBX子板接收到的 无线电信号就会和发送的无线电信号不同。要想传输的内容不发生变化,就要修改程序,使每次只发送一个数据,这样接收就不容易产生误码和乱码。修改程序后,把benchmark_tx.py中的
"payload = data + str(lines) + chr(options.num & 0xff) "
改为
“payload = str(lines) “
作用是只把 lines的值赋给发送函数paload,相当于只发送了lines数组。同时把发送端电脑的aa.txt文件里的“hello”改为“h”,只发送一个字符"h”,减少了传送的数据量,此时运行接收
./benchmark_rx.py -f 900M
和发送
./benchmark_tx.py -f 900M
发现接收端电脑的tt.txt文本显示’h’;表明接收成功
附件:benchmark_rx.py源码
#!/usr/bin/python
#!/usr/bin/env python
from gnuradio import gr, gru
from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
from optparse import OptionParser
from gnuradio import digital
from receive_path import receive_path
from uhd_interface import uhd_receiver
import struct
import sys
#import os
#print os.getpid()
#raw_input('Attach and press enter: ')
class my_top_block(gr.top_block):
def init(self, demodulator, rx_callback, options):
gr.top_block.init(self)
if(options.rx_freq is not None):
# Work-around to get the modulation's bits_per_symbol
args = demodulator.extract_kwargs_from_options(options)
symbol_rate = options.bitrate / demodulator(**args).bits_per_symbol()
self.source = uhd_receiver(options.args, symbol_rate,
options.samples_per_symbol, options.rx_freq,
options.lo_offset, options.rx_gain,
options.spec, options.antenna,
options.clock_source, options.verbose)
options.samples_per_symbol = self.source._sps
elif(options.from_file is not None):
sys.stderr.write(("Reading samples from '%s'.\n\n" % (options.from_file)))
self.source = blocks.file_source(gr.sizeof_gr_complex, options.from_file)
else:
sys.stderr.write("No source defined, pulling samples from null source.\n\n")
self.source = blocks.null_source(gr.sizeof_gr_complex)
# Set up receive path
# do this after for any adjustments to the options that may
# occur in the sinks (specifically the UHD sink)
self.rxpath = receive_path(demodulator, rx_callback, options)
self.connect(self.source, self.rxpath)
global n_rcvd, n_right
def main():
global n_rcvd, n_right
global c_rev
n_rcvd = 0
n_right = 0
def rx_callback(ok, payload):#dingyi rx_callback hanshu ,zuoyong shi xianshi jieshoushujubao
global n_rcvd, n_right
global c_rev #dingyi c_rev wei jieshou hanshu
(pktno,) = struct.unpack('!H', payload[0:2])
(c_rev,) = struct.unpack('H', payload[0:2])#c_rev jieshou xinhao
n_rcvd += 1
if ok:
n_right += 1
print "ok = %5s pktno = %4d n_rcvd = %4d n_right = %4d c_rev = %4d" % (
ok, pktno, n_rcvd, n_right,c_rev)
demods = digital.modulation_utils.type_1_demods()
# Create Options Parser:
parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
expert_grp = parser.add_option_group("Expert")
parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(),
default='psk',
help="Select modulation from: %s [default=%%default]"
% (', '.join(demods.keys()),))
parser.add_option("","--from-file", default=None,
help="input file of samples to demod")
receive_path.add_options(parser, expert_grp)
uhd_receiver.add_options(parser)
for mod in demods.values():
mod.add_options(expert_grp)
(options, args) = parser.parse_args ()
if len(args) != 0:
parser.print_help(sys.stderr)
sys.exit(1)
if options.from_file is None:
if options.rx_freq is None:
sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
parser.print_help(sys.stderr)
sys.exit(1)
# build the graph
tb = my_top_block(demods[options.modulation], rx_callback, options)
r = gr.enable_realtime_scheduling()
if r != gr.RT_OK:
print "Warning: Failed to enable realtime scheduling."
tb.start() # start flow graph
tb.wait() # wait for it to finish
if name == ‘main’:
try:
main()
except KeyboardInterrupt:
pass
benchmark_tx.py源码
#!/usr/bin/python
#!/usr/bin/env python
from gnuradio import gr
from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
from optparse import OptionParser#diaoyong minglinghang chuli canshu
from gnuradio import digital
from transmit_path import transmit_path
from uhd_interface import uhd_transmitter
import time, struct, sys
#import os
#print os.getpid()
#raw_input(‘Attach and press enter’)
class my_top_block(gr.top_block):
def init(self, modulator, options):
gr.top_block.init(self)
if(options.tx_freq is not None):
# Work-around to get the modulation's bits_per_symbol
args = modulator.extract_kwargs_from_options(options)
symbol_rate = options.bitrate / modulator(**args).bits_per_symbol()
self.sink = uhd_transmitter(options.args, symbol_rate,
options.samples_per_symbol, options.tx_freq,
options.lo_offset, options.tx_gain,
options.spec, options.antenna,
options.clock_source, options.verbose)
options.samples_per_symbol = self.sink._sps
elif(options.to_file is not None):
sys.stderr.write(("Saving samples to '%s'.\n\n" % (options.to_file)))
self.sink = blocks.file_sink(gr.sizeof_gr_complex, options.to_file)
else:
sys.stderr.write("No sink defined, dumping samples to null sink.\n\n")
self.sink = blocks.null_sink(gr.sizeof_gr_complex)
# do this after for any adjustments to the options that may
# occur in the sinks (specifically the UHD sink)
self.txpath = transmit_path(modulator, options)
self.connect(self.txpath, self.sink)
def main():
def send_pkt(payload='', eof=False):#dingyi fasong hanshu
return tb.txpath.send_pkt(payload, eof)
mods = digital.modulation_utils.type_1_mods()
parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
expert_grp = parser.add_option_group("Expert")
parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
default='psk',
help="Select modulation from: %s [default=%%default]"
% (', '.join(mods.keys()),))
parser.add_option("-s", "--size", type="eng_float", default=1500,
help="set packet size [default=%default]")
parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
help="set megabytes to transmit [default=%default]")
parser.add_option("-E","--discontinuous", action="store_true", default=False,
help="enable discontinous transmission (bursts of 5 packets)")
parser.add_option("-W","--from_file",dest='from_file', default=None,
help="use intput file for packet contents")
parser.add_option("-T","--to_file",dest='to_file', default=None,
help="Output file for modulated samples")
parser.add_option("-n","--num",type="int",dest="num",default=1000,
help="send message")
parser.add_option("-p", "--pdbk", action="store_true",
dest="pdcl",
default=False,
help="write pdbk data to oracle db")
parser.add_option("-z", "--zdbk", action="store_true",
dest="zdcl",
default=False,
help="write zdbk data to oracle db")
transmit_path.add_options(parser, expert_grp)
uhd_transmitter.add_options(parser)
for mod in mods.values():
mod.add_options(expert_grp)
(options, args) = parser.parse_args ()
# print 'pdcl is true'
# print 'zdcl is true'
if len(args) != 0:
parser.print_help()
sys.exit(1)
if options.from_file is not None:
source_file = open(options.from_file, 'r')
# build the graph
tb = my_top_block(mods[options.modulation], options)
r = gr.enable_realtime_scheduling()
if r != gr.RT_OK:
print "Warning: failed to enable realtime scheduling"
tb.start() # start flow graph
# generate and send packets
nbytes = int(1e6 * options.megabytes)
n = 0
pktno = 0
pkt_size = int(options.size)
while n < nbytes:
if options.from_file is None:
data =(pkt_size - 2) * chr(pktno & 0xff)
else:
data = source_file.read(pkt_size - 2)
if data == '':
break;
payload = struct.pack('!H', pktno & 0xffff) + data# + open(options.data)
# payload=data#+struct.pack('!H',pktno & 0xffff)
send_pkt(payload)
n += len(payload)
sys.stderr.write('.')
if options.discontinuous and pktno % 5 == 4:
time.sleep(1)
pktno += 1
send_pkt(eof=True)
tb.wait() # wait for it to finish
if name == ‘main’:
try:
main()
except KeyboardInterrupt:
pass