1#
2# Copyright 2005,2007,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_preemph
34
35
36class wfm_tx(gr.hier_block2):
37    def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3, fh=-1.0):
38        """
39        Wide Band FM Transmitter.
40
41        Takes a single float input stream of audio samples in the range [-1,+1]
42        and produces a single FM modulated complex baseband output.
43
44        Args:
45            audio_rate: sample rate of audio stream, >= 16k (integer)
46            quad_rate: sample rate of output stream (integer)
47            tau: preemphasis time constant (default 75e-6) (float)
48            max_dev: maximum deviation in Hz (default 75e3) (float)
49            fh: high frequency at which to flatten preemphasis; < 0 means default of 0.925*quad_rate/2.0 (float)
50
51        quad_rate must be an integer multiple of audio_rate.
52        """
53        gr.hier_block2.__init__(self, "wfm_tx",
54                                gr.io_signature(1, 1, gr.sizeof_float),      # Input signature
55                                gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
56
57        # FIXME audio_rate and quad_rate ought to be exact rationals
58        audio_rate = int(audio_rate)
59        quad_rate = int(quad_rate)
60
61        if quad_rate % audio_rate != 0:
62            raise ValueError("quad_rate is not an integer multiple of audio_rate")
63
64
65        do_interp = audio_rate != quad_rate
66
67        if do_interp:
68            interp_factor = quad_rate / audio_rate
69            interp_taps = filter.optfir.low_pass(interp_factor,   # gain
70                                                 quad_rate,       # Fs
71                                                 16000,           # passband cutoff
72                                                 18000,           # stopband cutoff
73                                                 0.1,             # passband ripple dB
74                                                 40)              # stopband atten dB
75
76            print("len(interp_taps) =", len(interp_taps))
77            self.interpolator = filter.interp_fir_filter_fff (interp_factor, interp_taps)
78
79        self.preemph = fm_preemph(quad_rate, tau=tau, fh=fh)
80
81        k = 2 * math.pi * max_dev / quad_rate
82        self.modulator = analog.frequency_modulator_fc (k)
83
84        if do_interp:
85            self.connect(self, self.interpolator, self.preemph, self.modulator, self)
86        else:
87            self.connect(self, self.preemph, self.modulator, self)
88