728x90

오늘은 Matlab에서의 Stft(short time fourier transform)와 python library인 librosa의 stft의 dimension 결과 및 각 vector값의 차이에 대해서 알아보겠다.

 

실제로 나는 Matlab에서 DTW 알고리즘으로 테스트할 것이 있어서 stft로 변환해본 뒤 python 결과와 비교해보았는데 dimension 크기가 달랐었다. 그리하여 그 이유를 정리하여 여기에 올리겠다.

 

우선 Matlab에서 spectrogram 을 변환하기 위한 코드는 아래와 같다.

 

>> [y, Fs] = audioread("filename1.wav");
>> [x, Fs] = audioread("filename2.wav");

 

음성은 16kHz 이고, nfft=512, hop=256으로 진행하겠다 ==> frame length를 32ms, 겹치는 hop을 16ms로 진행

 

>> s1 = spectrogram(x, 512, 256);
>> s2 = spectrogram(y, 512, 256);

 

matlab data 결과

 

첨부한 그림처럼,

s1: (257, 271)

s2: (257, 256) 으로, s1이 s2보다 길이가 크다고 볼 수 있다.

 

이번에는 python에서 librosa를 사용해서 진행하겠다.

 

nfft=512

hop_length=256

wavfile_male = '경로'

wavfile_female = '경로'

male_stft = librosa.stft(y_male, n_fft=nfft, hop_length=hop_length)
female_stft = librosa.stft(y_female, n_fft=nfft, hop_length=hop_length)
print("male_stft shape {} female_stft shape {}".format(np.shape(male_stft), np.shape(female_stft)))

 

첨부한 그림처럼

male(s1): 257, 273

female(s2): 257, 258

으로 나온다. s1이 s2보다 크다.

 

근데 여기서 차원이 다르다.

 

정확히 말하면 matlab 결과물이 python librosa 결과물보다 크다. 왜 그럴까?

 

계속 찾던 도중, 잘 설명해주는 글을 발견했다.

https://stackoverflow.com/questions/55474581/difference-between-output-of-python-librosa-core-stft-and-matlab-spectrogramx

 

요약하자면, matlab은 spectrogram의 마지막 window를 생략하면서, 각 window 가운데에 해당하는 시간 벡터를 출력한다. 예를 들어 3샘플 윈도우와 1개의 겸칩(overlap) 샘플을 갖는 10개의 샘플 길이의 신호는 다음과 같은 4개의 윈도우를 생성한다.

1:3

3:5

5:7

7:9,

m:n은 n번째 샘플을 포함하여 m에서 n까지의 샘플을 포함하는 윈도우를 나타낸다. 그러므로 window의 center가 2,4,6,8이다.

matlab은 (윈도우 크기-1) * 홉 길이 + 윈도우 사이즈 <= 샘플들의 개수로 되는 최대의 윈도우 크기를 필요로 하기 때문이다.

 

 

반면 python librosa stft 각 프레임의 첫 번째 샘플이 시간이고, 프레임은 입력 신호보다 많은 부분을 다룬다.

 

위의 matlab의 공식에 반해, librosa는

윈도우의 개수 * 홉 길이 > 샘플개수에 되는 최소한의 윈도우 크기를 요구한다.

 

정리

- MATLAB은 최대한의 윈도우 크기 요구

- Librosa는 최소한의 윈도우 크기 요구

 

그럼 MATLAB과 동일한 차원을 갖고 싶다면?

librosa.stft(y, nfft=, hop=, center=False)

위의 코드처럼 맨 뒤에 center=False를 해주면 된다.

 

자세한 내용은 librosa 공식 사이트를 확인해보자 

https://librosa.github.io/librosa/generated/librosa.core.stft.html

 

center:boolean

  • If True, the signal y is padded so that frame D[:, t] is centered at y[t * hop_length].
  • If False, then D[:, t] begins at y[t * hop_length]

위의 center=False로 돌려보면,

(257, 271) (257, 256) 으로 Matlab과 동일한 차원을 갖는 Spectrogram이 나오게 된다.

 

하지만 Matlab과 librosa의 각 spectrogram의 벡터값들이 모두 같진 않다.

얼핏 보기엔 유사하지만 같지 않다.

아무래도 각 팀들에서 Nomalize등의 기법을 다르게 하여 그런 것 같다.

 

 

 

Matlab 코드

[y, Fs] = audioread("filename1.wav"); #여자
[x, Fs] = audioread("filename2.wav"); #남자

s1 = spectrogram(x, 512, 256); 
s2 = spectrogram(y, 512, 256);

Python 코드

import numpy as np

nfft=512
hop_length=256
male_name = 'masch0'
female_name = 'fekmh0'
import pickle
import scipy
from scipy.spatial.distance import euclidean

wavfile_female = '/mnt/junewoo/speech/KAIST_wav/new_Korean_Voice_DB/public/falhj0/PBSG001.wav'

wavfile_male = '/mnt/junewoo/speech/KAIST_wav/new_Korean_Voice_DB/public/masch0/PBSG001.wav'

y_female, sr = librosa.load(wavfile_female, sr=16000)
y_male, sr = librosa.load(wavfile_male, sr=16000)
male_stft = librosa.stft(y_male, n_fft=nfft, hop_length=hop_length, center=False)
female_stft = librosa.stft(y_female, n_fft=nfft, hop_length=hop_length, center=False)
print("male_stft shape {} female_stft shape {}".format(np.shape(male_stft), np.shape(female_stft)))
print('Done')
728x90

+ Recent posts