Site menu Filtro IIR

Filtro IIR

E agora, por completeza, vamos construir um filtro IIR (resposta impulsional infinita). Este tipo de filtro digital calcula a saída baseado não apenas nos sinais de entrada, mas também com base nas saídas anteriores. Ou seja, há um componente recursivo neste tipo de filtro.

Por conta disso, ele pode gerar uma saída mesmo na ausência de sinal de entrada, daí a qualidade "infinita". Um filtro IIR pode funcionar como oscilador ou gerador de sinais, por exemplo.

Um filtro IIR pode ser expresso como uma equação diferencial discreta, que define a saída em termos das saídas anteriores, e com base nas entradas passadas. Uma equação muito popular dessa classe é a Seqüência de Fibonacci:

Fib(n) = Fib(n-1) + Fib(n-2)

Em filtragem digital, estamos mais interessados em equações diferenciais que sejam estáveis, ou seja, tendam a zero quando cessa o sinal de entrada.

Já que um filtro IIR funcional pode ser definido por uma simples equação, como a série de Fibonacci ilustrada acima, é possível fazer muita coisa com pouca capacidade computacional. Nesse sentido, um filtro IIR é muito mais poderoso que um filtro FIR.

O exemplo a seguir é um tipo de ressoador que melhora a resposta em freqüências em torno de 2000Hz (qualquer outro valor pode ser escolhido, basta alterar o código-fonte).

O fator "r" é o fator de ressonância. Se você escolher r=1, o ressoador vira um oscilador sintonizado em 2000Hz. Se você ficar r>1, a saída torna-se exponencial e inútil.

#!/usr/bin/env python

import wave, struct, math
SAMPLE_RATE = 44100

original = wave.open("NubiaCantaDalva.wav", "r")
filtered = wave.open("NubiaFilteredIIR.wav", "w")
filtered.setnchannels(1)
filtered.setsampwidth(2)
filtered.setframerate(SAMPLE_RATE)

# IIR filter coefficients
freq = 2000 # Hz
r = 0.98
a1 = -2.0 * r * math.cos(freq / (SAMPLE_RATE / 2.0) * math.pi)
a2 = r * r
filter = [a1, a2]
print filter

n = original.getnframes()
original = struct.unpack('%dh' % n, original.readframes(n))
original = [s / 2.0**15 for s in original]

result = [ 0 for i in range(0, len(filter)) ]
biggest = 1
for sample in original:
        for cpos in range(0, len(filter)):
            sample -= result[len(result) - 1 - cpos] * filter[cpos]
        result.append(sample)
        biggest = max(abs(sample), biggest)

result = [ sample / biggest for sample in result ]
result = [ int(sample * (2.0**15 - 1)) for sample in result ]
filtered.writeframes(struct.pack('%dh' % len(result), *result))

Vamos ver a qualidade de som. Primeiro, ouça o conteúdo original, e depois a versão filtrada:


(link to audio)


(link to audio)

Horrível, não é? :) Mas é de propósito. Ressoar em 2000Hz torna o som parecido com aquelas radiolas de antigamente, que reproduziam muito mais médiso do que graves e agudos.

Você pode ver que nosso filtro IIR foi calculado diretamente com base na freqüência de ressonância e no fator "r", e só tem dois pesos (a1 e a2), então ele consome apenas 2 multiplicações por amostra de áudio, enquanto um filtro FIR exigiria dezenas ou centenas de operações matemáticas por amostra.

Outra coisa que você pode notar é uma variável nominada biggest. O que é isso? De fato, os filtros IIR são antípodas dos filtros FIR: os primeiros só podem incrementar a resposta em freqüência, enquanto os segundos só podem diminuí-la.

Então, num filtro IIR, nós permitimos que ele aumente (muito) a resposta em torno de 2000Hz, acima inclusive dos limites de "clipping". Em seguida, diminuímos a saída de modo que caiba na faixa dinâmica. A composição das duas operações é deprimir todas as freqüências exceto aquelas em torno de 2000Hz.

Os coeficientes dos filtros IIR não são a resposta impulsional como seria o caso dos filtros FIR. Assim, infelizmente, você não pode calcular os pesos de um filtro IIR usando FFT. De fato, é muito difícil calcular um filtro IIR, e sempre há o risco de instabilidade devido ao caráter recursivo desse tipo de filtro.

Apenas os filtros IIR de ordem 2 (com dois pesos) são relativamente fáceis de construir, tal qual fizemos mais acima. Aproveitando-se disso, há métodos para construir filtros IIR de ordens superiores com base numa combinação de sub-filtros IIR de ordem 2, conectados em série ou em paralelo.

Outro método poderoso de desenhar um filtro IIR é imitando o desenho de um filtro analógico. Por ser tecnologia antiga e muito bem testada, há muitos designs de filtros analógicos com boa performance. De fato, todo filtro analógico tem "resposta infinita" e baseia-se em feedback (ainda que circuitos analógicos tenham saída contínua, não discreta), então de fato um filtro IIR é o equivalente digital mais próximo de um filtro analógico.

Na prática, a quase totalidade dos filtros digitais são FIR. Apesar de serem computacionalmente mais "pesados", eles são mais simples de desenvolver, e velocidade de processamento já não é mais problema, nem mesmo em dispositivos movidos a pilha-botão.