AI/signal

signal filter in python 소리의 필터

hadaney 2020. 3. 29. 15:58

 

소리의 필터는 다양한 종류가 있습니다.

https://en.wikipedia.org/wiki/Filter_(signal_processing)#/media/File:Bandform_template.svg

 

이중에 대표적으로 band-pass filter와 band-stop filter(notch filter)만 알면 다른 것들도 다 구현 가능합니다.

 

 

 

1) bandpass filter

bandpass-filter는 frequency중에 딱 일부 대역대만 뽑아서 통과시키는 필터입니다.

lower-pass가 기준값보다 작은 값을 모두 통과시키고, high-pass가 기준값보다 큰 값을 모두 통과시키는 것이라면,

band-pass 는 일정영역만 통과시킵니다.

모든 필터들이 frequency값을 통과시킬때 경계값을 어떻게 처리할 것인가에 방법이 모두 다를텐데, 가장 general한 방법은 butterworth형태입니다. ( [200-300]만 통과시킬때 200부근과 300부근이 경계값이다. 연속적인 파장을 가지는 소리의 경우, 정확히 200, 300처럼 값을 끊기가 어렵다 ) 

그림으로 간단히 설명해 보겠습니다.

The Butterworth filter rolls off more slowly around the cutoff frequency than the  Chebyshev filter  or the  Elliptic filter , but without ripple.

f/fo 1.0을 cut-off기준으로 삼아서 frequency를 자른다고 할 때, Buttterworth는 Chebyshev나 Elliptic보다 더 부드럽게 자르는 것을 알 수 있습니다. 천천히 자를 수록 자연스럽게 자를 수 있고, 빠르게 끊을 수록 정확히 해당 소리만 가져오게 됩니다.

python으로 butter방법을 이용하여 band pass filter를 해보겠습니다.

from scipy.signal import butter, lfilter

def butter_bandpass(lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='band')
    return b, a


def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    y = lfilter(b, a, data)
    return y
    
# return (400-600 Hz) filtered signal
butter_bandpass_filter(wav_data, 400, 600, 44100, 3)

lowcut과 highcut이 내가 관심있는 주파수 영역대라면,fs는 sampling rate를 일컫습니다.

( 소리를 측정하는 것과 관련되어 있는데, 이와 관련해서는 다음 포스팅에서 설명하겠습니다. )

order는 frequency를 어느정도로 급격하게 자를건지와 관련되어 있습니다.

stackoverflow에서 order와 관련된 이미지를 첨부하겠습니다.

https://stackoverflow.com/questions/21862777/bandpass-butterworth-filter-frequencies-in-scipy

 

 

 

2) band-stop filter (notch filter)

bandpass filter와 반대로 notch filter는 특정 frequency대역대만 제거하는 filter입니다.

python으로 구현하면 다음과 같습니다.

from scipy import signal

def notch_pass_filter(data, center, interval=20, sr=44100, normalized=False):
    center = center/(sr/2) if normalized else center
    b, a = signal.irrnotch(center, center/interval, sr)
    filtered_data = signal.lfilter(b, a, data)
    return filtered_data
    
# return filtered data with (1100 Hz) stopband 
notch_pass_filter(wav, 1100, 20, 44100, True)

center는 내가 지우고자 하는 frequency대역의 중심주파수 값입니다.

interval은 중심주파수를 기준으로 좌우로 얼마나 지울 것인지를 나타냅니다.

interval로 Quality Factor를 계산해서 irrnotch의 param으로 넣는데,
식은 좌측과 같습니다. fnull이 중심주파수라고 보면 됩니다.

irrnotch에 넣을 때는 반대로 넣습니다.