4 # Copyright 2005, 2006 Free Software Foundation, Inc.
6 # This file is part of GNU Radio
8 # GNU Radio is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2, or (at your option)
13 # GNU Radio is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with GNU Radio; see the file COPYING. If not, write to
20 # the Free Software Foundation, Inc., 51 Franklin Street,
21 # Boston, MA 02110-1301, USA.
24 from gnuradio import gr, gru, modulation_utils
25 from gnuradio import eng_notation
26 from gnuradio.eng_option import eng_option
27 from optparse import OptionParser
29 import random, time, struct, sys, math
32 from transmit_path_lb import transmit_path
33 from receive_path_lb import receive_path
36 class awgn_channel(gr.hier_block2):
37 def __init__(self, sample_rate, noise_voltage, frequency_offset, seed=False):
38 gr.hier_block2.__init__(self, "awgn_channel",
39 gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
40 gr.io_signature(1,1,gr.sizeof_gr_complex)) # Output signature
42 # Create the Gaussian noise source
44 self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage)
46 rseed = int(time.time())
47 self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage, rseed)
48 self.define_component("noise", self.noise)
49 self.define_component("adder", gr.add_cc())
51 # Create the frequency offset
52 self.define_component("offset", gr.sig_source_c((sample_rate*1.0), gr.GR_SIN_WAVE,
53 frequency_offset, 1.0, 0.0))
54 self.define_component("mixer", gr.multiply_cc())
56 # Connect the components
57 self.connect("self", 0, "mixer", 0)
58 self.connect("offset", 0, "mixer", 1)
59 self.connect("mixer", 0, "adder", 0)
60 self.connect("noise", 0, "adder", 1)
61 self.connect("adder", 0, "self", 0)
64 class my_graph(gr.hier_block2):
65 def __init__(self, mod_class, demod_class, rx_callback, options):
66 gr.hier_block2.__init__(self, "my_graph",
67 gr.io_signature(0,0,0), # Input signature
68 gr.io_signature(0,0,0)) # Output signature
72 SNR = 10.0**(options.snr/10.0)
73 frequency_offset = options.frequency_offset
75 power_in_signal = abs(options.tx_amplitude)**2
76 noise_power = power_in_signal/SNR
77 noise_voltage = math.sqrt(noise_power)
79 self.txpath = transmit_path(mod_class, options)
80 self.throttle = gr.throttle(gr.sizeof_gr_complex, options.sample_rate)
81 self.rxpath = receive_path(demod_class, rx_callback, options)
84 self.channel = awgn_channel(options.sample_rate, noise_voltage, frequency_offset, options.seed)
86 # Define the components
87 self.define_component("txpath", self.txpath)
88 self.define_component("throttle", self.throttle)
89 self.define_component("channel", self.channel)
90 self.define_component("rxpath", self.rxpath)
93 self.connect("txpath", 0, "throttle", 0)
94 self.connect("throttle", 0, "channel", 0)
95 self.connect("channel", 0, "rxpath", 0)
97 # Define the components
98 self.define_component("txpath", self.txpath)
99 self.define_component("throttle", self.throttle)
100 self.define_component("rxpath", self.rxpath)
103 self.connect("txpath", 0, "throttle", 0)
104 self.connect("throttle", 0, "rxpath", 0)
107 # /////////////////////////////////////////////////////////////////////////////
109 # /////////////////////////////////////////////////////////////////////////////
113 global n_rcvd, n_right
118 def rx_callback(ok, payload):
119 global n_rcvd, n_right
120 (pktno,) = struct.unpack('!H', payload[0:2])
125 print "ok = %5s pktno = %4d n_rcvd = %4d n_right = %4d" % (
126 ok, pktno, n_rcvd, n_right)
128 def send_pkt(payload='', eof=False):
129 return top_block.txpath.send_pkt(payload, eof)
132 mods = modulation_utils.type_1_mods()
133 demods = modulation_utils.type_1_demods()
135 parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
136 expert_grp = parser.add_option_group("Expert")
137 channel_grp = parser.add_option_group("Channel")
139 parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
141 help="Select modulation from: %s [default=%%default]"
142 % (', '.join(mods.keys()),))
144 parser.add_option("-s", "--size", type="eng_float", default=1500,
145 help="set packet size [default=%default]")
146 parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
147 help="set megabytes to transmit [default=%default]")
148 parser.add_option("","--discontinuous", action="store_true", default=False,
149 help="enable discontinous transmission (bursts of 5 packets)")
151 channel_grp.add_option("", "--sample-rate", type="eng_float", default=1e5,
152 help="set speed of channel/simulation rate to RATE [default=%default]")
153 channel_grp.add_option("", "--snr", type="eng_float", default=30,
154 help="set the SNR of the channel in dB [default=%default]")
155 channel_grp.add_option("", "--frequency-offset", type="eng_float", default=0,
156 help="set frequency offset introduced by channel [default=%default]")
157 channel_grp.add_option("", "--seed", action="store_true", default=False,
158 help="use a random seed for AWGN noise [default=%default]")
160 transmit_path.add_options(parser, expert_grp)
161 receive_path.add_options(parser, expert_grp)
163 for mod in mods.values():
164 mod.add_options(expert_grp)
165 for demod in demods.values():
166 demod.add_options(expert_grp)
168 (options, args) = parser.parse_args ()
174 r = gr.enable_realtime_scheduling()
176 print "Warning: failed to enable realtime scheduling"
178 # Create an instance of a hierarchical block
179 top_block = my_graph(mods[options.modulation], demods[options.modulation], rx_callback, options)
181 # Create an instance of a runtime, passing it the top block
182 runtime = gr.runtime(top_block)
185 # generate and send packets
186 nbytes = int(1e6 * options.megabytes)
189 pkt_size = int(options.size)
192 send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff))
194 if options.discontinuous and pktno % 5 == 4:
202 if __name__ == '__main__':
205 except KeyboardInterrupt: