summaryrefslogtreecommitdiff
path: root/gr-analog/python/analog/wfm_rcv_pll.py
diff options
context:
space:
mode:
Diffstat (limited to 'gr-analog/python/analog/wfm_rcv_pll.py')
-rw-r--r--gr-analog/python/analog/wfm_rcv_pll.py223
1 files changed, 67 insertions, 156 deletions
diff --git a/gr-analog/python/analog/wfm_rcv_pll.py b/gr-analog/python/analog/wfm_rcv_pll.py
index bc5e7c27c7..a0fd36fa4f 100644
--- a/gr-analog/python/analog/wfm_rcv_pll.py
+++ b/gr-analog/python/analog/wfm_rcv_pll.py
@@ -1,11 +1,11 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
#
-# Copyright 2005,2006,2012-2013 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
+# SPDX-License-Identifier: GPL-3.0
#
+# GNU Radio Python Flow Graph
+# Title: FM stereo demod block
from __future__ import absolute_import
from __future__ import division
@@ -16,10 +16,8 @@ import math
from gnuradio import gr
from gnuradio import blocks
from gnuradio import filter
-
-from . import analog_python as analog
-from .fm_emph import fm_deemph
-
+from gnuradio.filter import firdes
+from gnuradio import analog
class wfm_rcv_pll(gr.hier_block2):
def __init__(self, demod_rate, audio_decimation):
@@ -36,151 +34,64 @@ class wfm_rcv_pll(gr.hier_block2):
gr.hier_block2.__init__(self, "wfm_rcv_pll",
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(2, 2, gr.sizeof_float)) # Output signature
- bandwidth = 250e3
- audio_rate = demod_rate / audio_decimation
-
-
- # We assign to self so that outsiders can grab the demodulator
- # if they need to. E.g., to plot its output.
- #
- # input: complex; output: float
- loop_bw = 2*math.pi/100.0
- max_freq = 2.0*math.pi*90e3/demod_rate
- self.fm_demod = analog.pll_freqdet_cf(loop_bw, max_freq,-max_freq)
-
- # input: float; output: float
- self.deemph_Left = fm_deemph(audio_rate)
- self.deemph_Right = fm_deemph(audio_rate)
-
- # compute FIR filter taps for audio filter
- width_of_transition_band = audio_rate / 32
- audio_coeffs = filter.firdes.low_pass(1.0 , # gain
- demod_rate, # sampling rate
- 15000 ,
- width_of_transition_band,
- filter.firdes.WIN_HAMMING)
- # input: float; output: float
- self.audio_filter = filter.fir_filter_fff(audio_decimation, audio_coeffs)
- if 1:
- # Pick off the stereo carrier/2 with this filter. It attenuated 10 dB so apply 10 dB gain
- # We pick off the negative frequency half because we want to base band by it!
- ## NOTE THIS WAS HACKED TO OFFSET INSERTION LOSS DUE TO DEEMPHASIS
-
- stereo_carrier_filter_coeffs = \
- filter.firdes.complex_band_pass(10.0,
- demod_rate,
- -19020,
- -18980,
- width_of_transition_band,
- filter.firdes.WIN_HAMMING)
-
- #print "len stereo carrier filter = ",len(stereo_carrier_filter_coeffs)
- #print "stereo carrier filter ", stereo_carrier_filter_coeffs
- #print "width of transition band = ",width_of_transition_band, " audio rate = ", audio_rate
-
- # Pick off the double side band suppressed carrier Left-Right audio. It is attenuated 10 dB so apply 10 dB gain
-
- stereo_dsbsc_filter_coeffs = \
- filter.firdes.complex_band_pass(20.0,
- demod_rate,
- 38000-15000 / 2,
- 38000+15000 / 2,
- width_of_transition_band,
- filter.firdes.WIN_HAMMING)
- #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs)
- #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs
- # construct overlap add filter system from coefficients for stereo carrier
-
- self.stereo_carrier_filter = \
- filter.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs)
-
- # carrier is twice the picked off carrier so arrange to do a complex multiply
-
- self.stereo_carrier_generator = blocks.multiply_cc();
-
- # Pick off the rds signal
-
- stereo_rds_filter_coeffs = \
- filter.firdes.complex_band_pass(30.0,
- demod_rate,
- 57000 - 1500,
- 57000 + 1500,
- width_of_transition_band,
- filter.firdes.WIN_HAMMING)
- #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs)
- #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs
- # construct overlap add filter system from coefficients for stereo carrier
-
- self.rds_signal_filter = \
- filter.fir_filter_fcc(audio_decimation, stereo_rds_filter_coeffs)
-
- self.rds_carrier_generator = blocks.multiply_cc();
- self.rds_signal_generator = blocks.multiply_cc();
- self_rds_signal_processor = blocks.null_sink(gr.sizeof_gr_complex);
-
- loop_bw = 2*math.pi/100.0
- max_freq = -2.0*math.pi*18990/audio_rate;
- min_freq = -2.0*math.pi*19010/audio_rate;
-
- self.stereo_carrier_pll_recovery = \
- analog.pll_refout_cc(loop_bw, max_freq, min_freq);
- #self.stereo_carrier_pll_recovery.squelch_enable(False) #pll_refout does not have squelch yet, so disabled for now
-
- # set up mixer (multiplier) to get the L-R signal at baseband
-
- self.stereo_basebander = blocks.multiply_cc();
-
- # pick off the real component of the basebanded L-R signal. The imaginary SHOULD be zero
-
- self.LmR_real = blocks.complex_to_real();
- self.Make_Left = blocks.add_ff();
- self.Make_Right = blocks.sub_ff();
-
- self.stereo_dsbsc_filter = \
- filter.fir_filter_fcc(audio_decimation, stereo_dsbsc_filter_coeffs)
-
- if 1:
-
- # send the real signal to complex filter to pick off the carrier and then to one side of a multiplier
- self.connect(self, self.fm_demod, self.stereo_carrier_filter,
- self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator,0))
- # send the already filtered carrier to the otherside of the carrier
- self.connect(self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator,1))
- # the resulting signal from this multiplier is the carrier with correct phase but at -38000 Hz.
-
- # send the new carrier to one side of the mixer (multiplier)
- self.connect(self.stereo_carrier_generator, (self.stereo_basebander,0))
- # send the demphasized audio to the DSBSC pick off filter, the complex
- # DSBSC signal at +38000 Hz is sent to the other side of the mixer/multiplier
- self.connect(self.fm_demod,self.stereo_dsbsc_filter, (self.stereo_basebander,1))
- # the result is BASEBANDED DSBSC with phase zero!
-
- # Pick off the real part since the imaginary is theoretically zero and then to one side of a summer
- self.connect(self.stereo_basebander, self.LmR_real, (self.Make_Left,0))
- #take the same real part of the DSBSC baseband signal and send it to negative side of a subtracter
- self.connect(self.LmR_real,(self.Make_Right,1))
-
- # Make rds carrier by taking the squared pilot tone and multiplying by pilot tone
- self.connect(self.stereo_basebander,(self.rds_carrier_generator,0))
- self.connect(self.stereo_carrier_pll_recovery,(self.rds_carrier_generator,1))
- # take signal, filter off rds, send into mixer 0 channel
- self.connect(self.fm_demod,self.rds_signal_filter,(self.rds_signal_generator,0))
- # take rds_carrier_generator output and send into mixer 1 channel
- self.connect(self.rds_carrier_generator,(self.rds_signal_generator,1))
- # send basebanded rds signal and send into "processor" which for now is a null sink
- self.connect(self.rds_signal_generator,self_rds_signal_processor)
+ ##################################################
+ # Variables
+ ##################################################
+ self.samp_rate = samp_rate = 3840000
+ self.rf_decim = rf_decim = 10
+ self.demod_rate = demod_rate = (int)(samp_rate/rf_decim)
+ self.stereo_carrier_filter_coeffs_0 = stereo_carrier_filter_coeffs_0 = firdes.band_pass(1.0, demod_rate, 37600, 38400, 400, firdes.WIN_HAMMING, 6.76)
+ self.stereo_carrier_filter_coeffs = stereo_carrier_filter_coeffs = firdes.complex_band_pass(1.0, demod_rate, 18980, 19020, 1500, firdes.WIN_HAMMING, 6.76)
+ self.deviation = deviation = 75000
+ self.audio_filter = audio_filter = firdes.low_pass(1, demod_rate, 15000,1500, firdes.WIN_HAMMING, 6.76)
+ self.audio_decim = audio_decim = (int)(demod_rate/48000)
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.fir_filter_xxx_1 = filter.fir_filter_fcc(1, stereo_carrier_filter_coeffs)
+ self.fir_filter_xxx_1.declare_sample_delay(0)
+ self.fft_filter_xxx_3 = filter.fft_filter_fff(1, stereo_carrier_filter_coeffs_0, 1)
+ self.fft_filter_xxx_3.declare_sample_delay(0)
+ self.fft_filter_xxx_2 = filter.fft_filter_fff(audio_decim, audio_filter, 1)
+ self.fft_filter_xxx_2.declare_sample_delay(0)
+ self.fft_filter_xxx_1 = filter.fft_filter_fff(audio_decim, audio_filter, 1)
+ self.fft_filter_xxx_1.declare_sample_delay(0)
+ self.blocks_multiply_xx_2 = blocks.multiply_vff(1)
+ self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
+ self.blocks_multiply_const_vxx_0_1 = blocks.multiply_const_ff(5.5)
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(-5.5)
+ self.blocks_complex_to_imag_0 = blocks.complex_to_imag(1)
+ self.blocks_add_xx_0_0 = blocks.add_vff(1)
+ self.blocks_add_xx_0 = blocks.add_vff(1)
+ self.analog_quadrature_demod_cf_0 = analog.quadrature_demod_cf(demod_rate/(2*math.pi*deviation))
+ self.analog_pll_refout_cc_0 = analog.pll_refout_cc(0.001, 2*math.pi * 19200 / demod_rate, 2*math.pi * 18800 / demod_rate)
+ self.analog_fm_deemph_0_0 = analog.fm_deemph(fs=48000, tau=75e-6)
+ self.analog_fm_deemph_0 = analog.fm_deemph(fs=48000, tau=75e-6)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.analog_fm_deemph_0, 0), (self, 1))
+ self.connect((self.analog_fm_deemph_0_0, 0), (self, 0))
+ self.connect((self.analog_pll_refout_cc_0, 0), (self.blocks_multiply_xx_0, 1))
+ self.connect((self.analog_pll_refout_cc_0, 0), (self.blocks_multiply_xx_0, 0))
+ self.connect((self.analog_quadrature_demod_cf_0, 0), (self.blocks_multiply_xx_2, 0))
+ self.connect((self.analog_quadrature_demod_cf_0, 0), (self.fft_filter_xxx_1, 0))
+ self.connect((self.analog_quadrature_demod_cf_0, 0), (self.fir_filter_xxx_1, 0))
+ self.connect((self.blocks_add_xx_0, 0), (self.analog_fm_deemph_0, 0))
+ self.connect((self.blocks_add_xx_0_0, 0), (self.analog_fm_deemph_0_0, 0))
+ self.connect((self.blocks_complex_to_imag_0, 0), (self.fft_filter_xxx_3, 0))
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.blocks_add_xx_0, 0))
+ self.connect((self.blocks_multiply_const_vxx_0_1, 0), (self.blocks_add_xx_0_0, 0))
+ self.connect((self.blocks_multiply_xx_0, 0), (self.blocks_complex_to_imag_0, 0))
+ self.connect((self.blocks_multiply_xx_2, 0), (self.fft_filter_xxx_2, 0))
+ self.connect((self.fft_filter_xxx_1, 0), (self.blocks_add_xx_0, 1))
+ self.connect((self.fft_filter_xxx_1, 0), (self.blocks_add_xx_0_0, 1))
+ self.connect((self.fft_filter_xxx_2, 0), (self.blocks_multiply_const_vxx_0, 0))
+ self.connect((self.fft_filter_xxx_2, 0), (self.blocks_multiply_const_vxx_0_1, 0))
+ self.connect((self.fft_filter_xxx_3, 0), (self.blocks_multiply_xx_2, 1))
+ self.connect((self.fir_filter_xxx_1, 0), (self.analog_pll_refout_cc_0, 0))
+ self.connect((self, 0), (self.analog_quadrature_demod_cf_0, 0))
- if 1:
- # pick off the audio, L+R that is what we used to have and send it to the summer
- self.connect(self.fm_demod, self.audio_filter, (self.Make_Left, 1))
- # take the picked off L+R audio and send it to the PLUS side of the subtractor
- self.connect(self.audio_filter,(self.Make_Right, 0))
- # The result of Make_Left gets (L+R) + (L-R) and results in 2*L
- # The result of Make_Right gets (L+R) - (L-R) and results in 2*R
- self.connect(self.Make_Left , self.deemph_Left, (self, 0))
- self.connect(self.Make_Right, self.deemph_Right, (self, 1))
- # NOTE: mono support will require variable number of outputs in hier_block2s
- # See ticket:174 in Trac database
- #else:
- # self.connect (self.fm_demod, self.audio_filter, self)