Stereo FM transmitter using gnuradio

From Opendigitalradio
(Difference between revisions)
Jump to: navigation, search
(GRC Schema)

Revision as of 19:15, 2 January 2010

Stereo FM transmitter using gnuradio.

Tools needed:

  • gnuradio 3.2
  • grc (gnuradio companion)
  • mpg123
  • USRP


In this example we will show how to make a Stereo FM software transmitter. Input is from an mp3 stream for an Internet radio. Look at GRC schema or use directly python code below.

Input file is a unix FIFO file that means that we need to feed it externally from the shell using these commands:

Creation of the FIFO file (once):

mkfifo stream_32k.fifo

Decoding of an mp3 Internet radio station stream, conversion and output of raw linear samples to the FIFO:

mpg123 -r32000 -s  http://maxxima.mine.nu:8000 >stream_32k.fifo

"-r32000" perform sample rate conversion to 32kHz.


GRC Schema

FM transmitter stereo.png

Python code

#!/usr/bin/env python
##################################################
# Gnuradio Python Flow Graph
# Title: FM Stereo Transmitter
# Author: Mathias Coinchon
# Generated: Sat Jan  2 19:06:07 2010
##################################################

from gnuradio import blks2
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.gr import firdes
from gnuradio.wxgui import fftsink2
from gnuradio.wxgui import forms
from grc_gnuradio import usrp as grc_usrp
from grc_gnuradio import wxgui as grc_wxgui
from optparse import OptionParser
import wx

