본문 바로가기
Matlab

[음성 처리] 3. 음성의 높낮이, 발음 구분하기 (Speech recognition)

by 두재 2019. 4. 22.

matlab에서는 plot을 통하여 음성에 대한 정보를 직접 찾을 수 있습니다. 또한, formant 개념을 통하여 유성음을 구분할 수 있습니다.

2020. 11. 07 Formant 관련 내용 추가했습니다.


1. 음성의 음높이 구분하기

음의 높이는 주파수를 의미하며 이를 찾기 위해서는 우리 음성의 주기를 찾아 역수를 취하면 주파수를 찾을 수 있습니다. 우선 C3, G3, C4 세 음높이를 '아'(/a/) 발음으로 녹음하여 음성 파일을 만들고, 이 음성 파일에서 음높이를 찾아보도록 하겠습니다.

녹음은 아래 글을 참고하여 할 수 있습니다.

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

우선 C3, G3, C4를 각각 plot한 것은 다음과 같습니다.

/a/ C3 /a/ G3 /a/ C4

/a/ 발음을 세가지 음높이로 발음한 것

지금까지는 전체적인 모양은 알겠으나 약 1.2초 정도씩 녹음을 한 것이라 주파수를 찾기 위한 주기에 비해서는 너무나도 범위가 넓습니다.

이를 확대하여 그래프를 그리면 다음과 같습니다.

/a/ C3 close-up /a/ G3 close-up /a/ C4 close-up

/a/ 발음을 세가지 음높이로 발음한 것의 확대

이제 주기를 찾을 수 있을 정도로 확대하였고, 주기를 찾으면 됩니다. 가로축은 현재 배열의 크기입니다. 녹음을 48000Hz의 Sampling rate로 했는데, 즉 1초에 48000개의 값을 저장하고 있다는 것입니다. 때문에 그림 상에서 주기를 의미하는 가로 간격을 측정하고,

1s : 48000 = time : 간격

 이라는 식으로 실제 주기를 계산할 수 있습니다. 또한 이를 통해 주파수도 측정할 수 있습니다.

 

결과는 다음과 같습니다.

C3, G3, C4의 주기, 주파수

