ImplementaƧao das MFCCs em R

Jessica Cardoso

2018-05-15

Na Ć”rea de reconhecimento automĆ”tico de voz, uma das primeiras etapas estĆ” no processo de extraĆ§Ć£o de caracterĆ­sticas dos sinais de voz, ou seja, identificar os componentes do sinal de Ć”udio que sĆ£o bons para identificar o conteĆŗdo linguĆ­stico. E uma dessas tĆ©cnicas de reconhecimento de voz estĆ” o Mel-Frequency Cepstral Coefficients (MFCCs), a qual foi introduzida na dĆ©cada de 1980 por Davis e Mermelstein e tem sido considerada o estado da arte atĆ© o momemento [1].

Os MFCCs sĆ£o comumente obtidos atravĆ©s dos seguintes passos:

  1. Dividir o sinal em pequenos quadros
  2. Para cada quadro, calcular o espectro da potĆŖncia.
  3. Aplicar o mel filterbank no espectro de potĆŖncia e somar a energia em cada filtro.
  4. Obter o logaritmo de todas as energias do filterbanks.
  5. Pegar o DCT das energias dos logs dos filterbanks.
  6. Manter os coeficientes DCT 2-13, descartar o resto.

A operaĆ§Ć£o do MFCC foi implementado para a tarefa 2 da disciplina de Fundamentos de ComputaĆ§Ć£o GrĆ”fica (FCG), a linguagem de programaĆ§Ć£o escolhida foi o R. O cĆ³digo encontra-se disponĆ­vel no github.

Requerimentos

Explorando o pacote MFCC

ApĆ³s efetuar a instalaĆ§Ć£o do pacote, para usĆ”-lo basta utilizar a seguinte funĆ§Ć£o library(MFCC). Com o comando lsf("package:MFCC") Ć© possĆ­vel obter uma lista contendo o nome das funƧƵes implementadas, conforme ilustrado abaixo:

#>  [1] "%>%"                     "apply_dct"              
#>  [3] "apply_lifter"            "apply_preemphasis"      
#>  [5] "apply_window_hamming"    "calcule_filter_bank"    
#>  [7] "compute_mel_filterbanks" "compute_power_spectrum" 
#>  [9] "convert_hertz_to_mel"    "convert_mel_to_hertz"   
#> [11] "dct1"                    "dct2"                   
#> [13] "dct3"                    "dct4"                   
#> [15] "filter_bank_function"    "frame_the_signal"       
#> [17] "kronecker_delta"         "mfcc_function"          
#> [19] "nfft"                    "sound.data"

Para saber informaƧƵes sobre alguma funĆ§Ć£o, pode ser utilizado help('nome da funĆ§Ć£o') ou ?nome da funĆ§Ć£o.

AplicaĆ§Ć£o do pacote MFCC

Alguns exemplos do uso do pacote sĆ£o ilustrados a seguir:

library(MFCC) #carregar pacote do MFCC
library(ggplot2) #biblioteca para grƔficos

#Obter arquivo de Ɣudio exemplo
sound.data <- MFCC::sound.data
#Com o pacote tuneR, pode-se carregar um arquivo do disco da seguinte forma: (descomentar abaixo)
#sound.data <- tuneR::readWave('audio.wav', from = 0, to = 3.5, units = "seconds")
sound <- sound.data@left #valores do arquivo de Ɣudio
sample.rate <- sound.data@samp.rate #sample rate do arquivo de Ɣudio

#Exibir arquivo de Ɣudio
sound.time <- 0:(length(sound)-1)/sample.rate #tempo em segundos

#criar estrutura contendo o x e y do grƔfico
data.raw <- data.frame(x = sound.time, y = sound)

#Exibir grƔfico
p <- ggplot(data.raw, aes(x, y)) + geom_line() +
  xlab("Tempo (s)") + ylab("Amplitude") #+

## Etapas do MFCC

Inicialmente, sĆ£o definidos alguns parĆ¢metros arbitrĆ”rios que sĆ£o necessĆ”rios para o cĆ”lculo das MFCCs, sĆ£o eles:

A seguir sĆ£o inicializadas as respectivas variĆ”veis.

fft.npoints <- 512 #nĆŗmeros de pontos considerados para o cĆ”lculo da fft 
#help(nfft) #para mais informaƧƵes
freq.lower <- 0 #frequĆŖncia mĆ­nima em hertz considerada
freq.upper <- sample.rate / 2 #frequĆŖncia mĆ”xima em hertz considerada
num.filters <- 40 #nĆŗmero filtros considerados para o filterbank

PrĆ©-ĆŖnfase

