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:
parent
c038cd01d4
commit
4e66b37847
|
@ -27,7 +27,7 @@ import wx
|
|||
from gnuradio import audio
|
||||
from gnuradio import eng_notation
|
||||
from gnuradio import gr
|
||||
from gnuradio import p25_mod_bf
|
||||
from gnuradio import gru
|
||||
from gnuradio import usrp
|
||||
from gnuradio.eng_option import eng_option
|
||||
|
||||
|
@ -39,6 +39,60 @@ except Exception:
|
|||
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.
|
||||
"""
|
||||
|
@ -57,48 +111,41 @@ class usrp_c4fm_tx_block(gr.top_block):
|
|||
|
||||
# open the pcap source
|
||||
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)
|
||||
self.connect(pcap, c4fm)
|
||||
# modulator
|
||||
c4fm = p25_mod_bf(output_sample_rate=channel_rate)
|
||||
|
||||
# setup low pass filter + interpolator
|
||||
interp_factor = self.usrp_rate / self.channel_rate
|
||||
interp_factor = usrp_rate / channel_rate
|
||||
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)
|
||||
self.connect(c4fm, interpolator)
|
||||
|
||||
# frequency modulator
|
||||
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
|
||||
fm = gr.frequency_modulator_fc(k * adjustment)
|
||||
self.connect(interpolator, fm)
|
||||
|
||||
# amplify signal
|
||||
# signal gain
|
||||
gain = gr.multiply_const_cc(4000)
|
||||
self.connect(fm, gain)
|
||||
|
||||
# # configure USRP
|
||||
# configure USRP
|
||||
u = usrp.sink_c()
|
||||
if subdev_spec is None:
|
||||
subdev_spec = usrp.pick_tx_subdevice(u)
|
||||
u.set_mux(usrp.determine_tx_mux_value(u, subdev_spec))
|
||||
subdev = usrp.selected_subdev(u, subdev_spec)
|
||||
print "Using TX d'board %s" % (subdev.side_and_name(),)
|
||||
self.db = usrp.selected_subdev(u, subdev_spec)
|
||||
print "Using TX d'board %s" % (self.db.side_and_name(),)
|
||||
|
||||
if gain is None:
|
||||
g = subdev.gain_range()
|
||||
g = self.db.gain_range()
|
||||
gain = float(g[0] + g[1]) / 2
|
||||
subdev.set_gain(self.subdev.gain_range()[0])
|
||||
u.tune(subdev.which(), subdev, freq)
|
||||
self.connect(gain, u)
|
||||
subdev.set_enable(True)
|
||||
|
||||
# sink = gr.null_sink(gr.sizeof_float)
|
||||
# self.connect(gain, sink)
|
||||
self.db.set_gain(self.db.gain_range()[0])
|
||||
u.tune(self.db.which(), self.db, freq)
|
||||
self.db.set_enable(True)
|
||||
|
||||
self.connect(pcap,c4fm, interpolator, fm, gain, u)
|
||||
|
||||
# inject frames
|
||||
#
|
||||
|
@ -106,7 +153,7 @@ if __name__ == '__main__':
|
|||
|
||||
from optparse import OptionParser
|
||||
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")
|
||||
parser.add_option("-f", "--freq", type="eng_float", default=None,
|
||||
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.run()
|
||||
except KeyboardInterrupt:
|
||||
rx.subdev.set_enable(False)
|
||||
rx.db.set_enable(False)
|
||||
|
|
Reference in New Issue