c4fm_tx_nogui - add Max's modulator, initial testing.

git-svn-id: http://op25.osmocom.org/svn/trunk@275 65a5c917-d112-43f1-993d-58c26a4786be
This commit is contained in:
stevie 2011-04-03 05:12:15 +00:00
parent c038cd01d4
commit 4e66b37847
1 changed files with 71 additions and 24 deletions

View File

@ -27,7 +27,7 @@ import wx
from gnuradio import audio from gnuradio import audio
from gnuradio import eng_notation from gnuradio import eng_notation
from gnuradio import gr from gnuradio import gr
from gnuradio import p25_mod_bf from gnuradio import gru
from gnuradio import usrp from gnuradio import usrp
from gnuradio.eng_option import eng_option from gnuradio.eng_option import eng_option
@ -39,6 +39,60 @@ except Exception:
import fsk4, op25 import fsk4, op25
"""
Hierarchical block for RRC-filtered P25 FM modulation.
The input is a dibit (P25 symbol) stream (char, not packed) and the
output is the float "C4FM" signal at baseband, suitable for
application to an FM modulator stage
Input is at the base symbol rate (4800), output sample rate is
typically either 32000 (USRP TX chain) or 48000 (sound card)
@param output_sample_rate: output sample rate
@type output_sample_rate: integer
@param excess_bw: Root-raised cosine filter excess bandwidth
@type excess_bw: float
@param reverse: reverse polarity flag
@type reverse: bool
@param verbose: Print information about modulator?
@type verbose: bool
@param debug: Print modulation data to files?
@type debug: bool
"""
class p25_mod_bf(gr.hier_block2):
def __init__(self, output_sample_rate):
gr.hier_block2.__init__(self, "p25_c4fm_mod_bf",
gr.io_signature(1, 1, gr.sizeof_char), # Input signature
gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
input_sample_rate = 4800 # P25 baseband symbol rate
lcm = gru.lcm(input_sample_rate, output_sample_rate)
self._interp_factor = int(lcm // input_sample_rate)
self._decimation = int(lcm // output_sample_rate)
self._excess_bw =0.2
mod_map = [1.0/3.0, 1.0, -(1.0/3.0), -1.0]
self.C2S = gr.chunks_to_symbols_bf(mod_map)
ntaps = 11 * self._interp_factor
rrc_taps = gr.firdes.root_raised_cosine(
self._interp_factor, # gain (since we're interpolating by sps)
lcm, # sampling rate
input_sample_rate, # symbol rate
self._excess_bw, # excess bandwidth (roll-off factor)
ntaps)
self.rrc_filter = gr.interp_fir_filter_fff(self._interp_factor, rrc_taps)
# FM pre-emphasis filter
shaping_coeffs = [-0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018]
self.shaping_filter = gr.fir_filter_fff(1, shaping_coeffs)
self.connect(self, self.C2S, self.rrc_filter, self.shaping_filter, self)
""" """
Simple tx-from-pcap-file utility. Simple tx-from-pcap-file utility.
""" """
@ -57,48 +111,41 @@ class usrp_c4fm_tx_block(gr.top_block):
# open the pcap source # open the pcap source
pcap = op25.pcap_source_b(filename, delay, repeat) pcap = op25.pcap_source_b(filename, delay, repeat)
# ToDo: consider octet -> symbol unpacking in flow graph
c4fm = p25_mod_bf.p25_mod(output_sample_rate=channel_rate, log=False, verbose=False) # modulator
self.connect(pcap, c4fm) c4fm = p25_mod_bf(output_sample_rate=channel_rate)
# setup low pass filter + interpolator # setup low pass filter + interpolator
interp_factor = self.usrp_rate / self.channel_rate interp_factor = usrp_rate / channel_rate
low_pass = 2.88e3 low_pass = 2.88e3
interp_taps = gr.firdes.low_pass(1.0, self.usrp_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interp_taps = gr.firdes.low_pass(1.0, usrp_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN)
interpolator = gr.interp_fir_filter_fff (int(interp_factor), interp_taps) interpolator = gr.interp_fir_filter_fff (int(interp_factor), interp_taps)
self.connect(c4fm, interpolator)
# frequency modulator # frequency modulator
max_dev = 12.5e3 max_dev = 12.5e3
k = 2 * math.pi * max_dev / self.usrp_rate k = 2 * math.pi * max_dev / usrp_rate
adjustment = 1.5 # adjust for proper c4fm deviation level adjustment = 1.5 # adjust for proper c4fm deviation level
fm = gr.frequency_modulator_fc(k * adjustment) fm = gr.frequency_modulator_fc(k * adjustment)
self.connect(interpolator, fm)
# amplify signal # signal gain
gain = gr.multiply_const_cc(4000) gain = gr.multiply_const_cc(4000)
self.connect(fm, gain)
# # configure USRP # configure USRP
u = usrp.sink_c() u = usrp.sink_c()
if subdev_spec is None: if subdev_spec is None:
subdev_spec = usrp.pick_tx_subdevice(u) subdev_spec = usrp.pick_tx_subdevice(u)
u.set_mux(usrp.determine_tx_mux_value(u, subdev_spec)) u.set_mux(usrp.determine_tx_mux_value(u, subdev_spec))
subdev = usrp.selected_subdev(u, subdev_spec) self.db = usrp.selected_subdev(u, subdev_spec)
print "Using TX d'board %s" % (subdev.side_and_name(),) print "Using TX d'board %s" % (self.db.side_and_name(),)
if gain is None: if gain is None:
g = subdev.gain_range() g = self.db.gain_range()
gain = float(g[0] + g[1]) / 2 gain = float(g[0] + g[1]) / 2
subdev.set_gain(self.subdev.gain_range()[0]) self.db.set_gain(self.db.gain_range()[0])
u.tune(subdev.which(), subdev, freq) u.tune(self.db.which(), self.db, freq)
self.connect(gain, u) self.db.set_enable(True)
subdev.set_enable(True)
# sink = gr.null_sink(gr.sizeof_float)
# self.connect(gain, sink)
self.connect(pcap,c4fm, interpolator, fm, gain, u)
# inject frames # inject frames
# #
@ -106,7 +153,7 @@ if __name__ == '__main__':
from optparse import OptionParser from optparse import OptionParser
parser = OptionParser (option_class=eng_option) parser = OptionParser (option_class=eng_option)
parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, parser.add_option("-T", "--subdev-spec", type="subdev", default=None,
help="select USRP Tx side A or B") help="select USRP Tx side A or B")
parser.add_option("-f", "--freq", type="eng_float", default=None, parser.add_option("-f", "--freq", type="eng_float", default=None,
help="set Tx frequency to FREQ [required]") help="set Tx frequency to FREQ [required]")
@ -127,4 +174,4 @@ if __name__ == '__main__':
rx = usrp_c4fm_tx_block(options.subdev_spec, options.freq, options.gain, options.pcap_file, options.delay, options.repeat) rx = usrp_c4fm_tx_block(options.subdev_spec, options.freq, options.gain, options.pcap_file, options.delay, options.repeat)
rx.run() rx.run()
except KeyboardInterrupt: except KeyboardInterrupt:
rx.subdev.set_enable(False) rx.db.set_enable(False)