[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Discuss-gnuradio] Modified wfm_rcv_pll, usrp_wfm_rcv_pll blocks, and gr
From: |
Robert McGwier |
Subject: |
[Discuss-gnuradio] Modified wfm_rcv_pll, usrp_wfm_rcv_pll blocks, and gr_filter blocks |
Date: |
Mon, 06 Feb 2006 22:35:02 -0500 |
User-agent: |
Thunderbird 1.5 (Windows/20051201) |
Today Eric showed me how to use gr_kludge_copy to finish the
modifications to wfm_rcv_pll and we now have stereo receive on FM.
These modification are a testimonial to the GnuRadio code and the ease
with which it can be used to glue things together. I wrote the lines
down, Eric put in gr.kludge and it just worked the first time. This
Matt Ettus caught a stupid bug in the pll receiver. It is a second
order PLL. Effectively the phase gain was too small by 1/3 and it was
hugely overdamped.
We can now do a complex FIR band pass filter
gr.firdes.complex_band_pass designs the bandpass. Then you can use
gr_fir_filter_?cc to filter the input signal with the filter in the
usual overlap add manner
After this was done, stereo was a hop-skip-jump. Let me attempt to
describe it.
Tuner -> A/D -> USRP -> ///software in PC///
Tuner -> A/D -> FPGA
is the TV tuner and the A/D's on the USRP and the FPGA is doing
numerically controlled oscillator and half band filtering to downconvert
and downsample the signal.
///Software in PC///
Before today's code, the base FM station signal was being sent to the
sound system and it was monoaural. The PLL is doing a fine job of
demodulating the FM signal (with Matt's fix) and now it is easy to see
the stereo carrier, multiplex, and the RDS signal if they are
present. We definitely have some work to do on the de-emphasis but
that can wait. it appears to me that the de-emphasis is too strongly
tapered.
So we have this signal coming from the USRP and we run it through a PLL
detector for FM that takes the 150 kHz signal in and spits detector
audio out. This is run into the de-emphasis filter.
We ran a filter on the audio:
self.audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs)
where the wider band signal with all of the extra content had the base
audio signal filtered off. The filter was run and the (now lowpass)
signal is decimated down to a rate for sending to the sound card.
This used to be done in a statement that looked like this:
fg.connect (self.fm_demod, self.deemph, self.audio_filter)
This takes the fm demod output, does deemphasis, and then filters.
There are at least three other signals that might be in an FM broadcast.
If the broadcast is stereo, there are two more minimum. If you had a
stereo signal and you could not decode the stereo, what would you want
to send out the monoaural sink? You would lose the separation but
acceptable audio would be present if you send Left + Right down the
monoaural pipe. Then it is clear what you want transmit in any extra
channel, you need L-R or R-L.
FM carrier transmit a carrier signal at 19 kHz and double side band
suppressed carrier (DSBSC) centered at 38 kHz. If you square the FM
carrier signal at 19 kHz, you get the exact carrier needed to perfectly
baseband the DSBSC. By perfect what do I mean? DSBSC means the
analytic is real. If perfectly basebanded (the center frequency at
zero and the phase set correctly), the imaginary channel has zero in it
and all of the relevant signal is in the real part.
So, we build a complex filter for the carrier at -19000 Hz:
stereo_carrier_filter_coeffs =
gr.firdes.complex_band_pass(10.0*volume*fm_demod_gain,
demod_rate,
-19100,
-18900,
width_of_transition_band,
gr.firdes.WIN_HAMMING)
Notice that the audio transmitted by the FM is real. That means it has
negative and positive frequency content. Also recall from the previous
paragraph that we need to base band the DSBSC "perfectly", so we will
save some operations and pick off the "negative frequency" component of
the carrier. This will be explained further in a moment along with gain.
The DSBSC signal contain Left minus Right (L-R) is centered at 38 kHz
and is audio_rate wide. Lets build a filter for the DSBSC.
stereo_dsbsc_filter_coeffs =
gr.firdes.complex_band_pass(10.0*volume*fm_demod_gain,
demod_rate,
38000-audio_rate/2,
38000+audio_rate/2,
width_of_transition_band,
gr.firdes.WIN_HAMMING)
Again we have made a complex filter but this one is centered at +38000
Hz and is audio_rate wide. Both of these filters have a transition
bandwith that attenuates the nearby signals to keep them from
interfering. Both of these filters are done with 10 dB of gain. In my
reading, several articles say the carrier and DSBSC signal are added to
the main audio attenuated by 10 dB. THIS APPEARS TO BE RIGHT FROM THE
RESULTS but if someone knows better, let us know.
We need to square the carrier freq so we will use a complex multiply:
self.stereo_carrier_generator = gr.multiply_cc();
We will also need a mixer to use the carrier to baseband the DSBSC
audio. A mixer for us is a complex multiply
self.stereo_basebander = gr.multiply_cc();
Now some utilties:
self.LmR_real = gr.complex_to_real();
self.Make_Left = gr.add_ff();
self.Make_Right = gr.sub_ff();
We are going to produce a complex signal at baseband with the DSBSC
signal in it. The imaginary component in an ideal world is zero so we
will pick off the real part and this will be L-R audio.
The carrier will be filtered with the standard overlap add:
self.stereo_carrier_filter =
gr.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs)
and so will the DSBSC:
self.stereo_dsbsc_filter =
gr.fir_filter_fcc(audio_decimation, stereo_dsbsc_filter_coeffs)
Now that we have everything set up, lets explain the new stereo decoder:
fg.connect (self.fm_demod, self.deemph)
this demods the signal and sends it to the de-emphasis filter.
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.deemph,self.stereo_carrier_filter,
(self.stereo_carrier_generator,0))
# send the already filtered carrier to the otherside of the
carrier
fg.connect (self.stereo_carrier_filter,
(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.deemph,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))
if 1:
# pick off the audio, L+R that is what we used to have and
send it to the summer
fg.connect(self.deemph, 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 , (kludge, 0))
fg.connect(self.Make_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:
((( OLD MONO, LEFT OUT OF EXPLANATION))
This is not perfect yet but it does work. We need to work on the
pre-emphasis and possibly on the gains for the carrier and DSBSC filters
but the stereo separation is apparent. It appears to me that the result
L-R signal is down a few dB from where it should be. This will be
revisited until we are all happy.
Next after this is to decode the RDS signal at 57 kHz in the demphasized
audio. It has 1200 bps of data. This is usually the radio station
and/or the current song or show on the channel.
Happy FM'ing
Bob
--
AMSAT VP Engineering. Member: ARRL, AMSAT-DL, TAPR, Packrats,
NJQRP/AMQRP, QRP ARCI, QCWA, FRC. ARRL SDR Wrk Grp Chairman
Laziness is the number one inspiration for ingenuity. Guilty as charged!
- [Discuss-gnuradio] Modified wfm_rcv_pll, usrp_wfm_rcv_pll blocks, and gr_filter blocks,
Robert McGwier <=