Processamento de Sinais de Voz: Análise de Curto Prazo no Domínio do Tempo

Sinais de voz geralmente ocupam uma faixa de frequência entre 300 Hz e 3400 Hz. Para o processamento digital, uma taxa de amostragem de 8 kHz é comumente adotada. Devido à natureza variante no tempo da fala, utilizamos técnicas de análise de curto prazo para extrair características significativas em pequenos intervalos de tempo.

Filtro de Pré-ênfase

A pré-ênfase é aplicada para compensar a queda de energia nas altas frequências causada pela radiação labial. O objetivo é equilibrar o espectro e aumentar a resolução em altas frequências. Isso é realizado através de um filtro digital FIR de alta passagem de primeira ordem, definido pela função de transferência:

$$H(z) = 1 - \beta z^{-1}$$

Onde $\beta$ é o coeficiente de pré-ênface, usualmente situado no intervalo $[0.9, 1.0]$. Se $s(n)$ é o sinal original, o sinal filtrado $s'(n)$ é obtido por: $s'(n) = s(n) - \beta s(n-1)$. No exemplo abaixo, utilizaremos $\beta = 0.97$.


% Resposta em frequência do filtro de pré-ênfase
fs = 8000;
beta = 0.97;
[freq_resp, eixos_f] = freqz([1, -beta], [1], 512, fs);

subplot(2,1,1);
plot(eixos_f, abs(freq_resp));
title('Resposta em Magnitude do Filtro de Alta Passagem');
xlabel('Frequência (Hz)'); ylabel('Magnitude');

subplot(2,1,2);
plot(eixos_f, angle(freq_resp));
title('Resposta de Fase');
xlabel('Frequência (Hz)'); ylabel('Fase (radianos)');

Ao aplicar este filtro em um segmento de voz, observamos uma redução nas amplitudes de baixa frequência e um realce nos componentes de alta frequência, o que é crucial para identificar formantes e outros detalhes espectrais.


% Aplicação da pré-ênfase em um sinal de áudio
% s_original representa o vetor de dados de áudio
inicio = 500; fim = 755;
trecho_voz = s_original(inicio:fim);

% Filtragem no domínio do tempo
voz_filtrada = filter([1, -0.97], [1], trecho_voz);

subplot(2,1,1);
plot(trecho_voz);
title('Sinal de Voz Original');
xlabel('Amostras'); ylabel('Amplitude');

subplot(2,1,2);
plot(voz_filtrada);
title('Sinal Após Pré-ênfase');
xlabel('Amostras'); ylabel('Amplitude');

Janelamento de Sinais

A voz é um sinal quase-estacionário quando observada em intervalos curtos (10 a 30 ms). O janelamento divide o sinal em quadros, aplicando uma função de peso para suavizar as bordas e evitar descontinuidades abruptas durante a análise espectral (FFT). As funções de janela mais comuns são a Retangular e a de Hamming.

A janela de Hamming é definida como:

$$w(n) = 0.54 - 0.46 \cos\left(\frac{2\pi n}{N-1}\right), \quad 0 \leq n \leq N-1$$


% Comparação entre Janela Hamming e Retangular
N = 64;
janela_ham = hamming(N);
janela_ret = rectwin(N);

% Espectro da janela Hamming
fft_ham = abs(fft(janela_ham, 1024));
fft_ham = 20*log10(fft_ham / max(fft_ham));

% Espectro da janela Retangular
fft_ret = abs(fft(janela_ret, 1024));
fft_ret = 20*log10(fft_ret / max(fft_ret));

f_norm = (0:1023)/1024;

figure;
subplot(1,2,1);
plot(f_norm, fft_ham); axis([0 0.5 -80 0]);
title('Magnitude Hamming (dB)');
xlabel('Frequência Normalizada');

subplot(1,2,2);
plot(f_norm, fft_ret); axis([0 0.5 -80 0]);
title('Magnitude Retangular (dB)');
xlabel('Frequência Normalizada');

A janela Retangular possui um lobo principal estreito (melhor resolução de frequência), mas lobos secundários altos, causando vazamento espectral. A janela de Hamming reduz significativamente os lobos secundários em troca de um lobo principal mais largo.

Divisão em Quadros (Framing)

O processo de "Framing" consiste em segmentar o sinal contínuo em quadros sobrepostos. A sobreposição (overlap) garante que as características do sinal não sejam perdidas nas bordas das janelas. Definimos o comprimento do quadro (comp_quadro) e o deslocamento entre quadros sucessivos (salto).

O número total de quadros $N_f$ para um sinal de comprimento $L$ é dado por:

$$N_f = \lfloor \frac{L - comp\_quadro + salto}{salto} \rfloor$$

Abaixo, uma implementação personalizada da função de enquadramento:


function quadros = dividir_em_quadros(sinal, func_janela, deslocamento)
    % sinal: vetor de entrada
    % func_janela: vetor da janela ou escalar (comprimento)
    % deslocamento: amostras a saltar entre quadros
    
    total_amostras = length(sinal);
    tam_janela = length(func_janela);
    
    if tam_janela == 1
        L_quadro = func_janela;
        janela_vetor = ones(L_quadro, 1);
    else
        L_quadro = tam_janela;
        janela_vetor = func_janela(:);
    end
    
    num_quadros = floor((total_amostras - L_quadro + deslocamento) / deslocamento);
    quadros = zeros(num_quadros, L_quadro);
    
    for i = 1:num_quadros
        ponto_inicio = (i-1) * deslocamento + 1;
        segmento = sinal(ponto_inicio : ponto_inicio + L_quadro - 1);
        quadros(i, :) = segmento(:)' .* janela_vetor';
    end
end

Tags: SignalProcessing SpeechAnalysis MATLAB DigitalFilters AudioEngineering

Publicado em 8-14 05:55