Khachatur Mirijanyan
Khachatur Mirijanyan

Reputation: 435

Is np.fft.fft working properly? I am getting very large frequency values

I'm trying to do some audio cleaning, which I have never done before using python or otherwise and I came across the idea that I could use FFT to find the frequencies that make up my audio and eliminate the frequencies that don't belong. i did it on normal audio, but I couldn't understand the results, so I tried it on a simple sine wave.

I made it

frequency = 1000

num_samples = 48000

# The sampling rate of the analog to digital convert

sampling_rate = 48000.0
sine_wave = [np.sin(2 * np.pi * frequency * x1 / sampling_rate) for x1 in range(num_samples)]
sine_wave = np.array(sine_wave)

Then I played and plotted it and it looked and sounded like a normal size wave.

fig, ax = plt.subplots(figsize=(20,3))
ax.plot(sine_wave[:500])
IPython.display.Audio(data=sine_wave, rate=44100)

But when I did fft and looked at the frequencies on a graph it didn't make sense

def do_fft(data_samples):  
    data_fft = np.fft.fft(data_samples)
    freq = (np.abs(data_fft[:len(data_fft)]))
    plt.subplots(figsize=(20,10))
    plt.plot(freq)
    print("The frequency is {} Hz".format(np.argmax(freq)))
    return freq

sine_freq = do_fft(sine_wave)
sine_freq[47000]

For one, I don't really understand what my frequency array is supposed to mean. I know that a high number at a certain index K means that K Hz appears a lot in the sound. This would make sense since I got a value of like 23,999.99999 at 1000 Hz, which is what my wave frequency is. What doesn't make sense is that I got 24,000 for 47,000 Hz. That doesn't make any sense to me. Did I do something wrong? Is fft not working properly?

Upvotes: 0

Views: 1669

Answers (2)

hotpaw2
hotpaw2

Reputation: 70733

The FFT of strictly real (all imaginary components == zero) data is always conjugate mirror symmetric. That's just the way the math of an FFT works. So your 47kHz peak (the same as -1kHz) is just the mirror image of 1kHz at a 48k sample rate. The Nyquist folding frequency or mirroring hinge is at half the sample rate (and/or zero if you consider the upper bin frequencies negative).

Upvotes: 4

roadrunner66
roadrunner66

Reputation: 7941

I prefer to explicitly define time and calculate the frequencies. The FT should be plotted against those frequencies. The argmax alone computes the place in a vector, not a frequency. A sampling rate (sa/sec) is not a frequency. The Nyquist theorem states (among others) that your maximum frequency (in Hz) is 1/2 the sampling rate in Sa/sec. Since we are using the complex FT (pos. and neg. frequencies shown), the -999.979 Hz is actually +1000 Hz.

import numpy as np
import matplotlib.pyplot as p

sampling_rate = 48000 

t= np.linspace(0,1,sampling_rate+1)       # time vector
dt=t[1]-t[0]
print(f'first/last time {t[0]}, {t[-1]}')
print(f'time interval : {dt}')


f = 1000
sig = np.sin(2 * np.pi * f*t)

fig = p.figure(figsize=(15,10))
p.subplot(211)
p.plot(sig[:500])

p.subplot(212)
ft = np.fft.fftshift(np.fft.fft(sig))
freq=np.fft.fftshift(np.fft.fftfreq(len(t),dt))
p.plot(freq,ft )
print(f'argmax of FT is not a frequency, but a position in a vector : {np.argmax(ft)}')
f0=freq[np.argmax(ft)]
print(f'the frequency is {f0:.3f} Hz')

enter image description here

Upvotes: 2

Related Questions