diff options
author | Vadim Yanitskiy <axilirator@gmail.com> | 2017-12-03 23:49:09 +0700 |
---|---|---|
committer | Vadim Yanitskiy <axilirator@gmail.com> | 2017-12-04 00:22:39 +0700 |
commit | d222ee58bbc260ea70cc995c70d797768f00f895 (patch) | |
tree | 3d64a030a637b13b73a77f85ce5e6f32fd8addcb | |
parent | 63703bb1ff93d024a175983e57d1045dba997b3b (diff) |
trx/radio_if.py: implement AFC for both RX and TX paths
AFC (Automatic Frequency Control) was previously only utilized in
the receive path of the radio interface. Now we also need to keep
the transmitter frequency as accurate as possible.
-rw-r--r-- | python/trx/radio_if.py | 104 |
1 files changed, 84 insertions, 20 deletions
diff --git a/python/trx/radio_if.py b/python/trx/radio_if.py index dbccae7..1ded337 100644 --- a/python/trx/radio_if.py +++ b/python/trx/radio_if.py @@ -29,12 +29,14 @@ import osmosdr from math import pi -from gnuradio.filter import firdes from gnuradio import digital from gnuradio import blocks from gnuradio import uhd from gnuradio import gr +from gnuradio import filter +from gnuradio.filter import firdes + # HACK: should be implemented in C++! class burst_to_fn_time(gr.basic_block): @@ -55,10 +57,29 @@ class burst_to_fn_time(gr.basic_block): if pmt.to_python(fn_time) is not None: self.message_port_pub(pmt.intern("fn_time_out"), fn_time_msg) +class dict_toggle_sign(gr.basic_block): + def __init__(self): # only default arguments here + gr.basic_block.__init__(self, + name='Change sign of elts in dict', + in_sig=[], + out_sig=[] + ) + self.message_port_register_in(pmt.intern("dict_in")) + self.message_port_register_out(pmt.intern("dict_out")) + self.set_msg_handler(pmt.intern("dict_in"), self.change_sign) + + def change_sign(self, msg): + if pmt.is_dict(msg): + d = pmt.to_python(msg) + for key, value in d.items(): + d[key] *= -1 + self.message_port_pub(pmt.intern("dict_out"), pmt.to_pmt(d)) + class radio_if(gr.top_block): # PHY specific variables rx_freq = 935e6 tx_freq = 890e6 + osr = 4 # Application state flags trx_started = False @@ -75,8 +96,10 @@ class radio_if(gr.top_block): print("[i] Init Radio interface") # PHY specific variables + self.sample_rate = phy_sample_rate self.rx_gain = phy_rx_gain self.tx_gain = phy_tx_gain + self.ppm = phy_ppm gr.top_block.__init__(self, "GR-GSM TRX") @@ -97,14 +120,15 @@ class radio_if(gr.top_block): self.phy_src.set_bandwidth(650e3, 0) self.phy_src.set_gain(phy_rx_gain) - self.gsm_input = grgsm.gsm_input( - ppm = phy_ppm - int(phy_ppm), osr = 4, - fc = self.rx_freq, samp_rate_in = phy_sample_rate) + self.msg_to_tag_src = grgsm.msg_to_tag() - self.gsm_receiver = grgsm.receiver(4, ([0]), ([])) + self.rotator_src = grgsm.controlled_rotator_cc( + self.calc_phase_inc(self.rx_freq)) - self.gsm_clck_ctrl = grgsm.clock_offset_control( - self.rx_freq, phy_sample_rate, osr = 4) + self.lpf = filter.fir_filter_ccf(1, firdes.low_pass( + 1, phy_sample_rate, 125e3, 5e3, firdes.WIN_HAMMING, 6.76)) + + self.gsm_receiver = grgsm.receiver(self.osr, ([0]), ([])) self.ts_filter = grgsm.burst_timeslot_filter(0) self.ts_filter.set_policy(grgsm.FILTER_POLICY_DROP_ALL) @@ -112,10 +136,18 @@ class radio_if(gr.top_block): # Connections self.connect( (self.phy_src, 0), - (self.gsm_input, 0)) + (self.msg_to_tag_src, 0)) self.connect( - (self.gsm_input, 0), + (self.msg_to_tag_src, 0), + (self.rotator_src, 0)) + + self.connect( + (self.rotator_src, 0), + (self.lpf, 0)) + + self.connect( + (self.lpf, 0), (self.gsm_receiver, 0)) self.msg_connect( @@ -126,14 +158,6 @@ class radio_if(gr.top_block): (self.ts_filter, 'out'), (self.trx_burst_if, 'bursts')) - self.msg_connect( - (self.gsm_receiver, 'measurements'), - (self.gsm_clck_ctrl, 'measurements')) - - self.msg_connect( - (self.gsm_clck_ctrl, 'ctrl'), - (self.gsm_input, 'ctrl_in')) - # TX Path Definition self.phy_sink = uhd.usrp_sink(phy_args, @@ -156,12 +180,17 @@ class radio_if(gr.top_block): blocks.byte_t, 'packet_len') self.gmsk_mod = grgsm.gsm_gmsk_mod( - BT = 4, pulse_duration = 4, sps = 4) + BT = 0.3, pulse_duration = 4, sps = self.osr) self.burst_shaper = digital.burst_shaper_cc( (firdes.window(firdes.WIN_HANN, 16, 0)), 0, 20, False, "packet_len") + self.msg_to_tag_sink = grgsm.msg_to_tag() + + self.rotator_sink = grgsm.controlled_rotator_cc( + -self.calc_phase_inc(self.tx_freq)) + # Connections self.msg_connect( (self.trx_burst_if, 'bursts'), @@ -185,6 +214,14 @@ class radio_if(gr.top_block): self.connect( (self.burst_shaper, 0), + (self.msg_to_tag_sink, 0)) + + self.connect( + (self.msg_to_tag_sink, 0), + (self.rotator_sink, 0)) + + self.connect( + (self.rotator_sink, 0), (self.phy_sink, 0)) @@ -205,19 +242,46 @@ class radio_if(gr.top_block): (self.burst_to_fn_time, 'fn_time_out'), (self.tx_time_setter, 'fn_time')) + + # AFC (Automatic Frequency Correction) + self.gsm_clck_ctrl = grgsm.clock_offset_control( + self.rx_freq, phy_sample_rate, osr = self.osr) + + self.dict_toggle_sign = dict_toggle_sign() + + # Connections + self.msg_connect( + (self.gsm_receiver, 'measurements'), + (self.gsm_clck_ctrl, 'measurements')) + + self.msg_connect( + (self.gsm_clck_ctrl, 'ctrl'), + (self.msg_to_tag_src, 'msg')) + + self.msg_connect( + (self.gsm_clck_ctrl, 'ctrl'), + (self.dict_toggle_sign, 'dict_in')) + + self.msg_connect( + (self.dict_toggle_sign, 'dict_out'), + (self.msg_to_tag_sink, 'msg')) + def shutdown(self): print("[i] Shutdown Radio interface") self.stop() self.wait() + def calc_phase_inc(self, fc): + return self.ppm / 1.0e6 * 2 * pi * fc / self.sample_rate + def set_rx_freq(self, fc): self.phy_src.set_center_freq(fc, 0) - self.gsm_clck_ctrl.set_fc(fc) - self.gsm_input.set_fc(fc) + self.rotator_src.set_phase_inc(self.calc_phase_inc(fc)) self.rx_freq = fc def set_tx_freq(self, fc): self.phy_sink.set_center_freq(fc, 0) + self.rotator_sink.set_phase_inc(-self.calc_phase_inc(fc)) self.tx_freq = fc def set_rx_gain(self, gain): |