class FM_stereo_tx(grc_wxgui.top_block_gui):

	def __init__(self):
		grc_wxgui.top_block_gui.__init__(self, title="FM Stereo Transmitter")

		##################################################
		# Variables
		##################################################
		self.st_gain = st_gain = 10
		self.samp_rate = samp_rate = 32000
		self.pilot_gain = pilot_gain = 80e-3
		self.mpx_rate = mpx_rate = 160000
		self.Mono_gain = Mono_gain = 0.3
		self.FM_freq = FM_freq = 107900000

		##################################################
		# Controls
		##################################################
		_st_gain_sizer = wx.BoxSizer(wx.VERTICAL)
		self._st_gain_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_st_gain_sizer,
			value=self.st_gain,
			callback=self.set_st_gain,
			label="Stereo gain",
			converter=forms.float_converter(),
			proportion=0,
		)
		self._st_gain_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_st_gain_sizer,
			value=self.st_gain,
			callback=self.set_st_gain,
			minimum=0,
			maximum=100,
			num_steps=100,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_st_gain_sizer)
		_pilot_gain_sizer = wx.BoxSizer(wx.VERTICAL)
		self._pilot_gain_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_pilot_gain_sizer,
			value=self.pilot_gain,
			callback=self.set_pilot_gain,
			label='pilot_gain',
			converter=forms.float_converter(),
			proportion=0,
		)
		self._pilot_gain_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_pilot_gain_sizer,
			value=self.pilot_gain,
			callback=self.set_pilot_gain,
			minimum=0,
			maximum=1,
			num_steps=100,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_pilot_gain_sizer)
		_Mono_gain_sizer = wx.BoxSizer(wx.VERTICAL)
		self._Mono_gain_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_Mono_gain_sizer,
			value=self.Mono_gain,
			callback=self.set_Mono_gain,
			label="Mono signal gain",
			converter=forms.float_converter(),
			proportion=0,
		)
		self._Mono_gain_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_Mono_gain_sizer,
			value=self.Mono_gain,
			callback=self.set_Mono_gain,
			minimum=0,
			maximum=1,
			num_steps=100,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_Mono_gain_sizer)
		_FM_freq_sizer = wx.BoxSizer(wx.VERTICAL)
		self._FM_freq_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_FM_freq_sizer,
			value=self.FM_freq,
			callback=self.set_FM_freq,
			label="FM Frequency",
			converter=forms.float_converter(),
			proportion=0,
		)
		self._FM_freq_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_FM_freq_sizer,
			value=self.FM_freq,
			callback=self.set_FM_freq,
			minimum=87500000,
			maximum=108000000,
			num_steps=205,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_FM_freq_sizer)

		##################################################
		# Blocks
		##################################################
		self.Audio_A_resampler = blks2.rational_resampler_fff(
			interpolation=5,
			decimation=1,
			taps=None,
			fractional_bw=None,
		)
		self.Audio_B_resampler = blks2.rational_resampler_fff(
			interpolation=5,
			decimation=1,
			taps=None,
			fractional_bw=None,
		)
		self.MPX_upsampler = blks2.rational_resampler_fff(
			interpolation=4,
			decimation=1,
			taps=None,
			fractional_bw=None,
		)
		self.Pilot = gr.sig_source_f(mpx_rate, gr.GR_SIN_WAVE, 19000, pilot_gain, 0)
		self.band_pass_filter_0 = gr.fir_filter_fff(1, firdes.band_pass(
			st_gain, mpx_rate, 23e3, 53e3, 2e3, firdes.WIN_HAMMING, 6.76))
		self.blks2_fm_preemph_0 = blks2.fm_preemph(fs=mpx_rate, tau=50e-6)
		self.gr_add_xx_0 = gr.add_vff(1)
		self.gr_add_xx_1 = gr.add_vff(1)
		self.gr_file_source_0 = gr.file_source(gr.sizeof_short*2, "/home/mc/FM_demo/stream_32k.fifo", True)
		self.gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(0.98)
		self.gr_multiply_const_vxx_0 = gr.multiply_const_vcc((32768, ))
		self.gr_multiply_const_vxx_1 = gr.multiply_const_vff((0.00003, ))
		self.gr_multiply_const_vxx_3 = gr.multiply_const_vff((0.00003, ))
		self.gr_multiply_xx_1 = gr.multiply_vff(1)
		self.gr_short_to_float_0 = gr.short_to_float()
		self.gr_short_to_float_1 = gr.short_to_float()
		self.gr_sub_xx_0 = gr.sub_ff(1)
		self.gr_vector_to_streams_0 = gr.vector_to_streams(gr.sizeof_short*1, 2)
		self.low_pass_filter_0 = gr.fir_filter_fff(1, firdes.low_pass(
			Mono_gain, mpx_rate, 15e3, 2e3, firdes.WIN_HAMMING, 6.76))
		self.st_38k_carrier = gr.sig_source_f(mpx_rate, gr.GR_SIN_WAVE, 38000, 30e-3, 0)
		self.usrp_simple_sink_x_0 = grc_usrp.simple_sink_c(which=0, side="B")
		self.usrp_simple_sink_x_0.set_interp_rate(200)
		self.usrp_simple_sink_x_0.set_frequency(-FM_freq, verbose=True)
		self.usrp_simple_sink_x_0.set_gain(0)
		self.usrp_simple_sink_x_0.set_enable(True)
		self.wxgui_fftsink2_0 = fftsink2.fft_sink_f(
			self.GetWin(),
			baseband_freq=0,
			y_per_div=10,
			y_divs=10,
			ref_level=50,
			sample_rate=mpx_rate,
			fft_size=1024,
			fft_rate=30,
			average=False,
			avg_alpha=None,
			title="Baseband spectrum",
			peak_hold=False,
		)
		self.Add(self.wxgui_fftsink2_0.win)

		##################################################
		# Connections
		##################################################
		self.connect((self.Audio_A_resampler, 0), (self.gr_add_xx_1, 0))
		self.connect((self.Audio_B_resampler, 0), (self.gr_add_xx_1, 1))
		self.connect((self.Audio_A_resampler, 0), (self.gr_sub_xx_0, 0))
		self.connect((self.gr_multiply_xx_1, 0), (self.band_pass_filter_0, 0))
		self.connect((self.st_38k_carrier, 0), (self.gr_multiply_xx_1, 1))
		self.connect((self.low_pass_filter_0, 0), (self.gr_add_xx_0, 0))
		self.connect((self.gr_add_xx_1, 0), (self.low_pass_filter_0, 0))
		self.connect((self.gr_frequency_modulator_fc_0, 0), (self.gr_multiply_const_vxx_0, 0))
		self.connect((self.MPX_upsampler, 0), (self.gr_frequency_modulator_fc_0, 0))
		self.connect((self.blks2_fm_preemph_0, 0), (self.MPX_upsampler, 0))
		self.connect((self.gr_add_xx_0, 0), (self.blks2_fm_preemph_0, 0))
		self.connect((self.Pilot, 0), (self.gr_add_xx_0, 2))
		self.connect((self.band_pass_filter_0, 0), (self.gr_add_xx_0, 1))
		self.connect((self.gr_add_xx_0, 0), (self.wxgui_fftsink2_0, 0))
		self.connect((self.gr_sub_xx_0, 0), (self.gr_multiply_xx_1, 0))
		self.connect((self.Audio_B_resampler, 0), (self.gr_sub_xx_0, 1))
		self.connect((self.gr_multiply_const_vxx_0, 0), (self.usrp_simple_sink_x_0, 0))
		self.connect((self.gr_file_source_0, 0), (self.gr_vector_to_streams_0, 0))
		self.connect((self.gr_short_to_float_1, 0), (self.gr_multiply_const_vxx_1, 0))
		self.connect((self.gr_multiply_const_vxx_1, 0), (self.Audio_A_resampler, 0))
		self.connect((self.gr_short_to_float_0, 0), (self.gr_multiply_const_vxx_3, 0))
		self.connect((self.gr_multiply_const_vxx_3, 0), (self.Audio_B_resampler, 0))
		self.connect((self.gr_vector_to_streams_0, 1), (self.gr_short_to_float_1, 0))
		self.connect((self.gr_vector_to_streams_0, 0), (self.gr_short_to_float_0, 0))

	def set_st_gain(self, st_gain):
		self.st_gain = st_gain
		self.band_pass_filter_0.set_taps(firdes.band_pass(self.st_gain, self.mpx_rate, 23e3, 53e3, 2e3, firdes.WIN_HAMMING, 6.76))
		self._st_gain_slider.set_value(self.st_gain)
		self._st_gain_text_box.set_value(self.st_gain)

	def set_samp_rate(self, samp_rate):
		self.samp_rate = samp_rate

	def set_pilot_gain(self, pilot_gain):
		self.pilot_gain = pilot_gain
		self.Pilot.set_amplitude(self.pilot_gain)
		self._pilot_gain_slider.set_value(self.pilot_gain)
		self._pilot_gain_text_box.set_value(self.pilot_gain)

	def set_mpx_rate(self, mpx_rate):
		self.mpx_rate = mpx_rate
		self.band_pass_filter_0.set_taps(firdes.band_pass(self.st_gain, self.mpx_rate, 23e3, 53e3, 2e3, firdes.WIN_HAMMING, 6.76))
		self.low_pass_filter_0.set_taps(firdes.low_pass(self.Mono_gain, self.mpx_rate, 15e3, 2e3, firdes.WIN_HAMMING, 6.76))
		self.Pilot.set_sampling_freq(self.mpx_rate)
		self.st_38k_carrier.set_sampling_freq(self.mpx_rate)
		self.wxgui_fftsink2_0.set_sample_rate(self.mpx_rate)

	def set_Mono_gain(self, Mono_gain):
		self.Mono_gain = Mono_gain
		self.low_pass_filter_0.set_taps(firdes.low_pass(self.Mono_gain, self.mpx_rate, 15e3, 2e3, firdes.WIN_HAMMING, 6.76))
		self._Mono_gain_slider.set_value(self.Mono_gain)
		self._Mono_gain_text_box.set_value(self.Mono_gain)

	def set_FM_freq(self, FM_freq):
		self.FM_freq = FM_freq
		self.usrp_simple_sink_x_0.set_frequency(-self.FM_freq)
		self._FM_freq_slider.set_value(self.FM_freq)
		self._FM_freq_text_box.set_value(self.FM_freq)

if __name__ == '__main__':
	parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
	(options, args) = parser.parse_args()
	tb = FM_stereo_tx()
	tb.Run(True)
Personal tools