Phase 06 - Lesson 02
Espectrogramas, Escala Mel e Features de Áudio
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
Redes neurais não consomem bem formas de onda cruas. Elas consomem espectrogramas. Consomem espectrogramas mel ainda melhor. Todo ASR, TTS e classificador de áudio em 2026 vive ou morre por essa única escolha de pré-processamento.
Type: Build Languages: Python Prerequisites: Phase 6 · 01 (Audio Fundamentals) Time: ~45 minutes
O Problema
Pegue um clipe de 10 segundos a 16 kHz. São 160.000 floats, todos em [-1, 1], quase perfeitamente descorrelacionados do rótulo "cachorro latindo" ou "a palavra gato". A forma de onda crua tem a informação, mas em um formato que o modelo não consegue extrair facilmente. Dois fonemas idênticos pronunciados com 100 ms de diferença têm amostras cruas completamente diferentes.
Um espectrograma resolve isso. Ele descarta o detalhe temporal onde a percepção humana o ignora (jitter de microssegundos) e preserva a estrutura onde a percepção presta atenção (quais frequências são energéticas, ao longo de janelas de tempo de ~10–25 ms).
Espectrogramas mel vão mais longe. Os humanos percebem o tom (pitch) de forma logarítmica: 100 Hz vs 200 Hz soa "à mesma distância" que 1000 Hz vs 2000 Hz. A escala mel deforma o eixo de frequência para corresponder a isso. Um espectrograma em escala mel é a feature mais importante em ML de fala de 2010 até 2026.
O Conceito
STFT (Short-Time Fourier Transform). Fatie a forma de onda em quadros (frames) sobrepostos (típico: janela de 25 ms, salto de 10 ms = 400 amostras / 160 amostras a 16 kHz). Multiplique cada quadro por uma função de janela (Hann é o padrão; Hamming tem um tradeoff levemente diferente). Aplique FFT em cada quadro. Empilhe os espectros de magnitude em uma matriz de formato (n_frames, n_freq_bins). Esse é o seu espectrograma.
Log-magnitude. Magnitudes cruas abrangem 5-6 ordens de grandeza. Aplique log(|X| + 1e-6) ou 20 * log10(|X|) para comprimir a faixa dinâmica. Todo pipeline de produção usa log-magnitude, não magnitude crua.
Escala mel. A frequência f em Hz mapeia para mel m por m = 2595 * log10(1 + f / 700). O mapeamento é aproximadamente linear abaixo de 1 kHz e aproximadamente logarítmico acima. 80 bins mel cobrindo 0–8 kHz é a entrada padrão de ASR.
Banco de filtros mel (mel filterbank). Um conjunto de filtros triangulares espaçados igualmente na escala mel. Cada filtro é uma soma ponderada de bins adjacentes da FFT. Multiplicar a magnitude da STFT pela matriz do banco de filtros dá o espectrograma mel em uma única multiplicação de matrizes (matmul).
Espectrograma log-mel. log(mel_spec + 1e-10). A entrada do Whisper. A entrada do Parakeet. A entrada do SeamlessM4T. O frontend de áudio universal de 2026.
MFCCs. Pegue o espectrograma log-mel, aplique uma DCT (tipo II), mantenha os primeiros 13 coeficientes. Descorrelaciona as features e comprime ainda mais. Feature dominante até cerca de 2015, quando CNNs/Transformers sobre log-mels cruos a alcançaram. Ainda usada em reconhecimento de locutor (x-vectors, ECAPA).
Tradeoff de resolução. FFT maior = melhor resolução de frequência, mas pior resolução temporal. 25 ms / 10 ms é o padrão de ML de áudio; 50 ms / 12,5 ms para música; 5 ms / 2 ms para detecção de transientes (batidas de bateria, plosivas).
Construa
Passo 1: dividir a forma de onda em quadros
def frame(signal, frame_len, hop):
n = 1 + (len(signal) - frame_len) // hop
return [signal[i * hop : i * hop + frame_len] for i in range(n)]
Um clipe de 10 segundos a 16 kHz com frame_len=400, hop=160 produz 998 quadros.
Passo 2: janela de Hann
import math
def hann(N):
return [0.5 * (1 - math.cos(2 * math.pi * n / (N - 1))) for n in range(N)]
Multiplique elemento a elemento antes da FFT. Remove o vazamento espectral (spectral leakage) causado por truncar em extremidades diferentes de zero.
Passo 3: magnitude da STFT
def stft_magnitude(signal, frame_len=400, hop=160):
win = hann(frame_len)
frames = frame(signal, frame_len, hop)
return [magnitudes(dft([w * s for w, s in zip(win, f)])) for f in frames]
A produção usa torch.stft ou librosa.stft (apoiados em FFT, vetorizados). O laço aqui é pedagógico; ele roda em clipes curtos em code/main.py.
Passo 4: banco de filtros mel
def hz_to_mel(f):
return 2595.0 * math.log10(1.0 + f / 700.0)
def mel_to_hz(m):
return 700.0 * (10 ** (m / 2595.0) - 1)
def mel_filterbank(n_mels, n_fft, sr, fmin=0, fmax=None):
fmax = fmax or sr / 2
mels = [hz_to_mel(fmin) + (hz_to_mel(fmax) - hz_to_mel(fmin)) * i / (n_mels + 1)
for i in range(n_mels + 2)]
hzs = [mel_to_hz(m) for m in mels]
bins = [int(h * n_fft / sr) for h in hzs]
fb = [[0.0] * (n_fft // 2 + 1) for _ in range(n_mels)]
for m in range(n_mels):
for k in range(bins[m], bins[m + 1]):
fb[m][k] = (k - bins[m]) / max(1, bins[m + 1] - bins[m])
for k in range(bins[m + 1], bins[m + 2]):
fb[m][k] = (bins[m + 2] - k) / max(1, bins[m + 2] - bins[m + 1])
return fb
80 mels cobrindo 0–8 kHz com n_fft=400 dá uma matriz (80, 201). Multiplique a magnitude da STFT (n_frames, 201) pela transposta para obter o espectrograma mel (n_frames, 80).
Passo 5: log-mel
def log_mel(mel_spec, eps=1e-10):
return [[math.log(max(v, eps)) for v in frame] for frame in mel_spec]
Alternativas comuns: librosa.power_to_db (dB normalizado por referência), 10 * log10(power + eps). O Whisper usa uma rotina de clip + normalização mais elaborada (veja o log_mel_spectrogram do Whisper).
Passo 6: MFCCs
def dct_ii(x, n_coeffs):
N = len(x)
return [
sum(x[n] * math.cos(math.pi * k * (2 * n + 1) / (2 * N)) for n in range(N))
for k in range(n_coeffs)
]
Aplique a DCT a cada quadro log-mel, mantenha os primeiros 13 coeficientes. Essa é a sua matriz MFCC. O primeiro coeficiente costuma ser descartado (ele codifica a energia geral).
Use
A stack de 2026:
| Tarefa | Features |
|---|---|
| ASR (Whisper, Parakeet, SeamlessM4T) | 80 log-mels, salto de 10 ms, janela de 25 ms |
| Modelo acústico de TTS (VITS, F5-TTS, Kokoro) | 80 mels, salto de 5–12 ms para controle temporal fino |
| Classificação de áudio (AST, PANNs, BEATs) | 128 log-mels, salto de 10 ms |
| Embedding de locutor (ECAPA-TDNN, WavLM) | 80 log-mels ou SSL sobre forma de onda crua |
| Música (MusicGen, Stable Audio 2) | Tokens discretos do EnCodec (não mels) |
| Detecção de palavra-chave (keyword spotting) | 40 MFCCs para dispositivos minúsculos |
Regra prática: se você não está trabalhando com música, comece com 80 log-mels. O ônus da prova recai sobre qualquer desvio.
Armadilhas que ainda chegam à produção em 2026
- Incompatibilidade na contagem de mels. Treinar com 80 mels, inferir com 128 mels. Falha silenciosa. Logue o formato (shape) da feature nas duas pontas.
- Incompatibilidade de sample rate upstream. Mels computados a 22,05 kHz parecem diferentes dos de 16 kHz. Corrija o SR antes da extração de features.
- dB vs log. O Whisper espera log-mel, não dB-mel. Alguns pipelines do HF autodetectam; o seu código customizado não vai.
- Deriva de normalização. Normalização por enunciado durante o treino, normalização global durante a inferência. Bug de produção que dobra o WER.
- Vazamento por padding. Preencher o final de um clipe com zeros produz um espectro plano nos quadros finais. Faça padding simétrico ou replique.
Entregue (Ship It)
Salve como outputs/skill-feature-extractor.md. A skill escolhe o tipo de feature, a contagem de mels, o frame/hop e a normalização para um determinado modelo-alvo.
Exercícios
- Fácil. Rode
code/main.py. Ele sintetiza um chirp (frequência varrida de 200 → 4000 Hz) e imprime o argmax do bin mel por quadro. Plote (opcional) e confirme que corresponde à varredura. - Médio. Reexecute com
n_melsem{40, 80, 128}eframe_lenem{200, 400, 800}. Meça a largura de banda do pico agudo ao longo do eixo temporal. Qual combinação resolve melhor o chirp? - Difícil. Implemente
power_to_dbe compare a acurácia de ASR de um pequeno classificador CNN no AudioMNIST usando (a) log-mel cru, (b) dB-mel comref=max, (c) MFCC-13 + delta + delta-delta. Reporte a acurácia top-1.
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| Frame | Uma fatia | Trecho de 25 ms da forma de onda alimentado em uma FFT. |
| Hop | Stride | Amostras entre quadros consecutivos; 10 ms é o padrão de ASR. |
| Window | Coisa Hann/Hamming | Multiplicador ponto a ponto que afina as bordas do quadro até zero. |
| STFT | Gerador de espectrograma | FFT enquadrada + janelada; produz matriz tempo × frequência. |
| Mel | Frequência deformada | Escala de log-percepção; m = 2595·log10(1 + f/700). |
| Filterbank | A matriz | Filtros triangulares que projetam a STFT em bins mel. |
| Log-mel | A entrada do Whisper | log(mel_spec + eps); padronizada em 2026. |
| MFCC | Feature da velha guarda | DCT do log-mel; 13 coeficientes, descorrelacionados. |
Leitura Adicional
- Davis, Mermelstein (1980). Comparison of parametric representations for monosyllabic word recognition — o artigo do MFCC.
- Stevens, Volkmann, Newman (1937). A Scale for the Measurement of the Psychological Magnitude Pitch — a escala mel original.
- OpenAI — Whisper source, log_mel_spectrogram — leia a implementação de referência.
- librosa feature extraction docs — referência para
mfcc,melspectrograme hop/window. - NVIDIA NeMo — audio preprocessing — pipeline em escala de produção para os modelos Parakeet + Canary.