Exploring DFT






Now that we have dft working lets look at a few simple contrived cases to see that it's doing what we learned in school.

First is a constant sine wave which should return a peak in the dft output. Trying 600hz, the code:

	sample_rate = 32000
	fft_size = 1024

        src = gr.sig_source_c (sample_rate,gr.GR_SIN_WAVE,600,1,0)
        s2p = gr.serial_to_parallel (gr.sizeof_gr_complex, fft_size)
        fft1 = gr.fft_vcc (fft_size,True,True)		# forward, windowing on
        p2s_1 = gr.parallel_to_serial (gr.sizeof_gr_complex, fft_size)
        fft_1 = gr.file_sink(gr.sizeof_gr_complex, "fft")
        fg.connect ( src, s2p )
        fg.connect ( s2p, fft1 )
        fg.connect ( fft1, p2s_1 )
        fg.connect ( p2s_1, fft_1 )
When run we get this output:



Since we are using an fft window size of 1024 the above is many windows in a range of 20000. Focusing on the first 0-1023 window:



shows one peak in the far left. Focusing in on that:



we see the peak is about point 19. Out sampling rate is 32000, and the fft window is 1024, so each point is 32000/1024 = 31.25hz. Multiplying 19 * 31.25 is 593.75, very close to our input signal. Adjusting the signal to an even 'bin' frequency of 593.75, we get a more symmetrical peak:



and each 1024 sample 'window' has the same symmetrical peak, as opposed to the first plot where each has a different shape due to different phase within the window. Indeed you can change the input signal frequency to anything from a few hz to 16Khz and move the peak up and down the spectrum, just as expected.




Next we create our own spectrum with a peak at 19 and do an inverse dft transform. The code:
        sample_rate = 32000
        fft_size = 1024


        vec = []
        for i in range(0,19):           # 0 to 18
          vec += [0]
        vec += [1+0j]                   # 19
        for i in range(21,1024):        # 20 to 1023
          vec += [0]

        src = gr.vector_source_c(vec, 1)
        s2p = gr.serial_to_parallel (gr.sizeof_gr_complex, fft_size)
        ifft1 = gr.fft_vcc (fft_size,False,False) # inverse, no windowing

        p2s = gr.parallel_to_serial (gr.sizeof_gr_complex, fft_size)
        ifft_out = gr.file_sink(gr.sizeof_gr_complex, "ifft")

        fg.connect ( src, s2p )
        fg.connect ( s2p, ifft1 )
        fg.connect ( ifft1, p2s )
        fg.connect ( p2s, ifft_out )


which returns this nice cosine wave with 54 points/cycle, or about 592Hz at 32000 sample rate:






Finally, the point of this operation, to do an inverse DFT on a rectangle to create sinc functions. The code, same as above except to create our input spectrum vector:

        vec = []
        for i in range(0,19):           # 0 to 20
          vec += [1]
        for i in range(20,1024):        # 21 to 1023
          vec += [0]


which produces this beautiful output:



Math: According to the paper referenced here, "Note that a pulse of width t has the bulk of its energy contained in the main lobe, which spans a one-sided bandwidth of 1/t Hz." Our pulse width here is 20/32000 = 625uS, so the main lobe bandwidth should be 1600Hz. Estimating the width above near the bottom is something around 1050-995=55 bins. Recall each bin is 32000/1024=31.25 (sample rate / fft width), and indeed 55*31.25=1718.75. Moral of story, narrower pulses use wider bandwith.

Below, using a narrower rectangle pulse gets a wider sinc function. Using 10 instead of 20: