summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/python/gnuradio/blksimpl
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core/src/python/gnuradio/blksimpl')
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am49
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/__init__.py1
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/am_demod.py75
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/digital_voice.py.real102
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/filterbank.py160
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/fm_demod.py122
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/fm_emph.py145
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py159
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py174
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/nbfm_rx.py87
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/nbfm_tx.py95
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/pkt.py156
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/rational_resampler.py137
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/standard_squelch.py73
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv.py72
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv_pll.py206
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/wfm_tx.py79
17 files changed, 1892 insertions, 0 deletions
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am
new file mode 100644
index 0000000000..415920b299
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am
@@ -0,0 +1,49 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+# EXTRA_DIST = run_tests.in
+# TESTS = run_tests
+
+grblkspythondir = $(grpythondir)/blksimpl
+
+grblkspython_PYTHON = \
+ __init__.py \
+ am_demod.py \
+ filterbank.py \
+ fm_demod.py \
+ fm_emph.py \
+ gmsk2.py \
+ gmsk2_pkt.py \
+ nbfm_rx.py \
+ nbfm_tx.py \
+ pkt.py \
+ rational_resampler.py \
+ standard_squelch.py \
+ wfm_rcv.py \
+ wfm_rcv_pll.py \
+ wfm_tx.py
+
+
+noinst_PYTHON =
+
+CLEANFILES = *.pyc *.pyo
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/__init__.py b/gnuradio-core/src/python/gnuradio/blksimpl/__init__.py
new file mode 100644
index 0000000000..a4917cf64c
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/__init__.py
@@ -0,0 +1 @@
+# make this a package
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/am_demod.py b/gnuradio-core/src/python/gnuradio/blksimpl/am_demod.py
new file mode 100644
index 0000000000..309f5e6504
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/am_demod.py
@@ -0,0 +1,75 @@
+#
+# Copyright 2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr, optfir
+
+class am_demod_cf(gr.hier_block):
+ """
+ Generalized AM demodulation block with audio filtering.
+
+ This block demodulates a band-limited, complex down-converted AM
+ channel into the the original baseband signal, applying low pass
+ filtering to the audio output. It produces a float stream in the
+ range [-1.0, +1.0].
+
+ @param fg: flowgraph
+ @param channel_rate: incoming sample rate of the AM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ @param audio_pass: audio low pass filter passband frequency
+ @type audio_pass: float
+ @param audio_stop: audio low pass filter stop frequency
+ @type audio_stop: float
+ """
+ def __init__(self, fg, channel_rate, audio_decim, audio_pass, audio_stop):
+ MAG = gr.complex_to_mag()
+ DCR = gr.add_const_ff(-1.0)
+
+ audio_taps = optfir.low_pass(0.5, # Filter gain
+ channel_rate, # Sample rate
+ audio_pass, # Audio passband
+ audio_stop, # Audio stopband
+ 0.1, # Passband ripple
+ 60) # Stopband attenuation
+ LPF = gr.fir_filter_fff(audio_decim, audio_taps)
+
+ fg.connect(MAG, DCR, LPF)
+ gr.hier_block.__init__(self, fg, MAG, LPF)
+
+class demod_10k0a3e_cf(am_demod_cf):
+ """
+ AM demodulation block, 10 KHz channel.
+
+ This block demodulates an AM channel conformant to 10K0A3E emission
+ standards, such as broadcast band AM transmissions.
+
+ @param fg: flowgraph
+ @param channel_rate: incoming sample rate of the AM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ """
+ def __init__(self, fg, channel_rate, audio_decim):
+ am_demod_cf.__init__(self, fg, channel_rate, audio_decim,
+ 5000, # Audio passband
+ 5500) # Audio stopband
+ \ No newline at end of file
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/digital_voice.py.real b/gnuradio-core/src/python/gnuradio/blksimpl/digital_voice.py.real
new file mode 100644
index 0000000000..1b3a14f3e7
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/digital_voice.py.real
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+"""
+Digital voice Tx and Rx using GSM 13kbit vocoder and GMSK.
+
+Runs channel at 32kbit/sec. Currently uses fake channel coding,
+but there's room for a rate 1/2 coder.
+"""
+
+from gnuradio import gr, gru
+from gnuradio.blksimpl.gmsk import gmsk_mod, gmsk_demod
+
+from gnuradio.vocoder import gsm_full_rate
+
+# Size of gsm full rate speech encoder output packet in bytes
+
+GSM_FRAME_SIZE = 33
+
+# Size of packet in bytes that we send to GMSK modulator:
+#
+# Target: 256kS/sec air rate.
+#
+# 256kS 1 sym 1 bit 1 byte 0.020 sec 80 bytes
+# ---- * ----- * ----- * ------ * --------- = --------
+# sec 8 S 1 sym 8 bits frame frame
+#
+# gr_simple_framer add 10 bytes of overhead.
+
+AIR_FRAME_SIZE = 70
+
+
+class digital_voice_tx(gr.hier_block):
+ """
+ Hierarchical block for digital voice tranmission.
+
+ The input is 8kS/sec floating point audio in the range [-1,+1]
+ The output is 256kS/sec GMSK modulated complex baseband signal in the range [-1,+1].
+ """
+ def __init__(self, fg):
+ samples_per_symbol = 8
+ symbol_rate = 32000
+ bt = 0.3 # Gaussian filter bandwidth * symbol time
+
+ src_scale = gr.multiply_const_ff(32767)
+ f2s = gr.float_to_short()
+ voice_coder = gsm_full_rate.encode_sp()
+
+ channel_coder = gr.fake_channel_encoder_pp(GSM_FRAME_SIZE, AIR_FRAME_SIZE)
+ p2s = gr.parallel_to_serial(gr.sizeof_char, AIR_FRAME_SIZE)
+
+ mod = gmsk_mod(fg, sps=samples_per_symbol,
+ symbol_rate=symbol_rate, bt=bt,
+ p_size=AIR_FRAME_SIZE)
+
+ fg.connect(src_scale, f2s, voice_coder, channel_coder, p2s, mod)
+ gr.hier_block.__init__(self, fg, src_scale, mod)
+
+
+class digital_voice_rx(gr.hier_block):
+ """
+ Hierarchical block for digital voice reception.
+
+ The input is 256kS/sec GMSK modulated complex baseband signal.
+ The output is 8kS/sec floating point audio in the range [-1,+1]
+ """
+ def __init__(self, fg):
+ samples_per_symbol = 8
+ symbol_rate = 32000
+
+ demod = gmsk_demod(fg, sps=samples_per_symbol,
+ symbol_rate=symbol_rate,
+ p_size=AIR_FRAME_SIZE)
+
+ s2p = gr.serial_to_parallel(gr.sizeof_char, AIR_FRAME_SIZE)
+ channel_decoder = gr.fake_channel_decoder_pp(AIR_FRAME_SIZE, GSM_FRAME_SIZE)
+
+ voice_decoder = gsm_full_rate.decode_ps()
+ s2f = gr.short_to_float ()
+ sink_scale = gr.multiply_const_ff(1.0/32767.)
+
+ fg.connect(demod, s2p, channel_decoder, voice_decoder, s2f, sink_scale)
+ gr.hier_block.__init__(self, fg, demod, sink_scale)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/filterbank.py b/gnuradio-core/src/python/gnuradio/blksimpl/filterbank.py
new file mode 100644
index 0000000000..bd23f7936d
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/filterbank.py
@@ -0,0 +1,160 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import sys
+from gnuradio import gr, gru
+
+def _generate_synthesis_taps(mpoints):
+ return [] # FIXME
+
+
+def _split_taps(taps, mpoints):
+ assert (len(taps) % mpoints) == 0
+ result = [list() for x in range(mpoints)]
+ for i in xrange(len(taps)):
+ (result[i % mpoints]).append(taps[i])
+ return [tuple(x) for x in result]
+
+
+class synthesis_filterbank(gr.hier_block):
+ """
+ Uniformly modulated polyphase DFT filter bank: synthesis
+
+ See http://cnx.rice.edu/content/m10424/latest
+ """
+ def __init__(self, fg, mpoints, taps=None):
+ """
+ Takes M complex streams in, produces single complex stream out
+ that runs at M times the input sample rate
+
+ @param fg: flow_graph
+ @param mpoints: number of freq bins/interpolation factor/subbands
+ @param taps: filter taps for subband filter
+
+ The channel spacing is equal to the input sample rate.
+ The total bandwidth and output sample rate are equal the input
+ sample rate * nchannels.
+
+ Output stream to frequency mapping:
+
+ channel zero is at zero frequency.
+
+ if mpoints is odd:
+
+ Channels with increasing positive frequencies come from
+ channels 1 through (N-1)/2.
+
+ Channel (N+1)/2 is the maximum negative frequency, and
+ frequency increases through N-1 which is one channel lower
+ than the zero frequency.
+
+ if mpoints is even:
+
+ Channels with increasing positive frequencies come from
+ channels 1 through (N/2)-1.
+
+ Channel (N/2) is evenly split between the max positive and
+ negative bins.
+
+ Channel (N/2)+1 is the maximum negative frequency, and
+ frequency increases through N-1 which is one channel lower
+ than the zero frequency.
+
+ Channels near the frequency extremes end up getting cut
+ off by subsequent filters and therefore have diminished
+ utility.
+ """
+ item_size = gr.sizeof_gr_complex
+
+ if taps is None:
+ taps = _generate_synthesis_taps(mpoints)
+
+ # pad taps to multiple of mpoints
+ r = len(taps) % mpoints
+ if r != 0:
+ taps = taps + (mpoints - r) * (0,)
+
+ # split in mpoints separate set of taps
+ sub_taps = _split_taps(taps, mpoints)
+
+ self.ss2v = gr.streams_to_vector(item_size, mpoints)
+ self.ifft = gr.fft_vcc(mpoints, False, [])
+ self.v2ss = gr.vector_to_streams(item_size, mpoints)
+ # mpoints filters go in here...
+ self.ss2s = gr.streams_to_stream(item_size, mpoints)
+
+ fg.connect(self.ss2v, self.ifft, self.v2ss)
+
+ # build mpoints fir filters...
+ for i in range(mpoints):
+ f = gr.fft_filter_ccc(1, sub_taps[i])
+ fg.connect((self.v2ss, i), f)
+ fg.connect(f, (self.ss2s, i))
+
+ gr.hier_block.__init__(self, fg, self.ss2v, self.ss2s)
+
+
+class analysis_filterbank(gr.hier_block):
+ """
+ Uniformly modulated polyphase DFT filter bank: analysis
+
+ See http://cnx.rice.edu/content/m10424/latest
+ """
+ def __init__(self, fg, mpoints, taps=None):
+ """
+ Takes 1 complex stream in, produces M complex streams out
+ that runs at 1/M times the input sample rate
+
+ @param fg: flow_graph
+ @param mpoints: number of freq bins/interpolation factor/subbands
+ @param taps: filter taps for subband filter
+
+ Same channel to frequency mapping as described above.
+ """
+ item_size = gr.sizeof_gr_complex
+
+ if taps is None:
+ taps = _generate_synthesis_taps(mpoints)
+
+ # pad taps to multiple of mpoints
+ r = len(taps) % mpoints
+ if r != 0:
+ taps = taps + (mpoints - r) * (0,)
+
+ # split in mpoints separate set of taps
+ sub_taps = _split_taps(taps, mpoints)
+
+ # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps)
+
+ self.s2ss = gr.stream_to_streams(item_size, mpoints)
+ # filters here
+ self.ss2v = gr.streams_to_vector(item_size, mpoints)
+ self.fft = gr.fft_vcc(mpoints, True, [])
+ self.v2ss = gr.vector_to_streams(item_size, mpoints)
+
+ # build mpoints fir filters...
+ for i in range(mpoints):
+ f = gr.fft_filter_ccc(1, sub_taps[mpoints-i-1])
+ fg.connect((self.s2ss, i), f)
+ fg.connect(f, (self.ss2v, i))
+
+ fg.connect(self.ss2v, self.fft, self.v2ss)
+ gr.hier_block.__init__(self, fg, self.s2ss, self.v2ss)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/fm_demod.py b/gnuradio-core/src/python/gnuradio/blksimpl/fm_demod.py
new file mode 100644
index 0000000000..9487e0f0fc
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/fm_demod.py
@@ -0,0 +1,122 @@
+#
+# Copyright 2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr, optfir
+from gnuradio.blksimpl.fm_emph import fm_deemph
+from math import pi
+
+class fm_demod_cf(gr.hier_block):
+ """
+ Generalized FM demodulation block with deemphasis and audio
+ filtering.
+
+ This block demodulates a band-limited, complex down-converted FM
+ channel into the the original baseband signal, optionally applying
+ deemphasis. Low pass filtering is done on the resultant signal. It
+ produces an output float strem in the range of [-1.0, +1.0].
+
+ @param fg: flowgraph
+ @param channel_rate: incoming sample rate of the FM baseband
+ @type sample_rate: integer
+ @param deviation: maximum FM deviation (default = 5000)
+ @type deviation: float
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ @param audio_pass: audio low pass filter passband frequency
+ @type audio_pass: float
+ @param audio_stop: audio low pass filter stop frequency
+ @type audio_stop: float
+ @param gain: gain applied to audio output (default = 1.0)
+ @type gain: float
+ @param tau: deemphasis time constant (default = 75e-6), specify 'None'
+ to prevent deemphasis
+ """
+ def __init__(self, fg, channel_rate, audio_decim, deviation,
+ audio_pass, audio_stop, gain=1.0, tau=75e-6):
+
+ """
+ # Equalizer for ~100 us delay
+ delay = 100e-6
+ num_taps = int(channel_rate*delay)
+
+ mu = 1e-4/num_taps
+ print "CMA: delay =", delay, "n =", num_taps, "mu =", mu
+ CMA = gr.cma_equalizer_cc(num_taps, 1.0, mu)
+ """
+ k = channel_rate/(2*pi*deviation)
+ QUAD = gr.quadrature_demod_cf(k)
+
+ audio_taps = optfir.low_pass(gain, # Filter gain
+ channel_rate, # Sample rate
+ audio_pass, # Audio passband
+ audio_stop, # Audio stopband
+ 0.1, # Passband ripple
+ 60) # Stopband attenuation
+ LPF = gr.fir_filter_fff(audio_decim, audio_taps)
+
+ if tau is not None:
+ DEEMPH = fm_deemph(fg, channel_rate, tau)
+ fg.connect(QUAD, DEEMPH, LPF)
+ else:
+ fg.connect(QUAD, LPF)
+
+ gr.hier_block.__init__(self, fg, QUAD, LPF)
+
+class demod_20k0f3e_cf(fm_demod_cf):
+ """
+ NBFM demodulation block, 20 KHz channels
+
+ This block demodulates a complex, downconverted, narrowband FM
+ channel conforming to 20K0F3E emission standards, outputting
+ floats in the range [-1.0, +1.0].
+
+ @param fg: flowgraph
+ @param sample_rate: incoming sample rate of the FM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ """
+ def __init__(self, fg, channel_rate, audio_decim):
+ fm_demod_cf.__init__(self, fg, channel_rate, audio_decim,
+ 5000, # Deviation
+ 3000, # Audio passband frequency
+ 4000) # Audio stopband frequency
+
+class demod_200kf3e_cf(fm_demod_cf):
+ """
+ WFM demodulation block, mono.
+
+ This block demodulates a complex, downconverted, wideband FM
+ channel conforming to 200KF3E emission standards, outputting
+ floats in the range [-1.0, +1.0].
+
+ @param fg: flowgraph
+ @param sample_rate: incoming sample rate of the FM baseband
+ @type sample_rate: integer
+ @param audio_decim: input to output decimation rate
+ @type audio_decim: integer
+ """
+ def __init__(self, fg, channel_rate, audio_decim):
+ fm_demod_cf.__init__(self, fg, channel_rate, audio_decim,
+ 75000, # Deviation
+ 15000, # Audio passband
+ 16000, # Audio stopband
+ 20.0) # Audio gain
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/fm_emph.py b/gnuradio-core/src/python/gnuradio/blksimpl/fm_emph.py
new file mode 100644
index 0000000000..5c256f5d04
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/fm_emph.py
@@ -0,0 +1,145 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr
+import math
+
+
+#
+# 1
+# H(s) = -------
+# 1 + s
+#
+# tau is the RC time constant.
+# critical frequency: w_p = 1/tau
+#
+# We prewarp and use the bilinear z-transform to get our IIR coefficients.
+# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis
+#
+
+class fm_deemph(gr.hier_block):
+ """
+ FM Deemphasis IIR filter.
+ """
+ def __init__(self, fg, fs, tau=75e-6):
+ """
+ @param fg: flow graph
+ @type fg: gr.flow_graph
+ @param fs: sampling frequency in Hz
+ @type fs: float
+ @param tau: Time constant in seconds (75us in US, 50us in EUR)
+ @type tau: float
+ """
+ w_p = 1/tau
+ w_pp = math.tan (w_p / (fs * 2)) # prewarped analog freq
+
+ a1 = (w_pp - 1)/(w_pp + 1)
+ b0 = w_pp/(1 + w_pp)
+ b1 = b0
+
+ btaps = [b0, b1]
+ ataps = [1, a1]
+
+ if 0:
+ print "btaps =", btaps
+ print "ataps =", ataps
+ global plot1
+ plot1 = gru.gnuplot_freqz (gru.freqz (btaps, ataps), fs, True)
+
+ deemph = gr.iir_filter_ffd(btaps, ataps)
+ gr.hier_block.__init__(self, fg, deemph, deemph)
+
+#
+# 1 + s*t1
+# H(s) = ----------
+# 1 + s*t2
+#
+# I think this is the right transfer function.
+#
+#
+# This fine ASCII rendition is based on Figure 5-15
+# in "Digital and Analog Communication Systems", Leon W. Couch II
+#
+#
+# R1
+# +-----||------+
+# | |
+# o------+ +-----+--------o
+# | C1 | |
+# +----/\/\/\/--+ \
+# /
+# \ R2
+# /
+# \
+# |
+# o--------------------------+--------o
+#
+# f1 = 1/(2*pi*t1) = 1/(2*pi*R1*C)
+#
+# 1 R1 + R2
+# f2 = ------- = ------------
+# 2*pi*t2 2*pi*R1*R2*C
+#
+# t1 is 75us in US, 50us in EUR
+# f2 should be higher than our audio bandwidth.
+#
+#
+# The Bode plot looks like this:
+#
+#
+# /----------------
+# /
+# / <-- slope = 20dB/decade
+# /
+# -------------/
+# f1 f2
+#
+# We prewarp and use the bilinear z-transform to get our IIR coefficients.
+# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis
+#
+
+class fm_preemph(gr.hier_block):
+ """
+ FM Preemphasis IIR filter.
+ """
+ def __init__(self, fg, fs, tau=75e-6):
+ """
+ @param fg: flow graph
+ @type fg: gr.flow_graph
+ @param fs: sampling frequency in Hz
+ @type fs: float
+ @param tau: Time constant in seconds (75us in US, 50us in EUR)
+ @type tau: float
+ """
+
+ # FIXME make this compute the right answer
+
+ btaps = [1]
+ ataps = [1]
+
+ if 0:
+ print "btaps =", btaps
+ print "ataps =", ataps
+ global plot2
+ plot2 = gru.gnuplot_freqz (gru.freqz (btaps, ataps), fs, True)
+
+ preemph = gr.iir_filter_ffd(btaps, ataps)
+ gr.hier_block.__init__(self, fg, preemph, preemph)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py
new file mode 100644
index 0000000000..68d189679d
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py
@@ -0,0 +1,159 @@
+#
+# GMSK modulation and demodulation.
+#
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+from gnuradio import gr
+from math import pi
+import Numeric
+
+# /////////////////////////////////////////////////////////////////////////////
+# GMSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class gmsk2_mod(gr.hier_block):
+
+ def __init__(self, fg, spb = 2, bt = 0.3):
+ """
+ Hierarchical block for Gaussian Minimum Shift Key (GMSK)
+ modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud >= 2
+ @type spb: integer
+ @param bt: Gaussian filter bandwidth * symbol time
+ @type bt: float
+ """
+ if not isinstance(spb, int) or spb < 2:
+ raise TypeError, "sbp must be an integer >= 2"
+ self.spb = spb
+
+ ntaps = 4 * spb # up to 3 bits in filter at once
+ sensitivity = (pi / 2) / spb # phase change per bit = pi / 2
+
+ # Turn it into NRZ data.
+ self.nrz = gr.bytes_to_syms()
+
+ # Form Gaussian filter
+
+ # Generate Gaussian response (Needs to be convolved with window below).
+ self.gaussian_taps = gr.firdes.gaussian(
+ 1, # gain
+ spb, # symbol_rate
+ bt, # bandwidth * symbol time
+ ntaps # number of taps
+ )
+
+ self.sqwave = (1,) * spb # rectangular window
+ self.taps = Numeric.convolve(Numeric.array(self.gaussian_taps),Numeric.array(self.sqwave))
+ self.gaussian_filter = gr.interp_fir_filter_fff(spb, self.taps)
+
+ # FM modulation
+ self.fmmod = gr.frequency_modulator_fc(sensitivity)
+
+ # Connect
+ fg.connect(self.nrz, self.gaussian_filter, self.fmmod)
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.nrz, self.fmmod)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM
+
+
+class gmsk2_demod(gr.hier_block):
+
+ def __init__(self, fg, spb=2, omega=None, gain_mu=0.03, mu=0.5,
+ omega_relative_limit=0.000200, freq_error=0.0):
+ """
+ Hierarchical block for Gaussian Minimum Shift Key (GMSK)
+ demodulation.
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of symbols ready to be sliced at zero.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param spb: samples per baud
+ @type spb: integer
+
+ Clock recovery parameters. These all have reasonble defaults.
+
+ @param omega: nominal relative freq (defaults to spb)
+ @type omega: float
+ @param gain_mu: controls rate of mu adjustment
+ @type gain_mu: float
+ @param mu: fractional delay [0.0, 1.0]
+ @type mu: float
+ @param omega_relative_limit: sets max variation in omega
+ @type omega_relative_limit: float, typically 0.000200 (200 ppm)
+ @param freq_error: bit rate error as a fraction
+ @param float
+ """
+ if spb < 2:
+ raise TypeError, "sbp >= 2"
+ self.spb = spb
+
+ if omega is None:
+ omega = spb*(1+freq_error)
+
+ gain_omega = .25*gain_mu*gain_mu # critically damped
+
+ # Automatic gain control
+ self.preamp = gr.multiply_const_cc(10e-5)
+ self.agc = gr.agc_cc(1e-3, 1, 1, 1000)
+
+ # Demodulate FM
+ sensitivity = (pi / 2) / spb
+ self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity)
+
+ alpha = 0.0008
+
+ # the clock recovery block tracks the symbol clock and resamples as needed.
+ # the output of the block is a stream of soft symbols (float)
+ self.clock_recovery = gr.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu,
+ omega_relative_limit)
+
+ # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
+ self.slicer = gr.binary_slicer_fb()
+
+ fg.connect(self.preamp, self.agc, self.fmdemod, self.clock_recovery, self.slicer)
+
+ # Initialize base class
+ gr.hier_block.__init__(self, fg, self.preamp, self.slicer)
+
+ def samples_per_baud(self):
+ return self.spb
+
+ def bits_per_baud(self=None): # staticmethod that's also callable on an instance
+ return 1
+ bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py
new file mode 100644
index 0000000000..af586239a5
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py
@@ -0,0 +1,174 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from math import pi
+import Numeric
+
+from gnuradio import gr, packet_utils
+import gnuradio.gr.gr_threading as _threading
+import gmsk2
+
+
+def _deprecation_warning(old_name, new_name):
+ print '#'
+ print '# Warning: %s is deprecated and will be removed soon.' % (old_name,)
+ print '# Please use the modulation independent block, %s.' % (new_name,)
+ print "#"
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# GMSK mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class gmsk2_mod_pkts(gr.hier_block):
+ """
+ GSM modulator that is a GNU Radio source.
+
+ Send packets by calling send_pkt
+ """
+ def __init__(self, fg, access_code=None, msgq_limit=2, pad_for_usrp=True, *args, **kwargs):
+ """
+ Hierarchical block for Gaussian Minimum Shift Key (GMSK) modulation.
+
+ Packets to be sent are enqueued by calling send_pkt.
+ The output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param access_code: AKA sync vector
+ @type access_code: string of 1's and 0's between 1 and 64 long
+ @param msgq_limit: maximum number of messages in message queue
+ @type msgq_limit: int
+ @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
+
+ See gmsk_mod for remaining parameters
+ """
+ _deprecation_warning('gmsk2_mod_pkts', 'mod_pkts')
+
+ self.pad_for_usrp = pad_for_usrp
+ if access_code is None:
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+
+ # accepts messages from the outside world
+ self.pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
+ self.gmsk_mod = gmsk2.gmsk2_mod(fg, *args, **kwargs)
+ fg.connect(self.pkt_input, self.gmsk_mod)
+ gr.hier_block.__init__(self, fg, None, self.gmsk_mod)
+
+ def send_pkt(self, payload='', eof=False):
+ """
+ Send the payload.
+
+ @param payload: data to send
+ @type payload: string
+ """
+ if eof:
+ msg = gr.message(1) # tell self.pkt_input we're not sending any more packets
+ else:
+ # print "original_payload =", string_to_hex_list(payload)
+ pkt = packet_utils.make_packet(payload,
+ self.gmsk_mod.samples_per_baud(),
+ self.gmsk_mod.bits_per_baud(),
+ self._access_code,
+ self.pad_for_usrp)
+ #print "pkt =", string_to_hex_list(pkt)
+ msg = gr.message_from_string(pkt)
+ self.pkt_input.msgq().insert_tail(msg)
+
+
+
+class gmsk2_demod_pkts(gr.hier_block):
+ """
+ GSM demodulator that is a GNU Radio sink.
+
+ The input is complex baseband. When packets are demodulated, they are passed to the
+ app via the callback.
+ """
+
+ def __init__(self, fg, access_code=None, callback=None, threshold=-1, *args, **kwargs):
+ """
+ Hierarchical block for Gaussian Minimum Shift Key (GMSK)
+ demodulation.
+
+ The input is the complex modulated signal at baseband.
+ Demodulated packets are sent to the handler.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param access_code: AKA sync vector
+ @type access_code: string of 1's and 0's
+ @param callback: function of two args: ok, payload
+ @type callback: ok: bool; payload: string
+ @param threshold: detect access_code with up to threshold bits wrong (-1 -> use default)
+ @type threshold: int
+
+ See gmsk_demod for remaining parameters.
+ """
+
+ _deprecation_warning('gmsk2_demod_pkts', 'demod_pkts')
+
+ if access_code is None:
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+
+ if threshold == -1:
+ threshold = 12 # FIXME raise exception
+
+ self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY
+ self.gmsk_demod = gmsk2.gmsk2_demod(fg, *args, **kwargs)
+ self.correlator = gr.correlate_access_code_bb(access_code, threshold)
+
+ self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
+ fg.connect(self.gmsk_demod, self.correlator, self.framer_sink)
+
+ gr.hier_block.__init__(self, fg, self.gmsk_demod, None)
+ self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+ def carrier_sensed(self):
+ """
+ Return True if we detect carrier.
+ """
+ return False # FIXME
+
+
+class _queue_watcher_thread(_threading.Thread):
+ def __init__(self, rcvd_pktq, callback):
+ _threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.rcvd_pktq = rcvd_pktq
+ self.callback = callback
+ self.keep_running = True
+ self.start()
+
+ #def stop(self):
+ # self.keep_running = False
+
+ def run(self):
+ while self.keep_running:
+ msg = self.rcvd_pktq.delete_head()
+ ok, payload = packet_utils.unmake_packet(msg.to_string())
+ if self.callback:
+ self.callback(ok, payload)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/nbfm_rx.py b/gnuradio-core/src/python/gnuradio/blksimpl/nbfm_rx.py
new file mode 100644
index 0000000000..39059ec9ca
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/nbfm_rx.py
@@ -0,0 +1,87 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+from gnuradio import gr, optfir
+from gnuradio.blksimpl.fm_emph import fm_deemph
+from gnuradio.blksimpl.standard_squelch import standard_squelch
+
+class nbfm_rx(gr.hier_block):
+ def __init__(self, fg, audio_rate, quad_rate, tau=75e-6, max_dev=5e3):
+ """
+ Narrow Band FM Receiver.
+
+ Takes a single complex baseband input stream and produces a single
+ float output stream of audio sample in the range [-1, +1].
+
+ @param fg: flow graph
+ @param audio_rate: sample rate of audio stream, >= 16k
+ @type audio_rate: integer
+ @param quad_rate: sample rate of output stream
+ @type quad_rate: integer
+ @param tau: preemphasis time constant (default 75e-6)
+ @type tau: float
+ @param max_dev: maximum deviation in Hz (default 5e3)
+ @type max_dev: float
+
+ quad_rate must be an integer multiple of audio_rate.
+
+ Exported sub-blocks (attributes):
+ squelch
+ quad_demod
+ deemph
+ audio_filter
+ """
+
+ # FIXME audio_rate and quad_rate ought to be exact rationals
+ audio_rate = int(audio_rate)
+ quad_rate = int(quad_rate)
+
+ if quad_rate % audio_rate != 0:
+ raise ValueError, "quad_rate is not an integer multiple of audio_rate"
+
+ squelch_threshold = 20 # dB
+ #self.squelch = gr.simple_squelch_cc(squelch_threshold, 0.001)
+
+ # FM Demodulator input: complex; output: float
+ k = quad_rate/(2*math.pi*max_dev)
+ self.quad_demod = gr.quadrature_demod_cf(k)
+
+ # FM Deemphasis IIR filter
+ self.deemph = fm_deemph (fg, quad_rate, tau=tau)
+
+ # compute FIR taps for audio filter
+ audio_decim = quad_rate // audio_rate
+ audio_taps = gr.firdes.low_pass (1.0, # gain
+ quad_rate, # sampling rate
+ 4.5e3, # Audio LPF cutoff
+ 2.5e3, # Transition band
+ gr.firdes.WIN_HAMMING) # filter type
+
+ print "len(audio_taps) =", len(audio_taps)
+
+ # Decimating audio filter
+ # input: float; output: float; taps: float
+ self.audio_filter = gr.fir_filter_fff(audio_decim, audio_taps)
+
+ fg.connect(self.quad_demod, self.deemph, self.audio_filter)
+
+ gr.hier_block.__init__(self, fg, self.quad_demod, self.audio_filter)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/nbfm_tx.py b/gnuradio-core/src/python/gnuradio/blksimpl/nbfm_tx.py
new file mode 100644
index 0000000000..2f636b67fa
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/nbfm_tx.py
@@ -0,0 +1,95 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+from gnuradio import gr, optfir
+from gnuradio.blksimpl.fm_emph import fm_preemph
+
+#from gnuradio import ctcss
+
+class nbfm_tx(gr.hier_block):
+ def __init__(self, fg, audio_rate, quad_rate, tau=75e-6, max_dev=5e3):
+ """
+ Narrow Band FM Transmitter.
+
+ Takes a single float input stream of audio samples in the range [-1,+1]
+ and produces a single FM modulated complex baseband output.
+
+ @param fg: flow graph
+ @param audio_rate: sample rate of audio stream, >= 16k
+ @type audio_rate: integer
+ @param quad_rate: sample rate of output stream
+ @type quad_rate: integer
+ @param tau: preemphasis time constant (default 75e-6)
+ @type tau: float
+ @param max_dev: maximum deviation in Hz (default 5e3)
+ @type max_dev: float
+
+ quad_rate must be an integer multiple of audio_rate.
+ """
+
+ # FIXME audio_rate and quad_rate ought to be exact rationals
+ audio_rate = int(audio_rate)
+ quad_rate = int(quad_rate)
+
+ if quad_rate % audio_rate != 0:
+ raise ValueError, "quad_rate is not an integer multiple of audio_rate"
+
+
+ do_interp = audio_rate != quad_rate
+
+ if do_interp:
+ interp_factor = quad_rate / audio_rate
+ interp_taps = optfir.low_pass (interp_factor, # gain
+ quad_rate, # Fs
+ 4500, # passband cutoff
+ 7000, # stopband cutoff
+ 0.1, # passband ripple dB
+ 40) # stopband atten dB
+
+ #print "len(interp_taps) =", len(interp_taps)
+ self.interpolator = gr.interp_fir_filter_fff (interp_factor, interp_taps)
+
+ self.preemph = fm_preemph (fg, quad_rate, tau=tau)
+
+ k = 2 * math.pi * max_dev / quad_rate
+ self.modulator = gr.frequency_modulator_fc (k)
+
+ if do_interp:
+ fg.connect (self.interpolator, self.preemph, self.modulator)
+ gr.hier_block.__init__(self, fg, self.interpolator, self.modulator)
+ else:
+ fg.connect(self.preemph, self.modulator)
+ gr.hier_block.__init__(self, fg, self.preemph, self.modulator)
+
+
+#class ctcss_gen_f(gr.sig_source_f):
+# def __init__(self, sample_rate, tone_freq):
+# gr.sig_source_f.__init__(self, sample_rate, gr.SIN_WAVE, tone_freq, 0.1, 0.0)
+#
+# def set_tone (self, tone):
+# gr.sig_source_f.set_frequency(self,tone)
+
+class ctcss_gen_f(gr.hier_block):
+ def __init__(self, fg, sample_rate, tone_freq):
+ self.plgen = gr.sig_source_f(sample_rate, gr.GR_SIN_WAVE, tone_freq, 0.1, 0.0)
+
+ gr.hier_block.__init__(self, fg, self.plgen, self.plgen)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py b/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py
new file mode 100644
index 0000000000..3ebb7229c6
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py
@@ -0,0 +1,156 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from math import pi
+import Numeric
+
+from gnuradio import gr, packet_utils
+import gnuradio.gr.gr_threading as _threading
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class mod_pkts(gr.hier_block):
+ """
+ Wrap an arbitrary digital modulator in our packet handling framework.
+
+ Send packets by calling send_pkt
+ """
+ def __init__(self, fg, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True):
+ """
+ Hierarchical block for sending packets
+
+ Packets to be sent are enqueued by calling send_pkt.
+ The output is the complex modulated signal at baseband.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param modulator: instance of modulator class (gr_block or hier_block)
+ @type modulator: complex baseband out
+ @param access_code: AKA sync vector
+ @type access_code: string of 1's and 0's between 1 and 64 long
+ @param msgq_limit: maximum number of messages in message queue
+ @type msgq_limit: int
+ @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
+
+ See gmsk_mod for remaining parameters
+ """
+ self._modulator = modulator
+ self._pad_for_usrp = pad_for_usrp
+
+ if access_code is None:
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+
+ # accepts messages from the outside world
+ self._pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
+ fg.connect(self._pkt_input, self._modulator)
+ gr.hier_block.__init__(self, fg, None, self._modulator)
+
+ def send_pkt(self, payload='', eof=False):
+ """
+ Send the payload.
+
+ @param payload: data to send
+ @type payload: string
+ """
+ if eof:
+ msg = gr.message(1) # tell self._pkt_input we're not sending any more packets
+ else:
+ # print "original_payload =", string_to_hex_list(payload)
+ pkt = packet_utils.make_packet(payload,
+ self._modulator.samples_per_baud(),
+ self._modulator.bits_per_baud(),
+ self._access_code,
+ self._pad_for_usrp)
+ #print "pkt =", string_to_hex_list(pkt)
+ msg = gr.message_from_string(pkt)
+ self._pkt_input.msgq().insert_tail(msg)
+
+
+
+class demod_pkts(gr.hier_block):
+ """
+ Wrap an arbitrary digital demodulator in our packet handling framework.
+
+ The input is complex baseband. When packets are demodulated, they are passed to the
+ app via the callback.
+ """
+
+ def __init__(self, fg, demodulator, access_code=None, callback=None, threshold=-1):
+ """
+ Hierarchical block for demodulating and deframing packets.
+
+ The input is the complex modulated signal at baseband.
+ Demodulated packets are sent to the handler.
+
+ @param fg: flow graph
+ @type fg: flow graph
+ @param demodulator: instance of demodulator class (gr_block or hier_block)
+ @type demodulator: complex baseband in
+ @param access_code: AKA sync vector
+ @type access_code: string of 1's and 0's
+ @param callback: function of two args: ok, payload
+ @type callback: ok: bool; payload: string
+ @param threshold: detect access_code with up to threshold bits wrong (-1 -> use default)
+ @type threshold: int
+ """
+
+ self._demodulator = demodulator
+ if access_code is None:
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+
+ if threshold == -1:
+ threshold = 12 # FIXME raise exception
+
+ self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY
+ self.correlator = gr.correlate_access_code_bb(access_code, threshold)
+
+ self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
+ fg.connect(self._demodulator, self.correlator, self.framer_sink)
+
+ gr.hier_block.__init__(self, fg, self._demodulator, None)
+ self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+
+class _queue_watcher_thread(_threading.Thread):
+ def __init__(self, rcvd_pktq, callback):
+ _threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.rcvd_pktq = rcvd_pktq
+ self.callback = callback
+ self.keep_running = True
+ self.start()
+
+
+ def run(self):
+ while self.keep_running:
+ msg = self.rcvd_pktq.delete_head()
+ ok, payload = packet_utils.unmake_packet(msg.to_string())
+ if self.callback:
+ self.callback(ok, payload)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/rational_resampler.py b/gnuradio-core/src/python/gnuradio/blksimpl/rational_resampler.py
new file mode 100644
index 0000000000..8b928b102f
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/rational_resampler.py
@@ -0,0 +1,137 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr, gru
+
+_plot = None
+
+def design_filter(interpolation, decimation, fractional_bw):
+ """
+ Given the interpolation rate, decimation rate and a fractional bandwidth,
+ design a set of taps.
+
+ @param interpolation: interpolation factor
+ @type interpolation: integer > 0
+ @param decimation: decimation factor
+ @type decimation: integer > 0
+ @param fractional_bw: fractional bandwidth in (0, 0.5) 0.4 works well.
+ @type fractional_bw: float
+ @returns: sequence of numbers
+ """
+
+ global _plot
+
+ if fractional_bw >= 0.5 or fractional_bw <= 0:
+ raise ValueError, "Invalid fractional_bandwidth, must be in (0, 0.5)"
+
+ beta = 5.0
+ trans_width = 0.5 - fractional_bw
+ mid_transition_band = 0.5 - trans_width/2
+
+ taps = gr.firdes.low_pass(interpolation, # gain
+ 1, # Fs
+ mid_transition_band/interpolation, # trans mid point
+ trans_width/interpolation, # transition width
+ gr.firdes.WIN_KAISER,
+ beta # beta
+ )
+ # print "len(resampler_taps) =", len(taps)
+ # _plot = gru.gnuplot_freqz(gru.freqz(taps, 1), 1)
+
+ return taps
+
+
+
+class _rational_resampler_base(gr.hier_block):
+ """
+ base class for all rational resampler variants.
+ """
+ def __init__(self, resampler_base, fg,
+ interpolation, decimation, taps=None, fractional_bw=None):
+ """
+ Rational resampling polyphase FIR filter.
+
+ Either taps or fractional_bw may be specified, but not both.
+ If neither is specified, a reasonable default, 0.4, is used as
+ the fractional_bw.
+
+ @param fg: flow graph
+ @param interpolation: interpolation factor
+ @type interpolation: integer > 0
+ @param decimation: decimation factor
+ @type decimation: integer > 0
+ @param taps: optional filter coefficients
+ @type taps: sequence
+ @param fractional_bw: fractional bandwidth in (0, 0.5), measured at final freq (use 0.4)
+ @type fractional_bw: float
+ """
+
+ if not isinstance(interpolation, int) or interpolation < 1:
+ raise ValueError, "interpolation must be an integer >= 1"
+
+ if not isinstance(decimation, int) or decimation < 1:
+ raise ValueError, "decimation must be an integer >= 1"
+
+ if taps is None and fractional_bw is None:
+ fractional_bw = 0.4
+
+ d = gru.gcd(interpolation, decimation)
+ interpolation = interpolation // d
+ decimation = decimation // d
+
+ if taps is None:
+ taps = design_filter(interpolation, decimation, fractional_bw)
+
+ resampler = resampler_base(interpolation, decimation, taps)
+ gr.hier_block.__init__(self, fg, resampler, resampler)
+
+
+
+class rational_resampler_fff(_rational_resampler_base):
+ def __init__(self, fg, interpolation, decimation, taps=None, fractional_bw=None):
+ """
+ Rational resampling polyphase FIR filter with
+ float input, float output and float taps.
+ """
+ _rational_resampler_base.__init__(self, gr.rational_resampler_base_fff, fg,
+ interpolation, decimation,
+ taps, fractional_bw)
+
+class rational_resampler_ccf(_rational_resampler_base):
+ def __init__(self, fg, interpolation, decimation, taps=None, fractional_bw=None):
+ """
+ Rational resampling polyphase FIR filter with
+ complex input, complex output and float taps.
+ """
+ _rational_resampler_base.__init__(self, gr.rational_resampler_base_ccf, fg,
+ interpolation, decimation,
+ taps, fractional_bw)
+
+class rational_resampler_ccc(_rational_resampler_base):
+ def __init__(self, fg, interpolation, decimation, taps=None, fractional_bw=None):
+ """
+ Rational resampling polyphase FIR filter with
+ complex input, complex output and complex taps.
+ """
+ _rational_resampler_base.__init__(self, gr.rational_resampler_base_ccc, fg,
+ interpolation, decimation,
+ taps, fractional_bw)
+
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/standard_squelch.py b/gnuradio-core/src/python/gnuradio/blksimpl/standard_squelch.py
new file mode 100644
index 0000000000..2c80dd5af7
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/standard_squelch.py
@@ -0,0 +1,73 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+from gnuradio import gr, optfir
+
+class standard_squelch(gr.hier_block):
+ def __init__(self, fg, audio_rate):
+
+ self.input_node = gr.add_const_ff(0) # FIXME kludge
+
+ self.low_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.9524,-0.9615))
+ self.low_square = gr.multiply_ff()
+ self.low_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate)) # 100ms time constant
+
+ self.hi_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.3597,-0.9615))
+ self.hi_square = gr.multiply_ff()
+ self.hi_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))
+
+ self.sub = gr.sub_ff();
+ self.add = gr.add_ff();
+ self.gate = gr.threshold_ff(0.3,0.43,0)
+ self.squelch_lpf = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))
+
+ self.div = gr.divide_ff()
+ self.squelch_mult = gr.multiply_ff()
+
+ fg.connect (self.input_node, (self.squelch_mult, 0))
+
+ fg.connect (self.input_node,self.low_iir)
+ fg.connect (self.low_iir,(self.low_square,0))
+ fg.connect (self.low_iir,(self.low_square,1))
+ fg.connect (self.low_square,self.low_smooth,(self.sub,0))
+ fg.connect (self.low_smooth, (self.add,0))
+
+ fg.connect (self.input_node,self.hi_iir)
+ fg.connect (self.hi_iir,(self.hi_square,0))
+ fg.connect (self.hi_iir,(self.hi_square,1))
+ fg.connect (self.hi_square,self.hi_smooth,(self.sub,1))
+ fg.connect (self.hi_smooth, (self.add,1))
+
+ fg.connect (self.sub, (self.div, 0))
+ fg.connect (self.add, (self.div, 1))
+ fg.connect (self.div, self.gate, self.squelch_lpf, (self.squelch_mult,1))
+
+ gr.hier_block.__init__(self, fg, self.input_node, self.squelch_mult)
+
+ def set_threshold(self, threshold):
+ self.gate.set_hi(threshold)
+
+ def threshold(self):
+ return self.gate.hi()
+
+ def squelch_range(self):
+ return (0.0, 1.0, 1.0/100)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv.py b/gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv.py
new file mode 100644
index 0000000000..55dbbaa0c4
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv.py
@@ -0,0 +1,72 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr
+from gnuradio.blksimpl.fm_emph import fm_deemph
+import math
+
+class wfm_rcv(gr.hier_block):
+ def __init__ (self, fg, quad_rate, audio_decimation):
+ """
+ Hierarchical block for demodulating a broadcast FM signal.
+
+ The input is the downconverted complex baseband signal (gr_complex).
+ The output is the demodulated audio (float).
+
+ @param fg: flow graph.
+ @type fg: flow graph
+ @param quad_rate: input sample rate of complex baseband input.
+ @type quad_rate: float
+ @param audio_decimation: how much to decimate quad_rate to get to audio.
+ @type audio_decimation: integer
+ """
+ volume = 20.
+
+ max_dev = 75e3
+ fm_demod_gain = quad_rate/(2*math.pi*max_dev)
+ audio_rate = quad_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
+ self.fm_demod = gr.quadrature_demod_cf (fm_demod_gain)
+
+ # input: float; output: float
+ self.deemph = fm_deemph (fg, audio_rate)
+
+ # compute FIR filter taps for audio filter
+ width_of_transition_band = audio_rate / 32
+ audio_coeffs = gr.firdes.low_pass (1.0, # gain
+ quad_rate, # sampling rate
+ audio_rate/2 - width_of_transition_band,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+ # input: float; output: float
+ self.audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)
+
+ fg.connect (self.fm_demod, self.audio_filter, self.deemph)
+
+ gr.hier_block.__init__(self,
+ fg,
+ self.fm_demod, # head of the pipeline
+ self.deemph) # tail of the pipeline
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv_pll.py b/gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv_pll.py
new file mode 100644
index 0000000000..d116090e0a
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/wfm_rcv_pll.py
@@ -0,0 +1,206 @@
+#
+# Copyright 2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr
+from gnuradio.blksimpl.fm_emph import fm_deemph
+import math
+
+class wfm_rcv_pll(gr.hier_block):
+ def __init__ (self, fg, demod_rate, audio_decimation):
+ """
+ Hierarchical block for demodulating a broadcast FM signal.
+
+ The input is the downconverted complex baseband signal (gr_complex).
+ The output is two streams of the demodulated audio (float) 0=Left, 1=Right.
+
+ @param fg: flow graph.
+ @type fg: flow graph
+ @param demod_rate: input sample rate of complex baseband input.
+ @type demod_rate: float
+ @param audio_decimation: how much to decimate demod_rate to get to audio.
+ @type audio_decimation: integer
+ """
+
+ bandwidth = 200e3
+ 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
+ alpha = 0.25*bandwidth * math.pi / demod_rate
+ beta = alpha * alpha / 4.0
+ max_freq = 2.0*math.pi*100e3/demod_rate
+
+ self.fm_demod = gr.pll_freqdet_cf (alpha,beta,max_freq,-max_freq)
+
+ # input: float; output: float
+ self.deemph_Left = fm_deemph (fg, audio_rate)
+ self.deemph_Right = fm_deemph (fg, audio_rate)
+
+ # compute FIR filter taps for audio filter
+ width_of_transition_band = audio_rate / 32
+ audio_coeffs = gr.firdes.low_pass (1.0 , # gain
+ demod_rate, # sampling rate
+ 15000 ,
+ width_of_transition_band,
+ gr.firdes.WIN_HAMMING)
+ # input: float; output: float
+ self.audio_filter = gr.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 = gr.firdes.complex_band_pass(10.0,
+ demod_rate,
+ -19020,
+ -18980,
+ width_of_transition_band,
+ gr.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 = gr.firdes.complex_band_pass(20.0,
+ demod_rate,
+ 38000-15000/2,
+ 38000+15000/2,
+ width_of_transition_band,
+ gr.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 = gr.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs)
+
+ # carrier is twice the picked off carrier so arrange to do a commplex multiply
+
+ self.stereo_carrier_generator = gr.multiply_cc();
+
+ # Pick off the rds signal
+
+ stereo_rds_filter_coeffs = gr.firdes.complex_band_pass(30.0,
+ demod_rate,
+ 57000 - 1500,
+ 57000 + 1500,
+ width_of_transition_band,
+ gr.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 = gr.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs)
+ self.rds_signal_filter = gr.fir_filter_fcc(audio_decimation, stereo_rds_filter_coeffs)
+
+
+
+
+
+
+ self.rds_carrier_generator = gr.multiply_cc();
+ self.rds_signal_generator = gr.multiply_cc();
+ self_rds_signal_processor = gr.null_sink(gr.sizeof_gr_complex);
+
+
+
+ alpha = 5 * 0.25 * math.pi / (audio_rate)
+ beta = alpha * alpha / 4.0
+ max_freq = -2.0*math.pi*18990/audio_rate;
+ min_freq = -2.0*math.pi*19010/audio_rate;
+
+ self.stereo_carrier_pll_recovery = gr.pll_carriertracking_cc(alpha,beta,max_freq,min_freq);
+ self.stereo_carrier_pll_recovery.squelch_enable(False);
+
+
+ # set up mixer (multiplier) to get the L-R signal at baseband
+
+ self.stereo_basebander = gr.multiply_cc();
+
+ # pick off the real component of the basebanded L-R signal. The imaginary SHOULD be zero
+
+ self.LmR_real = gr.complex_to_real();
+ self.Make_Left = gr.add_ff();
+ self.Make_Right = gr.sub_ff();
+
+ self.stereo_dsbsc_filter = gr.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
+ fg.connect (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
+ fg.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)
+ fg.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
+ fg.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
+ fg.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
+ fg.connect (self.LmR_real,(self.Make_Right,1))
+
+ # Make rds carrier by taking the squared pilot tone and multiplying by pilot tone
+ fg.connect (self.stereo_basebander,(self.rds_carrier_generator,0))
+ fg.connect (self.stereo_carrier_pll_recovery,(self.rds_carrier_generator,1))
+ # take signal, filter off rds, send into mixer 0 channel
+ fg.connect (self.fm_demod,self.rds_signal_filter,(self.rds_signal_generator,0))
+ # take rds_carrier_generator output and send into mixer 1 channel
+ fg.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
+ fg.connect (self.rds_signal_generator,self_rds_signal_processor)
+
+
+ if 1:
+ # pick off the audio, L+R that is what we used to have and send it to the summer
+ fg.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
+ fg.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
+
+
+ # kludge the signals into a stereo channel
+ kludge = gr.kludge_copy(gr.sizeof_float)
+ fg.connect(self.Make_Left , self.deemph_Left, (kludge, 0))
+ fg.connect(self.Make_Right, self.deemph_Right, (kludge, 1))
+
+ #send it to the audio system
+ gr.hier_block.__init__(self,
+ fg,
+ self.fm_demod, # head of the pipeline
+ kludge) # tail of the pipeline
+ else:
+ fg.connect (self.fm_demod, self.audio_filter)
+ gr.hier_block.__init__(self,
+ fg,
+ self.fm_demod, # head of the pipeline
+ self.audio_filter) # tail of the pipeline
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/wfm_tx.py b/gnuradio-core/src/python/gnuradio/blksimpl/wfm_tx.py
new file mode 100644
index 0000000000..505455571e
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/wfm_tx.py
@@ -0,0 +1,79 @@
+#
+# Copyright 2005 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import math
+from gnuradio import gr, optfir
+from gnuradio.blksimpl.fm_emph import fm_preemph
+
+class wfm_tx(gr.hier_block):
+ def __init__(self, fg, audio_rate, quad_rate, tau=75e-6, max_dev=75e3):
+ """
+ Wide Band FM Transmitter.
+
+ Takes a single float input stream of audio samples in the range [-1,+1]
+ and produces a single FM modulated complex baseband output.
+
+ @param fg: flow graph
+ @param audio_rate: sample rate of audio stream, >= 16k
+ @type audio_rate: integer
+ @param quad_rate: sample rate of output stream
+ @type quad_rate: integer
+ @param tau: preemphasis time constant (default 75e-6)
+ @type tau: float
+ @param max_dev: maximum deviation in Hz (default 75e3)
+ @type max_dev: float
+
+ quad_rate must be an integer multiple of audio_rate.
+ """
+
+ # FIXME audio_rate and quad_rate ought to be exact rationals
+ audio_rate = int(audio_rate)
+ quad_rate = int(quad_rate)
+
+ if quad_rate % audio_rate != 0:
+ raise ValueError, "quad_rate is not an integer multiple of audio_rate"
+
+
+ do_interp = audio_rate != quad_rate
+
+ if do_interp:
+ interp_factor = quad_rate / audio_rate
+ interp_taps = optfir.low_pass (interp_factor, # gain
+ quad_rate, # Fs
+ 16000, # passband cutoff
+ 18000, # stopband cutoff
+ 0.1, # passband ripple dB
+ 40) # stopband atten dB
+
+ print "len(interp_taps) =", len(interp_taps)
+ self.interpolator = gr.interp_fir_filter_fff (interp_factor, interp_taps)
+
+ self.preemph = fm_preemph (fg, quad_rate, tau=tau)
+
+ k = 2 * math.pi * max_dev / quad_rate
+ self.modulator = gr.frequency_modulator_fc (k)
+
+ if do_interp:
+ fg.connect (self.interpolator, self.preemph, self.modulator)
+ gr.hier_block.__init__(self, fg, self.interpolator, self.modulator)
+ else:
+ fg.connect(self.preemph, self.modulator)
+ gr.hier_block.__init__(self, fg, self.preemph, self.modulator)