본문 바로가기
Matlab

[음성 처리] 2. 음성에서 노이즈 제거하기 (Noise suppression)

by 두재 2019. 4. 22.

 

matlab에서는 음성을 배열처럼 다뤄 손쉽게 합성할 수 있으며 filter를 통하여 다양한 filter를 만들고 음성을 filter에 통과시킬 수 있습니다. 이를 통해 노이즈가 혼합된 음성에서 filter를 통하여 기존의 음성을 복원해보겠습니다.


1. 음성과 노이즈 합성하기

우선 원하는 음성과 노이즈를 우선 따로 녹음하여 합성시킨 후 제거를 해보도록 하겠습니다.

<1. 음성 파일(.wav) 녹음 및 정보 확인하기> 글을 참고하여 3초간 남자 목소리, 여자 목소리, 소음(전자레인지 소리)을 각각 녹음합니다.

2019/04/21 - [Matlab] - [음성 처리] 1. 음성 파일(.wav) 녹음 및 정보 확인하기

 

[음성 처리] 1. 음성 파일(.wav) 녹음 및 정보 확인하기

매트랩에서는 audioread, audiowrite을 통해서 음성 파일 입출력이 가능합니다. 1. 녹음하기 recorder1 = audiorecorder(48000,16,1) disp('Start'); recordblocking(recorder1, 3); disp('End'); 위 코드는 3초..

honeyjamtech.tistory.com

남자, 여자 목소리를 따로 녹음하는 이유는 두 목소리의 주요한 주파수 범위가 다르기 때문입니다. 

이 글에서는 Filter를 이용하여 노이즈를 제거(Noise suppression)하는 것이기 때문에 노이즈와 원하는 목소리의 주파수 대역이 같다면 깔끔하게 노이즈를 제거할 수 없습니다.

 

clear
[x1, Fs1] = audioread('girl.wav');
[x2, Fs2] = audioread('boy.wav');
[x3, Fs3] = audioread('noise.wav');
k=0.65;
new1 = zeros(144000,1);
new2 = zeros(144000,1);
for i = 1:1:144000
    new1(i)=((1-k)*(x1(i))+k*(x3(i)));
    new2(i)=((1-k)*(x2(i))+k*(x3(i)));
end
filename1 = 'SPRgirl.wav';
filename2 = 'SPRme.wav';
audiowrite(filename1, new1, 48000);
audiowrite(filename2, new2, 48000);

spectrogram(x1, 'yaxis')
title('Original Girl')
spectrogram(x2, 'yaxis')
title('Original me')
spectrogram(x3, 'yaxis')
title('Origianl Noise')
spectrogram(new1, 'yaxis')
title('SPR girl')
spectrogram(new2, 'yaxis')
title('SPR me')

 

코드의 전체적인 흐름은 다음과 같습니다.

1. 여자 목소리, 남자 목소리, 노이즈 음성 파일을 읽습니다.

2. y = (1-k)*x + k*n 이라는 수식을 통하여 x (목소리 음성) + n (노이즈 음성)을 적절한 비율로 합칩니다. k가 0.5 일 경우는 각각 같은 크기로 더해지나, 몇 번의 시도 후 k가 0.65인 경우 목소리에 적절한 크기의 노이즈가 합쳐진 것으로 들렸습니다.

3. 여자 목소리+노이즈, 남자 목소리+노이즈 를 각각 .wav파일로 만듭니다.

4. 여자 목소리, 남자 목소리, 노이즈, 여자 목소리+노이즈, 남자 목소리+노이즈 이 5가지 음성 샘플의 Spectrogram을 관찰합니다.

 

우선 노이즈를 합치기 전 여자 목소리, 남자 목소리, 노이즈는 다음과 같습니다.

(그림 1) 여자 목소리 (그림 2) 남자 목소리 (그림 3) 노이즈

노이즈를 합치기 전 3가지 음성 파일의 Spectrogram

 

여기서 눈여겨 볼 점은 노이즈의 Spectrogram입니다. 거의 시간에 상관없이 일정하게 소리가 나오는 것으로 보이는데, 주요한 주파수 대역이 0에서 0.15입니다. 전자레인지 소리이기 때문에 낮은 주파수 대역에 소리가 집중되어 있는 것을 볼 수 있습니다.

그렇다면, 노이즈를 합친 후 여자 목소리+노이즈, 남자 목소리+노이즈를 보도록 하겠습니다.

(그림 4) 여자 목소리+노이즈 (그림 5) 남자 목소리+노이즈

노이즈를 합친 후 2가지 음성 파일의 Spectrogram

 

노이즈 부분이 합성되었기 때문에, 그림 1, 그림 2의 Spectrogram에서 주파수가 낮은 부분이 크기가 약 -30db/(rad/sample) 정도로 노란색으로 색칠된 것을 볼 수 있습니다. 그림 1의 경우는 낮은 주파수 부분이 초록색이었는데, 그림 4에서는 노란색으로 차이가 심하다는 것을 볼 수 있고, 그림 2에서는 노이즈의 주파수 대역을 목소리가 공유하기 때문에 약간 어려울 것으로 예상됩니다.

 


2. 필터 생성하기

