Gnuradio is a powerful tool to process all sorts of signals using wave functions. This covers AM, FM, all sorts of modulation and much more.
A simple starting point to play with Gnuradio is audio. It’s easy to built a tool to generate an audio tone, vary the frequency using a slider and output this using the soundcard of a PC.
Install Gnuradio
The first step is to install gnuradio and the necessary libraries. You should install gnuradio and all libgnuradio* libraries, and also libvolk.
Start Gnuradio Designer
The next step is to start Gnuradio designer
gnuradio-companion &
The GUI has 3 areas. The large one is the area which shows the built signal flow, the area on the right are the components (blocks), which can be used. The area on the bottom is a message window.
Define the components
We need the following components to create our „sound generator“:
- A signal source from the sources block. This component has two input values, the amplitude and the frequency. Use the variables defined in the two widgets defined below.
- A WX GUI Slider from the WX GUI Widgets block to vary the frequency of the signal source. Default value=5000, min=10 and max=20000
- A WX GUI Slider from the WX GUI Widgets block to vary the amplitude of the signal source. Default value=0.7, min=0.0 and max=1.0
- A Noise Source from the sources block. This is added to create a more realistic scenario. Use the variable of the widget below.
- A WX GUI Slider from the WX GUI Widgets block to vary the amplitude of the noise source. Default value=0.01, min=0.0 and max=1.0
- An Add from the operators block. This is used to add the output from the signal source and the noise source.
- A Complex to Real conversion from the Type Conversions block. This is needed to feed real values to the sound sink. The input is connected to the add output.
- A Audio Sink from the Sinks block. This sends the output signal to the soundcard. The input is connected to the Complex to Real output.
- A graphical display WX GUI Waterfall Sink from the WX GUI Widgets block. This shows the time/FFT spectrum. Set the FFT size to 2048. The input is connected to the add output.
- A graphical display WX GUI FFT Sink from the WX GUI Widgtes block. This shows the FFT spectrum. Set the FFT size to 2048, peak hold to on and average alpha to 0.1 . The input is connected to the add output.
The variable samp_rate should be set to the highest possible value for your soundcard. Most modern PCs accept a sampling rate of 192000. Setting this to high values reduces distortions of the output signal.
Now the signal flow area should look like the following screenshot:
Then you should save this setup using „save“. If you do not like to create the generator by yourself, you can use the saved Gnuradio configuration file frequency-generator.grc.
Run the generator
Use Build –> Execute to start the Sound generator. A new windows is opened, and you should now hear a tone (5000 Hz) out of the PC speaker/headphone. The window looks like:
The shown controls and graphics are:
- The slider Noise on the top defines the amplitude of the signal noise. Do not change it at the beginning.
- The second slider Loudness controls the amplitude of the audio signal source.
- The third slider Frequency is the real interesting one. If you move the slider slowly around, then the height of the tone changes.
The two graphics show the FFT of the signals.
Now it’s quite easy to extend the setup.
Python
When you select Build –> Execute, GnuRadio generates a python script in the current directory with the name top_block.py . The code generated by Gnuradio from the example is:
#!/usr/bin/env python ################################################## # Gnuradio Python Flow Graph # Title: Top Block # Generated: Fri Jan 3 21:21:14 2014 ################################################## from gnuradio import audio from gnuradio import eng_notation from gnuradio import gr from gnuradio import window from gnuradio.eng_option import eng_option from gnuradio.gr import firdes from gnuradio.wxgui import fftsink2 from gnuradio.wxgui import forms from gnuradio.wxgui import waterfallsink2 from grc_gnuradio import wxgui as grc_wxgui from optparse import OptionParser import wx class top_block(grc_wxgui.top_block_gui): def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Top Block") _icon_path = "/usr/share/icons/hicolor/32x32/apps/gnuradio-grc.png" self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) ################################################## # Variables ################################################## self.samp_rate = samp_rate = 192000 self.Noise = Noise = 0.01 self.Loudness = Loudness = 0.7 self.Frequency = Frequency = 5000 ################################################## # Blocks ################################################## _Noise_sizer = wx.BoxSizer(wx.VERTICAL) self._Noise_text_box = forms.text_box( parent=self.GetWin(), sizer=_Noise_sizer, value=self.Noise, callback=self.set_Noise, label="Noise", converter=forms.float_converter(), proportion=0, ) self._Noise_slider = forms.slider( parent=self.GetWin(), sizer=_Noise_sizer, value=self.Noise, callback=self.set_Noise, minimum=0.0, maximum=1, num_steps=1000, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_Noise_sizer) _Loudness_sizer = wx.BoxSizer(wx.VERTICAL) self._Loudness_text_box = forms.text_box( parent=self.GetWin(), sizer=_Loudness_sizer, value=self.Loudness, callback=self.set_Loudness, label="Loudness", converter=forms.float_converter(), proportion=0, ) self._Loudness_slider = forms.slider( parent=self.GetWin(), sizer=_Loudness_sizer, value=self.Loudness, callback=self.set_Loudness, minimum=0.0, maximum=1.0, num_steps=1000, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_Loudness_sizer) _Frequency_sizer = wx.BoxSizer(wx.VERTICAL) self._Frequency_text_box = forms.text_box( parent=self.GetWin(), sizer=_Frequency_sizer, value=self.Frequency, callback=self.set_Frequency, label="Frequency", converter=forms.int_converter(), proportion=0, ) self._Frequency_slider = forms.slider( parent=self.GetWin(), sizer=_Frequency_sizer, value=self.Frequency, callback=self.set_Frequency, minimum=10, maximum=20000, num_steps=1000, style=wx.SL_HORIZONTAL, cast=int, proportion=1, ) self.Add(_Frequency_sizer) self.wxgui_waterfallsink2_0 = waterfallsink2.waterfall_sink_c( self.GetWin(), baseband_freq=0, dynamic_range=100, ref_level=0, ref_scale=4.0, sample_rate=samp_rate, fft_size=2048, fft_rate=15, average=False, avg_alpha=0.1, title="Waterfall Plot", size=(900,200), ) self.Add(self.wxgui_waterfallsink2_0.win) def wxgui_waterfallsink2_0_callback(x, y): self.set_Frequency(x) self.wxgui_waterfallsink2_0.set_callback(wxgui_waterfallsink2_0_callback) self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( self.GetWin(), baseband_freq=0, y_per_div=10, y_divs=10, ref_level=0, ref_scale=4.0, sample_rate=samp_rate, fft_size=2048, fft_rate=15, average=True, avg_alpha=0.1, title="FFT Plot", peak_hold=True, ) self.Add(self.wxgui_fftsink2_0.win) self.gr_sig_source_x_2 = gr.sig_source_c(samp_rate, gr.GR_SIN_WAVE, Frequency, Loudness, 0) self.gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, Noise, 0) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_add_xx_1 = gr.add_vcc(1) self.audio_sink_0 = audio.sink(samp_rate, "", True) ################################################## # Connections ################################################## self.connect((self.gr_complex_to_real_0, 0), (self.audio_sink_0, 0)) self.connect((self.gr_noise_source_x_0, 0), (self.gr_add_xx_1, 0)) self.connect((self.gr_sig_source_x_2, 0), (self.gr_add_xx_1, 1)) self.connect((self.gr_add_xx_1, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_add_xx_1, 0), (self.wxgui_waterfallsink2_0, 0)) self.connect((self.gr_add_xx_1, 0), (self.wxgui_fftsink2_0, 0)) def get_samp_rate(self): return self.samp_rate def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate self.gr_sig_source_x_2.set_sampling_freq(self.samp_rate) self.wxgui_fftsink2_0.set_sample_rate(self.samp_rate) self.wxgui_waterfallsink2_0.set_sample_rate(self.samp_rate) def get_Noise(self): return self.Noise def set_Noise(self, Noise): self.Noise = Noise self.gr_noise_source_x_0.set_amplitude(self.Noise) self._Noise_slider.set_value(self.Noise) self._Noise_text_box.set_value(self.Noise) def get_Loudness(self): return self.Loudness def set_Loudness(self, Loudness): self.Loudness = Loudness self._Loudness_slider.set_value(self.Loudness) self._Loudness_text_box.set_value(self.Loudness) self.gr_sig_source_x_2.set_amplitude(self.Loudness) def get_Frequency(self): return self.Frequency def set_Frequency(self, Frequency): self.Frequency = Frequency self._Frequency_slider.set_value(self.Frequency) self._Frequency_text_box.set_value(self.Frequency) self.gr_sig_source_x_2.set_frequency(self.Frequency) if __name__ == '__main__': parser = OptionParser(option_class=eng_option, usage="%prog: [options]") (options, args) = parser.parse_args() tb = top_block() tb.Run(True)
If you save this code, there is no need to run the GnuRadio construction tool. GnuRadio provides a powerful python API.