Reputation: 435
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
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
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')
Upvotes: 2