Antes de aplicar os passos da MFCCs, Ć© aplicado um filtro de prĆ©-ĆŖnfase sobre o sinal, com o objetivo de amplificar as altas frequĆŖncias. A aplicaĆ§Ć£o desse filtro pode ser obtida a partir da seguinte equaĆ§Ć£o:

\[y(t) = x(t) - \alpha x(t-1)\]

Esse filtro foi implementado sobre o nome apply_preemphasis, os valores padrƵes de \(\alpha\) sĆ£o 0,95 ou 0,97. A seguir Ć© ilustrado o resultado da aplicaĆ§Ć£o do filtro sobre o sinal de som de entrada.


emphasized_signal <- apply_preemphasis(sound, 0.97)

#criar estrutura contendo o x e y do grƔfico
data.emphasized <- data.frame(x = sound.time, y = emphasized_signal)

#ExibiĆ§Ć£o
p <- ggplot(data.emphasized, aes(x, y)) + geom_line() +
  xlab("Tempo (s)") + ylab("Amplitude")

As etapas do algoritmo dos MFCCs sĆ£o descritas juntamente com as chamadas de funƧƵes implementadas neste pacote:

  1. Dividir o sinal em short frames.
  1. Para cada frame, calcular o espectro de potĆŖncia, o qual Ć© dado pela seguinte equaĆ§Ć£o: \[P = \frac{|FFT(x_i)|^2}{2}\]
  1. Aplicar o mel filterbank no espectro de potĆŖncia e somar a energia em cada filtro. \[H_m(k) = \begin{cases} \hfill 0 \hfill & k < f(m - 1) \\ \\ \hfill \dfrac{k - f(m - 1)}{f(m) - f(m - 1)} \hfill & f(m - 1) \leq k < f(m) \\ \\ \hfill 1 \hfill & k = f(m) \\ \\ \hfill \dfrac{f(m + 1) - k}{f(m + 1) - f(m)} \hfill & f(m) < k \leq f(m + 1) \\ \\ \hfill 0 \hfill & k > f(m - 1) \\ \end{cases}\]
  1. Obter o logaritmo de todas as energias do filterbanks.
  1. Pegar o DCT das energias dos logs dos filterbanks.
  1. Manter os coeficientes DCT 2-13, descartar o resto.

A visualizaĆ§Ć£o dos filterbanks pode ser vista com o seguinte trecho de cĆ³digo:


#Organizar dado para melhor visualizaĆ§Ć£o
x <- seq(from = freq.lower, to = freq.upper, length.out = ncol(fbanks)) %>% rep(num.filters)
y <- t(fbanks)
y %<>% as.data.frame() %>% tidyr::gather()

data <- data.frame(x = x, values = y$value, filters = y$key)

#Exibir espectograma
p <- ggplot(data, aes(x, values, colour = filters)) +
  geom_line() + xlab("FrequĆŖncia") + ylab("Amplitude") + theme(legend.position="none") +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0))

O espectograma da aplicaĆ§Ć£o do Filter Bank ao Power Spectrum Ć© ilustrado a seguir:


#Organizar dado para melhor visualizaĆ§Ć£o
fbanks.spec <- reshape2::melt(filter.banks)
fbanks.spec$Var1 <- fbanks.spec$Var1 / 100
fbanks.spec$Var2 <- fbanks.spec$Var2 / 10

#Exibir espectograma
p <- ggplot(fbanks.spec, aes(Var1,Var2)) + geom_raster(aes(fill = value)) +
  scale_fill_gradientn(colours = rainbow(10)) +
  xlab("Tempo (s)") + ylab("FrequĆŖncia (kHz)") + ggtitle("Espectograma do sinal") +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0))

Para realce de sinal pode ser aplicado o sinusoidal liftering aos MFCCs, o qual Ć© descrito pela seguinte equaĆ§Ć£o:

\[\hat{MFCC_i} = 1 + (\frac{w_i D}{2})\sin(\frac{Ļ€ n}{D})\]

E estĆ” implementado sobre a seguinte funĆ§Ć£o apply_lifter:

#Aplicar o sinusoidal liftering aos MFCCs
mfcc.lift <- apply_lifter(mfcc)

#Organizar dado para melhor visualizaĆ§Ć£o
mfccs.spec <- reshape2::melt(mfcc.lift)
mfccs.spec$Var1 <- mfccs.spec$Var1 / 100

#Espectograma do MFCCs
p <- ggplot(mfccs.spec, aes(Var1,Var2, fill=value)) + geom_raster(aes(fill = value)) +
  scale_fill_gradientn(colours = rainbow(10)) +
  xlab("Tempo (s)") + ylab("Coeficientes das MFCCs") + ggtitle("MFCCs") +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0))