0

Randomly building a very easy sound spectrum analyzer.

Given this python code:
http://rosettacode.org/wiki/Fast_Fourier_transform#Python
Implemented like this:

import math
from cmath import exp, pi

def fft(x):
    N = len(x)
    if N <= 1: return x
    even = fft(x[0::2])
    odd =  fft(x[1::2])
    return ([even[k] + exp(-2j * pi * k / N) * odd[k] for k in xrange(N / 2)] + 
            [even[k] - exp(-2j * pi * k / N) * odd[k] for k in xrange(N / 2)])

#res = fft([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])
res = [math.sin(k) / 2.0 + 0.5 for k in xrange(64)]  # positive sine wave
res = fft(res)

for k in xrange(64/2):
    # get the amplitude...
    sqr = math.sqrt(res[k].real * res[k].real + res[k].imag * res[k].imag)
    if sqr > 0:
        print 20 * math.log10(sqr)  # ...in decibels
    else:
        print "-INF"

I get these results:

30.1160980385
-22.9398603241
-18.5295301528
-15.0005952198
-11.9809319241
-9.15035811436
-6.26269080991
-3.05038111824
0.930742121289
6.85461898041
23.4890109499 <-- PEAK
11.1462405429
4.62796511517
1.22261338459
-1.03611868864
-2.69639200998
-3.98905968693
-5.03263380282
-5.89570135908
-6.62130526828
-7.23808293566
-7.76594168565
-8.21919399668
-8.60840088318
-8.94151058446
-9.22459042752
-9.46231245749
-9.6582838436
-9.81527579404
-9.93538377539
-10.0201395611
-10.070588143

Which are pretty OK. I have a 23 dB peak supposedly at the frequency of the input sine wave and everything seems fine.

Only thing, what is the first value: 30.1160980385? Is that some extremely loud bass going on? Or more likely a flaw in the algorithm. In this case how do I fix that.

Last question. Is it ok for the fft to have negative values as input? In the above example I used a sine wave which is always positive ranging in [0,1]. Do I screw up everything if I want to pass values ranging in [-1,1]?

EDIT:

I removed the edit because it was off-topic. You can read what it was about here:

FFT unexpected frequency shift after window function application

Community
  • 1
  • 1
user2464424
  • 1,536
  • 1
  • 14
  • 28
  • It looks like this is a learning project, which if true by all means keep learning how to implement the FFT yourself. If you want to use a robust library look at `scipy.fftpack` which will be faster than any pure-python solution. Take a look at http://stackoverflow.com/questions/19122157/fft-bandpass-filter-in-python/19124329#19124329 for example, and other uses of the library on SO for examples. – Hooked Oct 04 '13 at 14:09

1 Answers1

2

You apparently have a large DC component due to the fact that your sine wave has an offset of +0.5. If you make your sine wave have a zero mean (i.e. a range of say +/- 0.5 or +/- 1.0) then your spectrum should look better at the DC (0 Hz) end.

Note also that you have not use a window function prior to the FFT so you will get spectral leakage (a "smearing" of the spectrum) and this can exacerbate the effect of any DC component.

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • Thank you, that makes sense. I now implemented a window function and edited my OP post. For some reason now the peak got shifted. I messed with the code perhaps? – user2464424 Oct 04 '13 at 14:04
  • Sorry, I'm not a Python programmer, so I can only give general advice on the DSP theory - the code looks OK to my untrained eye, but it sounds like you may still have some debugging to do... – Paul R Oct 04 '13 at 14:11
  • 1
    I put the shifting problem into another question: [link](http://stackoverflow.com/questions/19184597/fft-unexpected-frequency-shift-after-window-function-application/19189395). I eventually answered myself, lol. Just a stupid conceptual mistake about windowing :) – user2464424 Oct 04 '13 at 20:08