Home > database >  Python audio signal doesn't filter well
Python audio signal doesn't filter well

Time:03-14

I need to take an .wav audio file that's noisy and filter out all that noise. I have to do it using Fourier Transform. After some days researching and experimenting, I finally made a working function, the problem is that it doesn't work as I intend it to. Here is the function I made:

# Audio signal processing
from scipy.io.wavfile import read, write
import matplotlib.pyplot as plt
import numpy as np
from scipy.fft import fft, fftfreq, ifft


def AudioSignalProcessing(audio):

    
    # Import the .wav format audio into two variables: 
    # sampling (int)
    # audio signal (numpy array)
    
    sampling, signal = read(audio)
    
    # time duration of the audio
    length = signal.shape[0] / sampling

    # x axis based on the time duration
    time = np.linspace(0., length, signal.shape[0])
    
    # show original signal
    plt.plot(time, signal)
    plt.xlabel("Time (s)")
    plt.ylabel("Amplitude")
    plt.title("Original signal")
    plt.show()

    
    # apply Fourier transform and normalize
    transform = abs(fft(signal))
    transform = transform/np.linalg.norm(transform)
    
    # obtain frequencies
    xf = fftfreq(transform.size, 1/sampling) 
    
    # show transformed signal (frequencies domain)
    plt.plot(xf, transform)
    plt.xlabel("Frecuency (Hz)")
    plt.ylabel("Amplitude")
    plt.title("Frequency domain signal")
    plt.show()

    
    # filter the transformed signal to a 40% of its maximum amplitude
    threshold = np.amax(transform)*0.4
    filtered = transform[np.where(transform > threshold)]
    xf_filtered = xf[np.where(transform > threshold)]
    
    # show filtered transformed signal
    plt.plot(xf_filtered, filtered)
    plt.xlabel("Frecuency (Hz)")
    plt.ylabel("Amplitude")
    plt.title("FILTERED time domain signal")
    plt.show()
    
    
    # transform the signal back to the time domain
    filtrada = ifft(signal)
    
    # show original signal filtered
    plt.plot(time, filtrada)
    plt.xlabel("Time (s)")
    plt.ylabel("Amplitude")
    plt.title("Filtered signal")
    plt.show()
    
    
    # convert audio signal to .wav format audio
    # write(audio.replace(".wav", " filtrado.wav"), sampling, filtrada.astype(signal.dtype))
    
    return None

AudioSignalProcessing("audio.wav")

Here is the output plots:

Original signal

Transformed signal

Filtered transformed signal

Filtered audio signal

The filtered frequencies don't look as I think they should, and after converting the filtered signal back to audio it doesn't sound good at all. Also, I've tried with different audios but the same filter distortion happens.

CodePudding user response:

I suggest asking at https://dsp.stackexchange.com/ for detailed signal processing questions.

It looks like you want to keep only those frequency components that are within at least 40% of the maximum component. If that is the case:

  1. Keep the complex form of the DFT, or you won't be able to transform back; so remove the abs from the line transform = abs(fft(signal)).

  2. Don't use np.where to "keep" the frequencies you want; instead, set the places where the transform magnitude is below you threshold to 0; something like transform[abs(transform) < 0.4 * max(abs(transform))] = 0

  3. Finally, apply the inverse DFT to this altered transform; you've applied it to signal (see line filtrata = ifft(signal)). (You probably get warning when plotting filtrada about discarding imaginary values.)

  • Related