Spectrum Inversion



Here we demonstrate spectrum inversion by inverting every other sample, i.e., multiply by [1, -1], or (-1)^n for sample 'n'. The sequence [-1, 1] can be interpreted as the Nyquist frequency, or the sampling rate divided by 2, the highest frequency that can be represented without aliasing, with the result being the usual sum and difference frequencies. We start with this code which adds 5 signals of descending amplitude just to show a recognizable spectrum.

spectra.py


#!/usr/bin/env python
#
# Copyright 2004 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.eng_option import eng_option
from gnuradio.wxgui import stdgui, fftsink
from optparse import OptionParser
import wx

class app_flow_graph (stdgui.gui_flow_graph):
    def __init__(self, frame, panel, vbox, argv):
        stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv)

        
        parser = OptionParser (option_class=eng_option)
        (options, args) = parser.parse_args ()

        sample_rate = 8e6

	src1 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 200e3, 5, 0)
	src2 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 800e3, 2, 0)
	src3 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 1200e3, 1.5, 0)
	src4 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 1600e3, 1, 0)
	src5 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 2000e3, .5, 0)


        block, fft_win = fftsink.make_fft_sink_f (self, panel, "Spectrum", 2048, sample_rate)

	sum = gr.add_ff ()

        self.connect (src1, (sum, 0) )
	self.connect (src2, (sum, 1) )
	self.connect (src3, (sum, 2) )
	self.connect (src4, (sum, 3) )
	self.connect (src5, (sum, 4) )
	self.connect (sum, block)
	vbox.Add (fft_win, 1, wx.EXPAND)


def main ():
    app = stdgui.stdapp (app_flow_graph, "Spectrum")
    app.MainLoop ()

if __name__ == '__main__':
    main ()


The above produces this fft window with signals at .2, .8, 1.2, 1.6 and 2Mhz:



Now we modify spectrum.py by adding a vector [1, -1], a vector source and a mixer. The product of the original signal shown above with the vector is then plotted.

spectra_inv.py

#!/usr/bin/env python
#
# Copyright 2004 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.eng_option import eng_option
from gnuradio.wxgui import stdgui, fftsink
from optparse import OptionParser
import wx

class app_flow_graph (stdgui.gui_flow_graph):
    def __init__(self, frame, panel, vbox, argv):
        stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv)

        
        parser = OptionParser (option_class=eng_option)
        (options, args) = parser.parse_args ()

        sample_rate = 8e6

	src1 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 200e3, 5, 0)
	src2 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 800e3, 2, 0)
	src3 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 1200e3, 1.5, 0)
	src4 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 1600e3, 1, 0)
	src5 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 2000e3, .5, 0)

	vec1 = [1, -1]
	vsource = gr.vector_source_f (vec1, 1)  # repeat
	multiply = gr.multiply_ff ()

        block, fft_win = fftsink.make_fft_sink_f (self, panel, "Spectrum", 2048, sample_rate)

	sum = gr.add_ff ()

        self.connect (src1, (sum, 0) )
	self.connect (src2, (sum, 1) )
	self.connect (src3, (sum, 2) )
	self.connect (src4, (sum, 3) )
	self.connect (src5, (sum, 4) )
	self.connect (sum, (multiply, 0))
	self.connect (vsource, (multiply, 1))
	self.connect (multiply, block)
	vbox.Add (fft_win, 1, wx.EXPAND)


def main ():
    app = stdgui.stdapp (app_flow_graph, "Spectrum")
    app.MainLoop ()

if __name__ == '__main__':
    main ()


Now we can see the original spectrum is inverted:



Lastly, here is a fun script to invert the audio input to a sound card and play it out the sound card. The result is basically like listening to a single sideband signal on the wrong sideband.

inv_audio.py

#!/usr/bin/env python
#
# Copyright 2004 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 import audio
                                                                                
def build_graph ():
                                                                                
        fg = gr.flow_graph ()
        sample_rate = 8000
                                                                                
        src = audio.source (sample_rate)
        out = audio.sink (sample_rate)
                                                                                
        vec1 = [1, -1]
        vsource = gr.vector_source_f (vec1, 1)
        multiply = gr.multiply_ff ()
                                                                                
        fg.connect (src, (multiply, 0))
        fg.connect (vsource, (multiply, 1))
        fg.connect (multiply, out)
                                                                                
        return fg
                                                                                
def main ():
        fg = build_graph()
        fg.start()
        raw_input ('Press Enter to quit')
        fg.stop()
                                                                                
                                                                                
if __name__ == '__main__':
    main ()