БИХ-фильтры (IIR): рекурсия и обратная связь

Разбираем IIR — фильтры с обратной связью: они экономнее FIR, но требуют осторожности.

IIR-фильтр (БИХ, с бесконечной импульсной характеристикой) использует обратную связь: выход зависит не только от входа, но и от прошлых выходов: y[n] = b*x[n] + a*y[n-1] + .... Отсюда бесконечный импульсный отклик.

FIR прост и надёжен, но «прожорлив»: крутой фильтр требует сотни коэффициентов. IIR решает ту же задачу горсткой коэффициентов за счёт хитрого приёма — обратной связи. Эхо, реверберация, резонанс, аналоговые фильтры (Баттерворта, Чебышёва) — всё это IIR. Но обратная связь несёт риск: фильтр может «разойтись». Разберёмся.

Однополюсный IIR: эконом-сглаживатель

Простейший IIR — однополюсный ФНЧ: y[n] = a*x[n] + (1-a)*y[n-1]. Каждый новый выход — это смесь нового входа и предыдущего выхода. Всего один коэффициент, а сглаживает не хуже длинного FIR.

def iir_lowpass(x, a):
    y = []
    prev = 0.0
    for s in x:
        prev = a * s + (1 - a) * prev    # обратная связь: используем прошлый выход
        y.append(round(prev, 3))
    return y

step = [0, 0] + [10] * 8                  # сигнал-ступенька
print("вход:        ", step)
print("IIR (a=0.5): ", iir_lowpass(step, 0.5))

Вывод:

вход:         [0, 0, 10, 10, 10, 10, 10, 10, 10, 10]
IIR (a=0.5):  [0.0, 0.0, 5.0, 7.5, 8.75, 9.375, 9.688, 9.844, 9.922, 9.961]

Выход плавно подползает к уровню 10 — это классическая экспоненциальная реакция ФНЧ. Параметр a задаёт скорость: меньше a — медленнее и сильнее сглаживание. И всё это одним коэффициентом!

Почему импульсная характеристика бесконечна

Подадим в IIR единичный импульс. Из-за обратной связи отклик не обрывается, а бесконечно затухает — отсюда название «бесконечная импульсная характеристика».

def iir_impulse(a, N):
    y = []
    prev = 0.0
    for n in range(N):
        x = 1 if n == 0 else 0
        prev = a * x + (1 - a) * prev
        y.append(round(prev, 4))
    return y

print("Импульсный отклик IIR (a=0.5):", iir_impulse(0.5, 8))

Вывод:

Импульсный отклик IIR (a=0.5): [0.5, 0.25, 0.125, 0.0625, 0.0312, 0.0156, 0.0078, 0.0039]

После единственного «укола» отклик тянется бесконечно, уменьшаясь вдвое на каждом шаге. У FIR он оборвался бы на длине ядра — у IIR продолжается вечно, пусть и затухая.

Устойчивость — главный риск IIR

Обратная связь может выйти из-под контроля. Рассмотрим фильтр y[n] = x[n] + a*y[n-1]. При |a| < 1 отклик затухает (устойчив), при |a| > 1 — растёт без предела (неустойчив).

def iir(a, N):
    y = []
    prev = 0.0
    for n in range(N):
        x = 1 if n == 0 else 0
        prev = x + a * prev
        y.append(round(prev, 2))
    return y

print("a=0.8 (|a|<1, устойчив):  ", iir(0.8, 8))
print("a=1.2 (|a|>1, расходится):", iir(1.2, 8))

Вывод:

a=0.8 (|a|<1, устойчив):   [1.0, 0.8, 0.64, 0.51, 0.41, 0.33, 0.26, 0.21]
a=1.2 (|a|>1, расходится): [1.0, 1.2, 1.44, 1.73, 2.07, 2.49, 2.99, 3.58]

При a=0.8 отклик мирно затухает. При a=1.2 он растёт лавиной — фильтр «взорвался». Устойчивость IIR надо проверять всегда; для FIR такой проблемы нет в принципе.

Как работает под капотом

Устойчивость IIR определяется положением его полюсов на комплексной плоскости (z-плоскости, см. следующий урок). Правило: все полюса должны лежать внутри единичной окружности — тогда фильтр устойчив. В нашем примере полюс находится в точке z = a: при |a| < 1 он внутри окружности (устойчиво), при |a| > 1 — снаружи (расходится). Реальные IIR-фильтры (Баттерворта, Чебышёва, эллиптические) проектируют, расставляя полюса и нули так, чтобы получить нужную АЧХ при минимальном порядке. IIR даёт крутые срезы дёшево, но платит нелинейной фазой и риском неустойчивости из-за конечной точности вычислений.

Частые ошибки

  • Не проверить устойчивость. Полюс вне единичной окружности — и фильтр расходится, выдавая бесконечность.
  • Игнорировать нелинейную фазу. IIR искажает форму сигнала; где важна форма, берут FIR или фильтруют «туда-обратно».
  • Высокий порядок одним блоком. Из-за округлений длинные IIR теряют устойчивость; их разбивают на каскад биквадов (секций 2-го порядка).

Итог

  • IIR использует обратную связь: выход зависит от прошлых выходов.
  • Импульсная характеристика бесконечна (затухает, но не обрывается).
  • IIR экономнее FIR: крутой фильтр — несколько коэффициентов.
  • Расплата — нелинейная фаза и риск неустойчивости (полюса вне единичной окружности).
Проверьте себя
1. Чем IIR-фильтр принципиально отличается от FIR?
AIIR быстрее за счёт БПФ
BIIR использует обратную связь — выход зависит от прошлых выходов
CIIR всегда устойчив
DIIR не использует свёртку
2. Почему у IIR импульсная характеристика бесконечна?
AИз-за ошибок округления
BИз-за обратной связи отклик на импульс затухает, но не обрывается
CПотому что ядро очень длинное
DЭто не так, она конечна
3. Когда однополюсный IIR y[n]=x[n]+a*y[n-1] устойчив?
AПри любом a
BПри |a| < 1 (полюс внутри единичной окружности)
CПри |a| > 1
DПри a = 0 только
4. Какова расплата за эффективность IIR?
AЛинейная фаза
BНелинейная фаза и риск неустойчивости
CБесконечная память
DНевозможность фильтровать