0

I am writing code that takes windows of 1024 samples each of a sine wave, takes the FFT of each window, and returns the maximum frequency of each window. I know they will all be the same for a sine wave, but it's for testing. My code works mostly, except the resulting frequencies seem to be about 10 percent lower than they should be. For example, a sine of 440Hz results in a max amplitude at frequency 430 in my FFT. I can't for the life of me figure out what's causing this. Any suggestions?

import math
import numpy as np
import matplotlib.pyplot as plt
import pylab as py
from scipy import fftpack
from pylab import *
import scipy.io.wavfile

def PARTA(window):

    sr = 44100
    x = arange(0., 2*pi, 1./sr)
    samples = sin(2*pi*440*x)

    time_step = 1. / sr

    end = len(samples)/window
    print end
    '''Make a 2-D array of samples'''
    windowed = []
    maxes = []
    for i in range(0, end):
        windowed.append(samples[i*window:(i+1)*window])
    for j in range(0, end):
        ps = np.abs(np.fft.fft(windowed[j]))**2
        freqs = np.fft.fftfreq(windowed[j].size, time_step)
        max_y = max(ps)  # Find the maximum y value
        max_x = freqs[ps.argmax()]  # Find the x value corresponding to the    maximum y value
        maxes.append(max_x)
    end2 = float(len(samples)/sr)
    #print end2
    interval = end2/end
    #print interval
    x = arange(0., end2, interval)
    y = []
    for i in range(0, len(maxes)):
        y.append(abs(maxes[i]))
    return (x, y)

x, y = PARTA(1024)
plt.plot(x, y, 'ro')
plt.show()

1 Answers1

0

It's just that your FFT has very coarse resolution, since it only has 1024 bins. Each bin in your FFT has a resolution of 44100 / 1024 = 43.1 Hz. Your 440 Hz peak will be at bin index 10 which has a corresponding centre frequency of 10 * 44100 / 1024 = 430.66 Hz.

See this question for more detail on FFT bin indices and corresponding frequencies.

Community
  • 1
  • 1
Paul R
  • 208,748
  • 37
  • 389
  • 560