1# 2# Copyright 2005,2012 Free Software Foundation, Inc. 3# 4# This file is part of GNU Radio 5# 6# GNU Radio is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 3, or (at your option) 9# any later version. 10# 11# GNU Radio is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with GNU Radio; see the file COPYING. If not, write to 18# the Free Software Foundation, Inc., 51 Franklin Street, 19# Boston, MA 02110-1301, USA. 20# 21 22from __future__ import print_function 23from __future__ import absolute_import 24from __future__ import division 25from __future__ import unicode_literals 26 27import math 28 29from gnuradio import gr 30from gnuradio import filter 31 32from . import analog_swig as analog 33from .fm_emph import fm_deemph 34 35 36class nbfm_rx(gr.hier_block2): 37 """ 38 Narrow Band FM Receiver. 39 40 Takes a single complex baseband input stream and produces a single 41 float output stream of audio sample in the range [-1, +1]. 42 43 Args: 44 audio_rate: sample rate of audio stream, >= 16k (integer) 45 quad_rate: sample rate of output stream (integer) 46 tau: preemphasis time constant (default 75e-6) (float) 47 max_dev: maximum deviation in Hz (default 5e3) (float) 48 49 quad_rate must be an integer multiple of audio_rate. 50 51 Exported sub-blocks (attributes): 52 squelch 53 quad_demod 54 deemph 55 audio_filter 56 """ 57 def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3): 58 gr.hier_block2.__init__(self, "nbfm_rx", 59 gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature 60 gr.io_signature(1, 1, gr.sizeof_float)) # Output signature 61 62 # FIXME audio_rate and quad_rate ought to be exact rationals 63 self._audio_rate = audio_rate = int(audio_rate) 64 self._quad_rate = quad_rate = int(quad_rate) 65 66 if quad_rate % audio_rate != 0: 67 raise ValueError("quad_rate is not an integer multiple of audio_rate") 68 69 squelch_threshold = 20 # dB 70 #self.squelch = analog.simple_squelch_cc(squelch_threshold, 0.001) 71 72 # FM Demodulator input: complex; output: float 73 k = quad_rate / (2*math.pi*max_dev) 74 self.quad_demod = analog.quadrature_demod_cf(k) 75 76 # FM Deemphasis IIR filter 77 self.deemph = fm_deemph(quad_rate, tau=tau) 78 79 # compute FIR taps for audio filter 80 audio_decim = quad_rate // audio_rate 81 audio_taps = filter.firdes.low_pass(1.0, # gain 82 quad_rate, # sampling rate 83 2.7e3, # Audio LPF cutoff 84 0.5e3, # Transition band 85 filter.firdes.WIN_HAMMING) # filter type 86 87 print("len(audio_taps) =", len(audio_taps)) 88 89 # Decimating audio filter 90 # input: float; output: float; taps: float 91 self.audio_filter = filter.fir_filter_fff(audio_decim, audio_taps) 92 93 self.connect(self, self.quad_demod, self.deemph, self.audio_filter, self) 94 95 def set_max_deviation(self, max_dev): 96 k = self._quad_rate / (2*math.pi*max_dev) 97 self.quad_demod.set_gain(k) 98