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))