I have to reduce white noise from a sound record.Because of that i used fourier transform.But i dont know how to use the fft function's return values which is in frequincy domain.How can i use the fft data to reduce noise?
Here is my code
from scipy.io import wavfile
import matplotlib.pyplot as plt
import simpleaudio as sa
from numpy.fft import fft,fftfreq,ifft
#reading wav file
fs,data=wavfile.read("a.wav","wb")
n=len(data)
freqs=fftfreq(n)
mask=freqs>0
#calculating raw fft values
fft_vals=fft(data)
#calculating theorical fft values
fft_theo=2*np.abs(fft_vals/n)
#ploting
plt.plot(freqs[mask],fft_theo[mask])
plt.show()```
It is better for such questions to build a synthetic example, so you don't have to post a big datafile and people can still follow your question (MCVE).
It is also important to plot intermediate results since we are talking about operations on complex numbers, so we often have to take re, im parts, or absolutes and angles respectively.
The Fourier transform of a real function is complex but is symmetric for positive vs negative frequencies. One can also look at that from an information theoretical viewpoint: you wouldn't want N independent real numbers in time to result in 2N independent real numbers describing the spectrum.
While you normally plot the absolute or absolute squared (voltage vs. power) of the spectrum, you can leave it complex when you apply the filter. After back-conversion to time via the IFFT, to plot it, you'll have to convert it to a real number again, in this case by taking the absolute.
If you design the filter kernel in the time domain (FFT of a Gaussian will be a Gaussian), the IFFT of the product of the FFT of the filter and the spectrum will have only very small imaginary parts and you can then take the real part (which makes more sense from a physics viewpoint, you started with real part, end with real part).
import numpy as np
import matplotlib.pyplot as p
%matplotlib inline
T=3 # secs
d=0.04 # secs
n=int(T/d)
print(n)
t=np.arange(0,T,d)
fr=1 # Hz
y1= np.sin(2*np.pi*fr*t) +1 # dc offset helps with backconversion, try setting it to zero
y2= 1/5*np.sin(2*np.pi*7*fr*t+0.5)
y=y1+y2
f=np.fft.fftshift(np.fft.fft(y))
freq=np.fft.fftshift(np.fft.fftfreq(n,d))
filter=np.exp(- freq**2/6) # simple Gaussian filter in the frequency domain
filtered_spectrum=f*filter # apply the filter to the spectrum
filtered_data = np.fft.ifft(filtered_spectrum) # then backtransform to time domain
p.figure(figsize=(24,16))
p.subplot(321)
p.plot(t,y1,'.-',color='red', lw=0.5, ms=1, label='signal')
p.plot(t,y2,'.-',color='blue', lw=0.5,ms=1, label='noise')
p.plot(t,y,'.-',color='green', lw=4, ms=4, alpha=0.3, label='noisy signal')
p.xlabel('time (sec)')
p.ylabel('amplitude (Volt)')
p.legend()
p.subplot(322)
p.plot(freq,np.abs(f)/n, label='raw spectrum')
p.plot(freq,filter,label='filter')
p.xlabel(' freq (Hz)')
p.ylabel('amplitude (Volt)');
p.legend()
p.subplot(323)
p.plot(t, np.absolute(filtered_data),'.-',color='green', lw=4, ms=4, alpha=0.3, label='cleaned signal')
p.legend()
p.subplot(324)
p.plot(freq,np.abs(filtered_spectrum), label = 'filtered spectrum')
p.legend()
p.subplot(326)
p.plot(freq,np.log( np.abs(filtered_spectrum)), label = 'filtered spectrum')
p.legend()
p.title(' in the log plot the noise is still visible');