[b, a] = butter(2, [0.1, 0.4], 'bandpass');
freqz(b, a)

aftfil1=filter(b,a,new1);
aftfil2=filter(b,a,new2);
%player2 = audioplayer(aftfil1, 48000, 16);
%play(player2)

spectrogram(aftfil1, 'yaxis')
title('After filter girl')
spectrogram(aftfil2, 'yaxis')
title('After filter me')
filename3 = './Sounds/butterworthgirl.wav';
filename4 = './Sounds/butterworthme.wav';
audiowrite(filename3, aftfil1, 48000);
audiowrite(filename4, aftfil2, 48000);

 

신호 처리에서 여러 가지 필터가 있습니다. Butterworth filter, Chebyshev filter, Elliptic filter 등입니다. 아래 사진은 이 들에 대한 비교입니다. Butterworth filter의 경우 다른 filter에 비해 cut-off frequency에서 급격하게 내려가지는 않습니다. 그리고 cut-off frequency 이전과 이후 모두 평평한 모양을 띄고 있습니다(monotonic amplitude response를 보임). Filter에 대해서는 나중에 더 추가로 얘기를 해보도록 하고, 여기서는 Butterworth filter를 사용해보겠습니다.

각 filter들에 대한 Gain

 

matlab에서 filter를 다루는 방법은 다음과 같습니다.

[b, a] = butter(2, [0.1, 0.4], 'bandpass');

이 명령을 통하여 butterworth filter의 전달 함수를 만들고, b는 전달함수의 분자의 계수로 이루어진 배열이고 a는 전달 함수의 분모의 계수로 이루어진 배열입니다.

예를 들어 전달 함수가 다음과 같다고 할 때,

b는 1, a는 [1, -0.2]로 설정한다는 것입니다.

또한, matlab에서 butterworth filter를 다룰 때 추가시키는 인자들이 현재 '2', '[0.1, 0.4], 'bandpass'가 있습니다.

2는 filter의 차수를 의미하고 [0.1, 0.4]는 필터에서 통과시킬 범위를 의미합니다. 현재 bandpass로 되어있기 때문에 앞에 나온 범위를 통과시키는 필터를 생성합니다. 'lowpass'나 'highpass'도 가능하며 이 때에는 범위가 아닌 cut-off frequency를 적어주면 됩니다.

freqz(b, a)

이 명령은 b와 a로 이루어진 전달 함수에 대하여 Magnitude response와 Phase response로 구성된 Bode plot을 그려줍니다.

결과는 다음과 같습니다.

생성한 Butterworth filter의 Bode plot

 

Bode plot에서 Magnitude response를 보면 낮은 주파수 대역을을 제거하고 있는 것을 볼 수 있습니다.

 

filter의 인자에 대해서는 Spectrogram을 참고하여 차수를 바꾸거나 범위를 바꾸는 등 여러 가지를 시도해보며 결정합니다.


3. Butterworth filter 통과시키기

aftfil1=filter(b,a,new1);
aftfil2=filter(b,a,new2);
%player2 = audioplayer(aftfil1, 48000, 16);
%play(player2)

spectrogram(aftfil1, 'yaxis')
title('After filter girl')
spectrogram(aftfil2, 'yaxis')
title('After filter me')
filename3 = './Sounds/butterworthgirl.wav';
filename4 = './Sounds/butterworthme.wav';
audiowrite(filename3, aftfil1, 48000);
audiowrite(filename4, aftfil2, 48000);

 

aftfil1=filter(b,a,new1);

aftfil2=filter(b,a,new2);

필터를 통과시키는 것은 위와 같습니다.

aftfil1, 2에 각각 앞서 만든 전달 함수의 분자, 분모 계수인 b와 a를 통과시키는 명령문입니다.

spectrogram(aftfil1, 'yaxis')

title('After filter girl')

spectrogram(aftfil2, 'yaxis')

title('After filter me')

또한 이 명령을 통하여 Butterworth filter를 통과시킨 후의 Spectrogram을 그립니다.

(그림 6) 필터 통과시킨 여자 목소리+노이즈 (그림 7) 필터 통과시킨 남자 목소리+노이즈

필터를 통과시킨 후의 두 음성 파일

 

두 Spectrogram을 보면 그림 4와 그림 5와 확연한 차이를 느낄 수 있습니다. 낮은 주파수 영역이 초록색, 파란색으로 바뀌었고 filter가 잘 적용되었다고 확인할 수 있습니다.

이 두 음성을 재생해보면 filter를 통과시킨 여자 목소리는 어느 정도 원래 목소리로 복원되었으나, 남자 목소리의 경우 노이즈는 없어졌으나 원래 목소리도 일부가 손상된 것을 확인할 수 있습니다.

 


Filter가 노이즈와 원래 음성을 구분할 수 없기 때문에 노이즈와 주파수가 겹치는 남자 목소리의 경우는 노이즈를 없애면 원본 음성이 손실되고 원본 음성을 살리자니 노이즈를 없앨 수 없는 문제가 생깁니다.

여러 Filter에 관한 설명과 Matlab에서 filter를 다루는 법에 대해서는 후에 더 작성하도록 하겠습니다.