Multiple stations FM transmitter using gnuradio
From Opendigitalradio
(Difference between revisions)
Latest revision as of 21:29, 2 January 2010
FM transmitter on many channels using gnuradio.
Tools needed:
- gnuradio 3.2
- grc (gnuradio companion)
- USRP with BasicTX daughterboard or any other card covering FM frequencies
In this example we will show how to make an FM software transmitter broadcasting simultaneously many stations on different channels. Unix FIFO are used as input (to create FIFO files, use "mkfifo" command).
Example of feeding FIFO files with mp3 radio streams.
#!/bin/sh mpg123 -r32000 -m -s http://maxxima.mine.nu:8000 >stream_32k.fifo & mpg123 -r32000 -m -s http://maxxima.mine.nu:8004 >lemixx.fifo & mpg123 -r32000 -m -s http://fbpc5.epfl.ch:8001 >banane.fifo &
Start FIFO streams and then run GRC or python script below.
[edit] Python code
#!/usr/bin/env python ################################################## # Gnuradio Python Flow Graph # Title: Multiple stations FM transmitter # Author: Mathias Coinchon # Generated: Sat Jan 2 21:19:02 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 multistations_FM_TX(grc_wxgui.top_block_gui): def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Multiple stations FM transmitter") ################################################## # Variables ################################################## self.samp_rate = samp_rate = 32000 self.quad_rate = quad_rate = 1280000 self.carrier2_frequency = carrier2_frequency = 300000 self.carrier1_frequency = carrier1_frequency = -300000 self.FM_frequency = FM_frequency = 107600000 ################################################## # Controls ################################################## _carrier2_frequency_sizer = wx.BoxSizer(wx.VERTICAL) self._carrier2_frequency_text_box = forms.text_box( parent=self.GetWin(), sizer=_carrier2_frequency_sizer, value=self.carrier2_frequency, callback=self.set_carrier2_frequency, label="Carrier 2 Frequency", converter=forms.float_converter(), proportion=0, ) self._carrier2_frequency_slider = forms.slider( parent=self.GetWin(), sizer=_carrier2_frequency_sizer, value=self.carrier2_frequency, callback=self.set_carrier2_frequency, minimum=-500000, maximum=500000, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_carrier2_frequency_sizer) _carrier1_frequency_sizer = wx.BoxSizer(wx.VERTICAL) self._carrier1_frequency_text_box = forms.text_box( parent=self.GetWin(), sizer=_carrier1_frequency_sizer, value=self.carrier1_frequency, callback=self.set_carrier1_frequency, label="Carrier 1 Frequency", converter=forms.float_converter(), proportion=0, ) self._carrier1_frequency_slider = forms.slider( parent=self.GetWin(), sizer=_carrier1_frequency_sizer, value=self.carrier1_frequency, callback=self.set_carrier1_frequency, minimum=-500000, maximum=500000, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_carrier1_frequency_sizer) _FM_frequency_sizer = wx.BoxSizer(wx.VERTICAL) self._FM_frequency_text_box = forms.text_box( parent=self.GetWin(), sizer=_FM_frequency_sizer, value=self.FM_frequency, callback=self.set_FM_frequency, label="Central FM frequency", converter=forms.float_converter(), proportion=0, ) self._FM_frequency_slider = forms.slider( parent=self.GetWin(), sizer=_FM_frequency_sizer, value=self.FM_frequency, callback=self.set_FM_frequency, minimum=87500000, maximum=108000000, num_steps=205, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_FM_frequency_sizer) ################################################## # Blocks ################################################## self.blks2_rational_resampler_xxx_0 = blks2.rational_resampler_ccc( interpolation=4, decimation=1, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_1 = blks2.rational_resampler_ccc( interpolation=4, decimation=1, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_2 = blks2.rational_resampler_ccc( interpolation=4, decimation=1, taps=None, fractional_bw=None, ) self.blks2_wfm_tx_0 = blks2.wfm_tx( audio_rate=samp_rate, quad_rate=320000, tau=50e-6, max_dev=75e3, ) self.blks2_wfm_tx_1 = blks2.wfm_tx( audio_rate=samp_rate, quad_rate=320000, tau=75e-6, max_dev=75e3, ) self.blks2_wfm_tx_2 = blks2.wfm_tx( audio_rate=samp_rate, quad_rate=320000, tau=75e-6, max_dev=75e3, ) self.gr_add_xx_0 = gr.add_vcc(1) self.gr_file_source_0 = gr.file_source(gr.sizeof_short*1, "/home/mc/FM_demo/lemixx.fifo", True) self.gr_file_source_1 = gr.file_source(gr.sizeof_short*1, "/home/mc/FM_demo/banane.fifo", True) self.gr_file_source_2 = gr.file_source(gr.sizeof_short*1, "/home/mc/FM_demo/stream_32k.fifo", True) self.gr_multiply_const_vxx_0 = gr.multiply_const_vcc((5000, )) self.gr_multiply_const_vxx_1 = gr.multiply_const_vff((30e-6, )) self.gr_multiply_const_vxx_1_0 = gr.multiply_const_vff((30e-6, )) self.gr_multiply_const_vxx_1_1 = gr.multiply_const_vff((30e-6, )) self.gr_multiply_xx_0 = gr.multiply_vcc(1) self.gr_multiply_xx_1 = gr.multiply_vcc(1) self.gr_short_to_float_0 = gr.short_to_float() self.gr_short_to_float_0_0 = gr.short_to_float() self.gr_short_to_float_0_0_0 = gr.short_to_float() self.gr_sig_source_x_0 = gr.sig_source_c(quad_rate, gr.GR_COS_WAVE, carrier1_frequency, 1, 0) self.gr_sig_source_x_1 = gr.sig_source_c(quad_rate, gr.GR_COS_WAVE, carrier2_frequency, 1, 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(100) self.usrp_simple_sink_x_0.set_frequency(-FM_frequency, verbose=True) self.usrp_simple_sink_x_0.set_gain(0) self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( self.GetWin(), baseband_freq=0, y_per_div=10, y_divs=10, ref_level=50, sample_rate=quad_rate, fft_size=1024, fft_rate=30, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.Add(self.wxgui_fftsink2_0.win) ################################################## # Connections ################################################## self.connect((self.gr_multiply_const_vxx_0, 0), (self.usrp_simple_sink_x_0, 0)) self.connect((self.gr_multiply_xx_0, 0), (self.gr_add_xx_0, 0)) self.connect((self.gr_add_xx_0, 0), (self.gr_multiply_const_vxx_0, 0)) self.connect((self.gr_add_xx_0, 0), (self.wxgui_fftsink2_0, 0)) self.connect((self.blks2_rational_resampler_xxx_0, 0), (self.gr_add_xx_0, 1)) self.connect((self.gr_multiply_xx_1, 0), (self.gr_add_xx_0, 2)) self.connect((self.gr_sig_source_x_1, 0), (self.gr_multiply_xx_1, 1)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 0)) self.connect((self.blks2_rational_resampler_xxx_2, 0), (self.gr_multiply_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_multiply_xx_1, 0)) self.connect((self.blks2_wfm_tx_0, 0), (self.blks2_rational_resampler_xxx_2, 0)) self.connect((self.blks2_wfm_tx_2, 0), (self.blks2_rational_resampler_xxx_0, 0)) self.connect((self.blks2_wfm_tx_1, 0), (self.blks2_rational_resampler_xxx_1, 0)) self.connect((self.gr_short_to_float_0, 0), (self.gr_multiply_const_vxx_1, 0)) self.connect((self.gr_file_source_1, 0), (self.gr_short_to_float_0, 0)) self.connect((self.gr_file_source_2, 0), (self.gr_short_to_float_0_0, 0)) self.connect((self.gr_file_source_0, 0), (self.gr_short_to_float_0_0_0, 0)) self.connect((self.gr_short_to_float_0_0, 0), (self.gr_multiply_const_vxx_1_0, 0)) self.connect((self.gr_short_to_float_0_0_0, 0), (self.gr_multiply_const_vxx_1_1, 0)) self.connect((self.gr_multiply_const_vxx_1, 0), (self.blks2_wfm_tx_1, 0)) self.connect((self.gr_multiply_const_vxx_1_0, 0), (self.blks2_wfm_tx_2, 0)) self.connect((self.gr_multiply_const_vxx_1_1, 0), (self.blks2_wfm_tx_0, 0)) def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate def set_quad_rate(self, quad_rate): self.quad_rate = quad_rate self.wxgui_fftsink2_0.set_sample_rate(self.quad_rate) self.gr_sig_source_x_0.set_sampling_freq(self.quad_rate) self.gr_sig_source_x_1.set_sampling_freq(self.quad_rate) def set_carrier2_frequency(self, carrier2_frequency): self.carrier2_frequency = carrier2_frequency self._carrier2_frequency_slider.set_value(self.carrier2_frequency) self._carrier2_frequency_text_box.set_value(self.carrier2_frequency) self.gr_sig_source_x_1.set_frequency(self.carrier2_frequency) def set_carrier1_frequency(self, carrier1_frequency): self.carrier1_frequency = carrier1_frequency self._carrier1_frequency_slider.set_value(self.carrier1_frequency) self._carrier1_frequency_text_box.set_value(self.carrier1_frequency) self.gr_sig_source_x_0.set_frequency(self.carrier1_frequency) def set_FM_frequency(self, FM_frequency): self.FM_frequency = FM_frequency self._FM_frequency_slider.set_value(self.FM_frequency) self._FM_frequency_text_box.set_value(self.FM_frequency) self.usrp_simple_sink_x_0.set_frequency(-self.FM_frequency) if __name__ == '__main__': parser = OptionParser(option_class=eng_option, usage="%prog: [options]") (options, args) = parser.parse_args() tb = multistations_FM_TX() tb.Run(True)