A4=440Hz를 기준으로 계산된 음들의 주파수는 다음과 같습니다. (참고 : http://pages.mtu.edu/~suits/notefreqs.html)

실제 음높이에 따른 주파수

비교해보면 C3는 거의 정확하고 C4는 11Hz 정도 차이가 나지만 어느 정도 일치하는 것을 확인할 수 있습니다.

 

 


2. 음성 구분하기 (Speech recognition by formants)

Formant 위키 백과 : https://en.wikipedia.org/wiki/Formant

 

Formant - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Spectrum of phonetic resonance in speech production, or its peak Spectrogram of American English vowels [i, u, ɑ] showing the formants F1 and F2 In speech science and phonetics, a form

en.wikipedia.org

모음을 구분하기 위해 formant라는 개념을 사용합니다. 아래 그림과 같이 음성을 130 Hz의 impulse train이 있고, 혀를 포함한 구강 구조가 filter 역할을 하여 이를 통과시킨 결과물이 우리의 음성이라는 관점으로 볼 수 있습니다. 아, 에, 이, 오, 우 모두 음높이가 같다면 주파수가 같아 같은 impulse train으로부터 만들어지지만 그 발음을 각각 할 때의 입모양과 구강 구조가 다르기 때문에 각각 다른 필터를 통과하면서 발음이 생긴다는 것입니다.

음성에 관한  모식도

 

어차피 Filter를 통과시키는 것은 주파수 영역에서는 곱셈으로 이루어지며 impulse train은 Fourier transform 이후에도 impulse train이므로 전체 음성을 Fourier transform 한 후 filter의 특성을 살펴보면 될 것입니다. 특성을 살펴보는 것은 극대점(local maxima)을 주파수가 낮은 순서대로 찾습니다. 이 극대점들을 Formants라 하며 주파수가 낮은 순서대로 F1, F2, F3 ... 으로 이름 붙입니다. 왼쪽 아래 사진 참고.

Formants를 이용해 음성을 찾는 방법은 이렇습니다. F1, F2 2개의 formants를 찾고, 오른쪽 아래 사진에 각각 표시하면 그에 해당하는 발음을 알 수 있습니다. 사람 각각의 목소리가 다르더라도 같은 발음을 하고 있으면 F1, F2가 어느 정도의 범위 내에서 형성된다는 것입니다.

F1, F2를 통해 발음 구분하기

 

그러면 Matlab에서 이를 찾아보겠습니다. (/a/발음 외에 비교를 위해 추가로 /i/(이) 발음을 녹음하였습니다.)

clear
[x1, Fs1] = audioread('AA.wav', [40000, 49999]);
[x2, Fs2] = audioread('AA.wav', [130000, 139999]);
[x3, Fs3] = audioread('AA.wav', [220000, 229999]);
[x4, Fs4] = audioread('IY.wav', [80000, 89999]);
[x5, Fs5] = audioread('IY.wav', [160000, 169999]);
[x6, Fs6] = audioread('IY.wav', [260000, 269999]);

aa1 = abs(fft(x1,48000));
plot(aa1)
title('Fast fourier transform AA C3')
plot(aa1,'r')
xlim([0, 2000])
grid on
title('formants AA C3 close-up')

aa2 = abs(fft(x2,48000));
plot(aa2)
title('Fast fourier transform AA G3')
plot(aa2,'r')
xlim([0, 2000])
grid on
title('formants AA G3 close-up')

aa3 = abs(fft(x3,48000));
plot(aa3)
title('Fast fourier transform AA C4')
plot(aa3,'r')
xlim([0, 3000])
grid on
title('formants AA C4 close-up')

iy1 = abs(fft(x4,48000));
plot(iy1)
title('Fast fourier transform IY C3')
plot(iy1,'r')
xlim([0, 3000])
grid on
title('formants IY C3 close-up')

iy2 = abs(fft(x5,48000));
plot(iy2)
title('Fast fourier transform IY G3')
plot(iy2,'r')
xlim([0, 3000])
grid on
title('formants IY G3 close-up')

iy3 = abs(fft(x6,48000));
plot(iy3)
title('Fast fourier transform IY C4')
plot(iy3,'r')
xlim([0, 3000])
grid on
title('formants IY C4 close-up')

 

Formants를 찾기 위하여 음성을 Fourier transform하였고 matlab에서 이는 fft(x1, 48000)을 통하여 할 수 있습니다. (fft는 fast fourier transform의 약자입니다.)

plot은 다음과 같습니다.

/a/ C3 fft /a/ G3 fft /a/ C4 fft

/a/ '아' 발음 fft

/i/ C3 fft /i/ G3 fft /a/ C4 fft

 

Formant를 찾는 방식에 대해서 내용을 추가합니다. (2020. 11. 07)

Formant를 찾는 과정은 결국 어떤 vowel을 냈는지를 찾는 과정이고 의미적으로는 결국 vowel마다 고유의 frequency를 가지기 때문에 이 고유의 frequency를 찾는 과정입니다.

그런데 우리가 위에서 얻은 FFT 결과는 이 고유의 frequency가 발성의 과정에서 목이나 입 등 여러 곳에서 자잘자잘한 반사와 울림이 중첩된 결과이며 이 과정에서 정말 1개의 주파수만으로는 표현이 되지 않을 수 있습니다. 위의 plot에서도 자잘자잘한 피크가 많이 있는 것을 보실 수 있는데요, 이 때문에 Formant를 찾기 위해서는 이 효과들을 무시하고, 제거하고 생각해야 합니다.

정확한 과정으로는 Linear predictive coding, Linear prediction analysis라는, 위에서 나온 FFT 결과를 몇 개의 수의 pole로 모델링하여 모델링된 그래프 내에서 Local maximum을 찾으면 됩니다.

출처 : www.mq.edu.au/about/about-the-university/faculties-and-departments/medicine-and-health-sciences/departments-and-centres/department-of-linguistics/our-research/phonetics-and-phonology/speech/acoustics/speech-acoustics/fft-and-lpc-spectrum-settings

위 그래프에서 자잘자잘한 선이 FFT 결과, 붉은 선이 LPC로 근사한 결과입니다. pole의 개수가 제한되어 있기 때문에 자잘자잘한 디테일은 근사하지 못하고 전체적인 peak들을 우선으로 근사한 것을 보실 수 있습니다. 이렇게 근사를 하고 나면 formant가 딱 눈에 보입니다.

저는 그런데 이 LPC까지는 하지 않았고, 쉽게 할 수 있는 방식은 아래와 같습니다. Peak들을 가상의 선으로 쭉 잇고 그 가상의 곡선에서 local maximum을 찾는 것입니다. LPC를 해서 formant를 찾는 것과 Formant의 정확한 위치는 약간씩 다를 수 있으나 생각해보시면 비슷한 위치를 나타내게 됩니다. 또한 LPC의 경우 몇 개의 pole을 쓰느냐에 따라서도 결과가 달라집니다.

출처 : hyperphysics.phy-astr.gsu.edu/hbase/Music/vowel.html

 

 

이렇게 제 1, 제 2 formant를 각각 정리하면 다음과 같습니다.

발음과 음높이에에 따른 F1, F2

이를 앞서 나온 Formants에 따른 발음을 그린 그림에 표시하면 다음과 같습니다.

Matlab fft를 통해 찾은 formants로 발음을 구분할 수 있습니다.

AA와 IY 발음으로 잘 확인되었습니다.

 


Matlab에서 음높이를 찾는 방법과, Formants를 찾고 이를 이용하여 발음을 구분해보았습니다.

Formants에 대한 자세한 얘기와 음성을 조작하거나 다루는 내용을 후에 더 작성하도록 하겠습니다.