Цифровые фильтры: импульсная характеристика, КИХ и БИХ

Как описать любой линейный фильтр и предсказать, какие частоты он ослабит и насколько задержит?

Однополюсный фильтр (one-pole filter)однополюсный фильтр (one-pole filter) — Простейший рекурсивный фильтр: новый выход вычисляется из входного отсчёта и одного предыдущего выхода, y[n] = y[n−1] + a·(x[n] − y[n−1]). При коэффициенте a от 0 до 1 работает как фильтр нижних частот. описан в своей статье во времени: новый выход вычисляется из входного отсчёта (sample)отсчёт (sample) — Значение сигнала в один момент дискретизации, одно число. В звукозаписи его также называют сэмплом. и прошлого выхода. По такой формуле трудно сразу ответить, насколько фильтр ослабит синусоиду (sine)синус (sine) — Вертикальная координата точки на единичной окружности под заданным углом от положительного направления горизонтальной оси. Для острого угла прямоугольного треугольника равен отношению противолежащего катета к гипотенузе. 5 кГц и на сколько её задержит. Ответ дают средства, общие для всех линейных фильтров: импульсная характеристика и свёртка, частотная характеристика, передаточная функция с нулями и полюсами, групповая задержка. С их помощью разобраны фильтры с конечной и бесконечной импульсной характеристикой и биквад — фильтр второго порядка, из которого собирают эквалайзеры. В конце — класс Biquad на C++23 и фильтры JUCE. Понадобятся комплексные числа и формула Эйлера.

Линейность и инвариантность во времени

Фильтр превращает последовательность входных отсчётов x[n]x[n] в выходные y[n]y[n]. Всё, что сказано в статье дальше, верно для фильтров, которые линейны и инвариантны во времени.

Линейность (linearity): если вход x1x_1 даёт выход y1y_1, а вход x2x_2 — выход y2y_2, то вход c1x1+c2x2c_1x_1 + c_2x_2 даёт c1y1+c2y2c_1y_1 + c_2y_2 при любых числах c1c_1 и c2c_2 (Sundararajan, §2.3.2). Вдвое более громкий вход даёт вдвое более громкий выход, а сумма двух сигналов проходит фильтр так, будто каждый прошёл отдельно и выходы сложили. Инвариантность во времени (time invariance): если вход x[n]x[n] даёт y[n]y[n], то задержанный вход x[n−D]x[n - D] даёт тот же выход, задержанный на DD отсчётов (там же, §2.3.3). Коэффициенты фильтра не меняются, и ему всё равно, когда пришёл сигнал. Системы с обоими свойствами называют линейными инвариантными во времени (linear time-invariant, LTI).

Линейность проверяется на числах. Однополюсный фильтр с a=0,5a = 0{,}5 из нулевого состояния превращает вход 0,2; 0,2; 0,2 в 0,1; 0,15; 0,175, а вход 0,4; 0,4; 0,4 — в 0,2; 0,3; 0,35, ровно вдвое больше. Возведение в квадрат y[n]=x2[n]y[n] = x^2[n] так себя не ведёт: 0,2 даёт 0,04, а 0,4 — 0,16, вчетверо больше. Квадрат — нелинейная операция.

Поэтому компрессор (dynamic range compressor)компрессор (dynamic range compressor) — Устройство или программа, которая ослабляет сигнал, когда его уровень выше порога, и тем сужает динамический диапазон. и дисторшн к LTI-системам не относятся: у компрессора усиление зависит от уровня входа, у дисторшна выход — нелинейная функция входа, вроде среза (clipping)клиппинг (clipping) — Ограничение значений сигнала крайними допустимыми уровнями при выходе за диапазон. Срезает вершины волны и создаёт искажения.. Тремоло (tremolo)тремоло (tremolo) — Эффект периодического изменения амплитуды аудиосигнала. Скорость пульсации задаёт частота управляющего генератора, а диапазон усиления зависит от глубины и способа её преобразования. умножает сигнал на LFO (low-frequency oscillator, LFO)низкочастотный генератор (low-frequency oscillator, LFO) — Генератор медленно повторяющегося управляющего сигнала, которым изменяют параметры звука, например усиление, частоту или панораму. Общей строгой верхней границы частоты у LFO нет.: оно линейно, но не инвариантно во времени — отсчёт ослабляется по-разному в зависимости от фазы LFO в момент его прихода. Так же ведёт себя фильтр, у которого во время работы двигают частоту среза (cutoff frequency)частота среза (cutoff frequency) — Частота, выше которой фильтр нижних частот заметно ослабляет сигнал. У однополюсного фильтра при частоте среза много ниже fs/2 синусоида этой частоты ослабляется примерно на 3 дБ.: пока ручка неподвижна, это LTI-система, а пока её крутят — нет. К этому случаю статья вернётся в разделе о смене коэффициентов.

Импульсная характеристика и свёртка

Единичный импульс δ[n]\delta[n] — последовательность, в которой δ[0]=1\delta[0] = 1, а все остальные отсчёты равны нулю: цифровой щелчок. Импульсная характеристика (impulse response, IR)импульсная характеристика (impulse response, IR) — Отклик линейной инвариантной во времени системы на единичный импульс из нулевого состояния. Полностью описывает такую систему: выход на любой вход — свёртка входа с импульсной характеристикой. h[n]h[n] — выход фильтра на такой вход из нулевого состояния. У однополюсного фильтра y[n]=a x[n]+(1−a) y[n−1]y[n] = a\,x[n] + (1 - a)\,y[n-1] её легко посчитать по шагам: h[0]=ah[0] = a, h[1]=a(1−a)h[1] = a(1 - a), h[2]=a(1−a)2h[2] = a(1 - a)^2, и вообще h[n]=a(1−a)nh[n] = a(1 - a)^n. При частоте среза 1000 Гц и 48 кГц коэффициент a≈0,1227a \approx 0{,}1227, и первые отсчёты равны 0,1227; 0,1076; 0,0944; 0,0828 — каждый в 1−a≈0,8771 - a \approx 0{,}877 раза меньше предыдущего.

Свёртка

Любой вход можно записать как сумму задержанных импульсов с весами — значениями отсчётов. Вход 2, 1, 3, 4 — это 2δ[n]+δ[n−1]+3δ[n−2]+4δ[n−3]2\delta[n] + \delta[n-1] + 3\delta[n-2] + 4\delta[n-3]. Инвариантность во времени говорит, что импульс δ[n−k]\delta[n - k] даёт отклик h[n−k]h[n - k], а линейность — что отклик на сумму равен сумме откликов с теми же весами. Отсюда выход для любого входа (Sundararajan, §2.2, с. 47):

y[n]=∑kx[k] h[n−k]=∑kh[k] x[n−k]y[n] = \sum_{k} x[k]\,h[n - k] = \sum_{k} h[k]\,x[n - k]
h[k]h[k]
импульсная характеристика, отклик на единичный импульс;
kk
номер слагаемого; сумма идёт по всем kk, при которых оба множителя отличны от нуля.

Такая операция называется свёрткой (convolution)свёртка (convolution) — Операция y[n] = Σ h[k]·x[n−k]: каждый выходной отсчёт — сумма текущего и прошлых входных отсчётов с весами из импульсной характеристики. Так линейный инвариантный во времени фильтр вычисляет выход. и записывается y=x∗hy = x * h. Обе формы суммы дают одно и то же: от перестановки последовательностей свёртка не меняется. Вторая форма прямо задаёт вычисление: выход — это текущий и прошлые входы, взвешенные отсчётами импульсной характеристики.

Пример из учебника Sundararajan: hh = 3, 1, 2, 4 и xx = 2, 1, 3, 4. Отсчёт y[3]y[3] собирает четыре произведения: x[0]h[3]+x[1]h[2]+x[2]h[1]+x[3]h[0]=2⋅4+1⋅2+3⋅1+4⋅3=25x[0]h[3] + x[1]h[2] + x[2]h[1] + x[3]h[0] = 2 \cdot 4 + 1 \cdot 2 + 3 \cdot 1 + 4 \cdot 3 = 25. Весь выход — 6, 5, 14, 25, 14, 20, 16: свёртка последовательностей длиной NN и MM содержит N+M−1N + M - 1 отсчётов (Sundararajan, §2.2, с. 47–48). Проверка: сумма выхода, 100, равна произведению сумм входа и характеристики, 10⋅1010 \cdot 10.

Визуализация 1Свёртка по шагам
Свёртка: вход, развёрнутая импульсная характеристика и выход Вход x = 2, 1, 3, 4, импульсная характеристика h = 3, 1, 2, 4. Сверху входные отсчёты, посередине h[n − k] — характеристика, развёрнутая во времени и сдвинутая на n = 3; отмечены отсчёты, которые перемножаются. Внизу выход: сумма произведений даёт y[3], более поздние отсчёты ещё не посчитаны. y[3] = x[0]·h[3] + x[1]·h[2] + x[2]·h[1] + x[3]·h[0] = 2·4 + 1·2 + 3·1 + 4·3 = 25. Готовы отсчёты y[0] … y[3]: 6, 5, 14, 25. Всего у результата 7 = 4 + 4 − 1 отсчётов. Вход x[k]Импульсная характеристика h[n − k] при n = 3Выход y[n] = Σ x[k]·h[n − k]-3-2-10123456Номер отсчёта k или n21343124651425
  • отсчёты, которые перемножаются для y[n]
  • уже посчитанные отсчёты выхода
  • ещё не посчитанные

y[3] = x[0]·h[3] + x[1]·h[2] + x[2]·h[1] + x[3]·h[0] = 2·4 + 1·2 + 3·1 + 4·3 = 25.

Готовы отсчёты y[0] … y[3]: 6, 5, 14, 25. Всего у результата 7 = 4 + 4 − 1 отсчётов.

Вход, импульсная характеристика и шаг
3

Параметры работают с включённым JavaScript. Показано начальное состояние.

Рис. 1. Вход x = 2, 1, 3, 4, импульсная характеристика h = 3, 1, 2, 4. Сверху входные отсчёты, посередине h[n − k] — характеристика, развёрнутая во времени и сдвинутая на n = 3; отмечены отсчёты, которые перемножаются. Внизу выход: сумма произведений даёт y[3], более поздние отсчёты ещё не посчитаны.

В визуализации 1 характеристика развёрнута во времени: значение h[m]h[m] стоит под входом x[n−m]x[n - m]. С ростом nn она сдвигается вправо, и под ней оказываются всё новые входные отсчёты. В начальном состоянии n=3n = 3, перекрываются все четыре отсчёта, и сумма равна 25. Выберите вход «щелчок»: выход повторит hh, потому что импульсная характеристика и есть отклик на щелчок. С характеристикой «эхо» каждый входной отсчёт возвращается через три отсчёта вдвое тише — так работает линия задержки (delay line)линия задержки (delay line) — Блок обработки, который хранит последние отсчёты сигнала и выдаёт вход на заданное число отсчётов позже: y[n] = x[n − D]. На нём построены эхо, хорус, фленжер, реверберация и компенсация задержки. с прямой связью. Вход «скачок» с характеристикой «разность» даёт 1 в начале, −1 в конце и нули посередине: разность реагирует только на изменения.

Импульсная характеристика полностью описывает LTI-фильтр: зная hh, можно вычислить отклик на любой вход. На этом построен свёрточный ревербератор (convolution reverb)свёрточный ревербератор (convolution reverb) — Обработчик, применяющий сохранённую импульсную характеристику к входному сигналу для воспроизведения отклика помещения или устройства.: он хранит записанную импульсную характеристику помещения и сворачивает с ней сигнал. Характеристика зала длится секунды, это десятки тысяч отсчётов, и прямой расчёт по формуле (1) требует столько же умножений на каждый выходной отсчёт. Поэтому длинные свёртки считают через БПФ.

КИХ-фильтры

Если импульсная характеристика конечна, то есть после MM отсчётов идут только нули, формула (1) содержит MM слагаемых, и фильтр вычисляется прямо по ней: y[n]=b0x[n]+b1x[n−1]+…+bM−1x[n−M+1]y[n] = b_0x[n] + b_1x[n-1] + \ldots + b_{M-1}x[n - M + 1]. Такой фильтр называют КИХ-фильтром (finite impulse response filter, FIR)КИХ-фильтр (finite impulse response filter, FIR) — Фильтр с конечной импульсной характеристикой: выход — взвешенная сумма текущего и нескольких прошлых входов, без обратной связи. Всегда устойчив; при симметричных коэффициентах задерживает все частоты одинаково., фильтром с конечной импульсной характеристикой. Его коэффициенты и есть отсчёты hh: если подать щелчок, на выход по очереди выйдут b0b_0, b1b_1 и так далее (Sundararajan, §7.1, с. 230–231).

Простейший КИХ-фильтр — скользящее среднее MM отсчётов: все коэффициенты равны 1/M1/M. Среднее двух соседних отсчётов, y[n]=(x[n]+x[n−1])/2y[n] = (x[n] + x[n-1])/2, сглаживает сигнал: медленные изменения проходят почти без потерь, а чередование знаков +1, −1, +1 даёт на выходе ноль. Насколько ослабляются промежуточные частоты, покажет частотная характеристика.

КИХ-фильтр всегда устойчив: выход — сумма MM ограниченных слагаемых, и расти без предела ему нечем (Sundararajan, §7.1, с. 232). Зато ему нужно MM умножений на каждый отсчёт. Документация JUCE советует считать FIR::Filter по формуле, пока коэффициентов меньше 128, а более длинные характеристики — через БПФ в классе Convolution (juce_FIRFilter.h).

Если коэффициенты симметричны, bk=bM−1−kb_k = b_{M-1-k}, как у скользящего среднего, фильтр задерживает все частоты на одно и то же время, (M−1)/2(M - 1)/2 отсчётов. Это свойство называют линейной фазой; оно разобрано в разделе о задержке.

БИХ-фильтры

Однополюсный фильтр устроен иначе: его выход зависит от прошлого выхода. Общая запись фильтра с обратной связью (feedback)обратная связь (feedback) — Возврат части выходного сигнала на вход обработки. В delay повторно направляет копию через линию задержки и создаёт цепочку повторений. — разностное уравнение (Sundararajan, §2.3.1 и §2.7):

y[n]=∑k=0Mbk x[n−k]−∑k=1Nak y[n−k]y[n] = \sum_{k=0}^{M} b_k\,x[n - k] - \sum_{k=1}^{N} a_k\,y[n - k]
bkb_k
коэффициенты прямой части, при входе и его задержках;
aka_k
коэффициенты обратной связи, при прошлых выходах;
NN
порядок фильтра: сколько прошлых выходов он помнит.

Если хоть один aka_k отличен от нуля, импульсная характеристика бесконечна: каждый выход возвращается во все следующие. Такой фильтр называют БИХ-фильтром (infinite impulse response filter, IIR)БИХ-фильтр (infinite impulse response filter, IIR) — Фильтр с бесконечной импульсной характеристикой: в разностное уравнение входят прошлые выходы. Даёт крутой спад малым числом коэффициентов, устойчив, только если все полюсы внутри единичной окружности., фильтром с бесконечной импульсной характеристикой (Sundararajan, §2.7, с. 60). Знак минус перед второй суммой — соглашение, с которым проще выглядит передаточная функция; так записывают коэффициенты Sundararajan, RBJ Audio EQ Cookbook и JUCE. Однополюсный фильтр — БИХ-фильтр первого порядка с b0=ab_0 = a и a1=−(1−a)a_1 = -(1 - a). Здесь aa без индекса — коэффициент из статьи об однополюсном фильтре, а a1a_1 — коэффициент обратной связи; это разные величины.

Импульсные характеристики КИХ- и БИХ-фильтраДва графика друг под другом, по горизонтали номер отсчёта от 0 до 39, по вертикали значение от 0 до 0,25. Сверху четыре одинаковых столбика высотой 0,25 на отсчётах 0–3, дальше пусто. Снизу столбики начинаются с высоты около 0,12 и плавно убывают, к 39-му отсчёту почти сливаются с нулём. КИХ: среднее 4 отсчётов0,000,25010203039БИХ: однополюсный ФНЧ 1 кГц0,000,25010203039Номер отсчёта n
Рис. 2. Первые 40 отсчётов импульсной характеристики двух фильтров нижних частот при 48 кГц. У скользящего среднего четырёх отсчётов характеристика — четыре коэффициента по 0,25, дальше нули. У однополюсного фильтра с частотой среза 1 кГц она начинается с a ≈ 0,123 и убывает в 0,877 раза за отсчёт, но нулём не становится никогда.

Обратная связь экономит вычисления. Импульсная характеристика однополюсного фильтра с частотой среза 1000 Гц опускается на 60 дБ ниже первого отсчёта только через 53 отсчёта. КИХ-фильтру с той же характеристикой, обрезанной на этом уровне, понадобилось бы 53 умножения на отсчёт, а однополюсному хватает двух. При 200 Гц КИХ-фильтру понадобилось бы 264 умножения. Sundararajan подводит итог: фильтрам с обратной связью для тех же требований нужно меньше коэффициентов, но у них появляется вопрос устойчивости (Sundararajan, §2.7, с. 59).

Устойчивость

Фильтр устойчив, если ограниченный вход всегда даёт ограниченный выход (определение из статьи об однополюсном фильтре). Через импульсную характеристику условие записывается так: сумма модулей ∑n∣h[n]∣\sum_n |h[n]| конечна (Sundararajan, §2.5, с. 57). У КИХ-фильтра она конечна всегда. У однополюсного фильтра это геометрическая прогрессия a (1+∣1−a∣+∣1−a∣2+…)a\,(1 + |1 - a| + |1 - a|^2 + \ldots), и она конечна, только если ∣1−a∣<1|1 - a| < 1. При 1−a=1,11 - a = 1{,}1 каждый отсчёт характеристики на 10 % больше предыдущего, и через 1000 отсчётов он больше 104110^{41}. Общее правило для БИХ-фильтров любого порядка дают полюсы.

Частотная характеристика

Подадим на LTI-фильтр комплексную синусоиду x[n]=ejωnx[n] = e^{j\omega n}, где ω=2πf/fs\omega = 2\pi f/f_s — частота в радианах на отсчёт, а fsf_s — частота дискретизации (sample rate)частота дискретизации (sample rate) — Число отсчётов в каждом канале за одну секунду, то же число кадров аудиоданных в секунду. Измеряется в герцах: 44 100 Гц означает 44 100 отсчётов на канал в секунду. (вращающийся вектор). По формуле (1) выход равен ∑kh[k] ejω(n−k)=ejωn∑kh[k] e−jωk\sum_k h[k]\,e^{j\omega(n-k)} = e^{j\omega n}\sum_k h[k]\,e^{-j\omega k}. Вторая сумма не зависит от nn: это комплексное число (complex number)комплексное число (complex number) — Число вида a + jb, где a и b вещественные, а мнимая единица j удовлетворяет j² = −1. Изображается точкой или вектором на плоскости; модуль и аргумент хранят длину и угол, например амплитуду и фазу синусоиды., одно для каждой частоты (Sundararajan, §2.4, с. 56–57).

H(ejω)=∑kh[k] e−jωk,ω=2πffsH(e^{j\omega}) = \sum_{k} h[k]\,e^{-j\omega k}, \qquad \omega = \frac{2\pi f}{f_s}
H(ejω)H(e^{j\omega})
частотная характеристика: комплексный множитель для синусоиды частоты ω\omega;
ω\omega
частота, рад/отсчёт, от 0 до π\pi на частотах от 0 до fs/2f_s/2.

Синусоида выходит из фильтра той же частоты, умноженная на H(ejω)H(e^{j\omega}). Для вещественной синусоиды это значит: cos⁡(ωn)\cos(\omega n) превращается в ∣H∣cos⁡(ωn+arg⁡H)|H|\cos(\omega n + \arg H) — амплитуда умножается на модуль, к фазе прибавляется аргумент (Sundararajan, §2.4, с. 57). Модуль ∣H(ejω)∣|H(e^{j\omega})| как функцию частоты называют амплитудно-частотной характеристикой (magnitude response)амплитудно-частотная характеристика (magnitude response) — Зависимость модуля частотной характеристики |H(e^jω)| от частоты: во сколько раз фильтр меняет амплитуду синусоиды каждой частоты. Обычно рисуется в дБ., АЧХ (magnitude response), аргумент — фазочастотной, ФЧХ (phase response). АЧХ обычно рисуют в децибелах (decibel)децибел (decibel) — Логарифмическая единица отношения двух величин: для амплитуд L = 20 lg(A/A₀), для мощностей — 10 lg(P/P₀). Смысл числа задаёт опорная величина.: 20lg⁡∣H∣20\lg|H|.

Отсюда следует, что LTI-фильтр не создаёт новых частот. Каждая синусоида входа выходит той же частоты, меняются только её амплитуда (amplitude)амплитуда (amplitude) — Наибольший модуль отклонения колеблющейся величины от равновесного значения. Для синусоиды обозначается A; единицы совпадают с единицами сигнала. и фаза (phase)фаза (phase) — Положение внутри периода колебания, выраженное углом: полный период соответствует 360°, или 2π радиан. Начальная фаза — её значение в момент t = 0.. Новые частоты появляются только в нелинейной обработке: срез добавляет гармоники и комбинационные частоты.

У среднего двух отсчётов hh = 0,5; 0,5, и по формуле (3) H=(1+e−jω)/2H = (1 + e^{-j\omega})/2. Если вынести e−jω/2e^{-j\omega/2}, в скобках останется полусумма ejω/2+e−jω/2e^{j\omega/2} + e^{-j\omega/2}, то есть cos⁡(ω/2)\cos(\omega/2) по формуле Эйлера: H=e−jω/2cos⁡(ω/2)H = e^{-j\omega/2}\cos(\omega/2). АЧХ — cos⁡(ω/2)\cos(\omega/2): 1 на нулевой частоте, 1/2≈0,7071/\sqrt{2} \approx 0{,}707 (−3,01 дБ) на fs/4f_s/4 — 12 кГц при 48 кГц — и 0 на fs/2f_s/2. ФЧХ — прямая −ω/2-\omega/2: все частоты сдвинуты на половину отсчёта.

Проверка однополюсного фильтра

У однополюсного фильтра h[k]=a(1−a)kh[k] = a(1 - a)^k, и формула (3) — сумма геометрической прогрессии со знаменателем (1−a)e−jω(1 - a)e^{-j\omega}. Её модуль меньше 1, и сумма равна a/(1−(1−a)e−jω)a/\bigl(1 - (1 - a)e^{-j\omega}\bigr). Квадрат модуля:

∣H(ejω)∣2=a21−2(1−a)cos⁡ω+(1−a)2|H(e^{j\omega})|^2 = \frac{a^2}{1 - 2(1 - a)\cos\omega + (1 - a)^2}

В статье об однополюсном фильтре сказано: если частота среза много ниже fs/2f_s/2, синусоида этой частоты ослабляется примерно на 3 дБ. Теперь это можно проверить. Обозначим p=1−a=e−ωcp = 1 - a = e^{-\omega_c}, где ωc=2πfc/fs\omega_c = 2\pi f_c/f_s. Знаменатель формулы (4) равен (1−p)2+2p (1−cos⁡ω)(1 - p)^2 + 2p\,(1 - \cos\omega). При малой ωc\omega_c выполняется 1−p=a≈ωc1 - p = a \approx \omega_c и 1−cos⁡ωc≈ωc2/21 - \cos\omega_c \approx \omega_c^2/2, а p≈1p \approx 1. На частоте среза знаменатель близок к a2+ωc2≈2a2a^2 + \omega_c^2 \approx 2a^2, и ∣H∣2≈1/2|H|^2 \approx 1/2: ослабление 3 дБ. Приближение требует ωc≪1\omega_c \ll 1, то есть fc≪fs/(2π)f_c \ll f_s/(2\pi). Таблица 1 даёт точные значения по формуле (4).

Таблица 1. АЧХ однополюсного фильтра при 48 кГц по формуле (4): ослабление синусоиды на частоте среза и на fs/2. Совпадает с таблицей 1 и разделом об ограничениях статьи об однополюсном фильтре.
fc, ГцaОслабление на fc, дБОслабление на fs/2, дБ
2000,025843,01037,66
10000,122693,00423,69
50000,480302,85810,00

На fs/2f_s/2, где cos⁡ω=−1\cos\omega = -1, формула (4) даёт ∣H∣=a/(2−a)|H| = a/(2 - a): при частоте среза 1000 Гц ослабление всего 23,7 дБ, как и сказано в разделе об ограничениях. Рисунок 3 сравнивает оба фильтра.

АЧХ и ФЧХ среднего двух отсчётов и однополюсного фильтраДва графика друг под другом с общей осью частот от 0 до 24 кГц. Верхний, АЧХ от 0 до −30 дБ, с пунктиром на −3 дБ: сплошная кривая медленно опускается и у правого края уходит вниз; штриховая быстро падает в первом килогерце и дальше полого спускается к −24 дБ. Нижний, ФЧХ от 0 до −90°: сплошная прямая от 0 до −90°; штриховая быстро опускается примерно до −61° около 4 кГц и плавно возвращается к нулю. АЧХ, дБФЧХ, градусы0−10−20−300−45−9006121824−3 дБсреднее двуходнополюсныйЧастота, кГц
Рис. 3. АЧХ в дБ и ФЧХ в градусах при 48 кГц на линейной оси от 0 до 24 кГц. Среднее двух отсчётов (сплошная линия) спадает до −3 дБ на 12 кГц и до нуля на 24 кГц, его фаза убывает по прямой до −90°. Однополюсный фильтр с частотой среза 1 кГц (штриховая) проходит −3 дБ на 1 кГц и выходит на −23,7 дБ на 24 кГц; его фаза отстаёт сильнее всего на низких частотах и к 24 кГц возвращается к нулю.

Передаточная функция и z-преобразование

Частотная характеристика (3) — сумма степеней e−jωe^{-j\omega}. Если обозначить z=ejωz = e^{j\omega}, задержка на kk отсчётов превращается в множитель z−kz^{-k}. На этом построено z-преобразование (z-transform)z-преобразование (z-transform) — Запись последовательности x[n] выражением X(z) = Σ x[n]·z⁻ⁿ, в которой задержка на один отсчёт становится умножением на z⁻¹. Превращает разностное уравнение фильтра в передаточную функцию.: последовательности x[n]x[n] сопоставляют выражение X(z)=∑nx[n] z−nX(z) = \sum_n x[n]\,z^{-n}, где zz — комплексное число (Sundararajan, §6.1, с. 196–197). Для фильтров важно одно его свойство: задержке на один отсчёт соответствует умножение на z−1z^{-1}. Поэтому элемент задержки на схемах фильтров подписывают z−1z^{-1}. В учебниках к z-преобразованию добавляют условие, при каких zz сумма сходится; для чтения передаточных функций оно не понадобится.

Применим это к разностному уравнению (2): каждое слагаемое x[n−k]x[n-k] превращается в z−kX(z)z^{-k}X(z), каждое y[n−k]y[n-k] — в z−kY(z)z^{-k}Y(z). Перенесём выходы влево и поделим на X(z)X(z). Отношение называют передаточной функцией (transfer function)передаточная функция (transfer function) — Отношение H(z) = Y(z)/X(z) многочленов от z⁻¹ с коэффициентами разностного уравнения фильтра. Корни числителя — нули, корни знаменателя — полюсы; на единичной окружности z = e^jω она равна частотной характеристике. (Sundararajan, §6.3.2, с. 217):

H(z)=Y(z)X(z)=b0+b1z−1+…+bMz−M1+a1z−1+…+aNz−NH(z) = \frac{Y(z)}{X(z)} = \frac{b_0 + b_1 z^{-1} + \ldots + b_M z^{-M}}{1 + a_1 z^{-1} + \ldots + a_N z^{-N}}

Числитель и знаменатель — многочлены, коэффициенты которых совпадают с коэффициентами разностного уравнения. На единичной окружности, при z=ejωz = e^{j\omega}, передаточная функция совпадает с частотной характеристикой (3) (Sundararajan, §6.1, с. 196).

Нули и полюсы

Корни числителя называют нулями (zeros): в них H(z)=0H(z) = 0. Корни знаменателя называют полюсами (poles): знаменатель там обращается в ноль, и H(z)H(z) бесконечна. Их рисуют на комплексной плоскости zz: нуль — кружком, полюс — крестиком. Точки единичной окружности соответствуют частотам: угол 0 — постоянной составляющей, π/2\pi/2 — частоте fs/4f_s/4, π\pi — частоте fs/2f_s/2, частоте Найквиста (Nyquist frequency)частота Найквиста (Nyquist frequency) — Половина частоты дискретизации, fₛ/2. В принятой низкочастотной модели точное восстановление по отсчётам требует, чтобы все частоты исходного сигнала были строго ниже этой границы.. Нижняя половина окружности — отрицательные частоты. У фильтра с вещественными коэффициентами комплексные нули и полюсы стоят парами, симметрично относительно вещественной оси (комплексные корни квадратного уравнения).

Положение нулей и полюсов объясняет форму АЧХ. Модуль ∣H(ejω)∣|H(e^{j\omega})| пропорционален произведению расстояний от точки ejωe^{j\omega} на окружности до нулей, делённому на произведение расстояний до полюсов (Bellanger, §6.2, с. 128). Когда частота проходит мимо нуля, лежащего у окружности, расстояние до него мало, и в АЧХ провал; нуль на самой окружности полностью подавляет свою частоту. Когда частота проходит мимо полюса у окружности, в АЧХ пик, и чем ближе полюс к окружности, тем он выше (Bellanger, §6.2, с. 129–130).

У среднего двух отсчётов H(z)=(1+z−1)/2=(z+1)/(2z)H(z) = (1 + z^{-1})/2 = (z + 1)/(2z): нуль в точке z=−1z = -1, то есть на fs/2f_s/2, где АЧХ обнулилась, и полюс в начале координат. До начала координат от любой точки окружности расстояние 1, и на АЧХ он не влияет. У однополюсного фильтра H(z)=a/(1−(1−a)z−1)=az/(z−(1−a))H(z) = a/\bigl(1 - (1 - a)z^{-1}\bigr) = az/\bigl(z - (1 - a)\bigr): полюс на вещественной оси в точке z=1−az = 1 - a, при частоте среза 1000 Гц — в точке 0,877. Он стоит у угла 0, рядом с низкими частотами, поэтому фильтр их пропускает лучше, чем высокие.

Отсюда общее условие устойчивости: фильтр устойчив, если все его полюсы лежат внутри единичной окружности, ∣p∣<1|p| < 1 (Sundararajan, §6.3.2, с. 218). У однополюсного фильтра это ∣1−a∣<1|1 - a| < 1 — то же условие, что получилось из прогрессии. У КИХ-фильтра знаменатель равен 1, все его полюсы в начале координат, и он устойчив всегда.

Фазовая и групповая задержка

ФЧХ даёт фазовый сдвиг в радианах, а знать удобнее задержку во времени. Для этого есть две величины (J. O. Smith, Phase and Group Delay):

τφ(ω)=−φ(ω)ω,τg(ω)=−dφdω\tau_\varphi(\omega) = -\frac{\varphi(\omega)}{\omega}, \qquad \tau_g(\omega) = -\frac{d\varphi}{d\omega}
φ(ω)\varphi(\omega)
ФЧХ, arg⁡H(ejω)\arg H(e^{j\omega}), рад;
τφ\tau_\varphi, τg\tau_g
фазовая и групповая задержка, отсчётов; в секундах — после деления на fsf_s.

Фазовая задержка показывает, на сколько отсчётов сдвинута синусоида частоты ω\omega. Групповая задержка (group delay)групповая задержка (group delay) — Производная фазочастотной характеристики по частоте с обратным знаком, −dφ/dω. Показывает, на сколько задерживается огибающая сигнала в узкой полосе около данной частоты. — производная фазы по частоте с обратным знаком. Она показывает задержку огибающей (envelope)огибающая (envelope) — Плавная кривая, которая следует за размахом волны и показывает, как уровень сигнала меняется во времени.: короткой пачки колебаний около частоты ω\omega, «группы» близких синусоид (J. O. Smith, Group Delay). Удар барабана и начало ноты — именно такие огибающие.

Если ФЧХ — прямая φ(ω)=−Dω\varphi(\omega) = -D\omega, обе задержки равны DD отсчётам на всех частотах. Тогда составляющие сигнала в полосе пропускания задержаны одинаково, и форма сигнала сохраняется: он просто приходит позже (Sundararajan, §7.2, с. 237). У среднего двух отсчётов φ=−ω/2\varphi = -\omega/2, задержка — половина отсчёта, при 48 кГц это 10,4 мкс.

Линейная фаза

У КИХ-фильтра с симметричными коэффициентами длины MM ФЧХ — прямая с наклоном −(M−1)/2-(M - 1)/2, а групповая задержка постоянна и равна (M−1)/2(M - 1)/2 отсчётов (Sundararajan, §7.2, с. 235–237). На частотах, где АЧХ проходит через ноль, фаза скачком меняется на π\pi, но прямой наклон и задержка от этого не меняются. У скользящего среднего восьми отсчётов задержка 3,5 отсчёта. Такие фильтры называют линейно-фазовыми.

У БИХ-фильтров ФЧХ — не прямая, и групповая задержка зависит от частоты. У однополюсного фильтра с частотой среза 1000 Гц она равна 7,15 отсчёта на нулевой частоте, 3,33 на 1 кГц, 1,04 на 2 кГц, а на 10 кГц становится даже немного отрицательной, −0,41. Групповая задержка описывает огибающую узкой полосы частот, а не момент, когда на выходе появляется сигнал, поэтому бывает и отрицательной; такие значения Bellanger отмечает и у секции второго порядка (Bellanger, §6.2, с. 131). Низкие частоты такой фильтр задерживает сильнее высоких.

Отклик на щелчок линейно-фазового КИХ-фильтра и биквадаДва графика друг под другом, по горизонтали номер отсчёта от 0 до 89. Сверху: до отсчёта 10 ноль, дальше мелкие колебания, растущие к узкому пику на отсчёте 41, после пика такие же затухающие колебания до отсчёта 72. Снизу: ноль до отсчёта 10, затем быстрый подъём к пику на отсчёте 14 и плавный спад с небольшим провалом ниже нуля. Линейно-фазовый КИХ, 63 отсчётов0,00,1020406080Биквад, Q = 0,7070,00,1020406080щелчокНомер отсчёта n
Рис. 4. Два фильтра нижних частот с частотой среза 2 кГц при 48 кГц, на вход подан щелчок в отсчёте 10 (вертикальный пунктир). Линейно-фазовый КИХ-фильтр — функция sinc, умноженная на окно Ханна, 63 коэффициента — симметричен: пик выхода через 31 отсчёт после щелчка, а колебания амплитудой до 10 % пика идут и до него, и после. Биквад с Q = 0,707 откликается сразу, пик через 4 отсчёта, колебания только после пика.

Недостатки линейной фазы видны на рисунке 4. Симметричная импульсная характеристика начинается до своего пика, поэтому выход начинает колебаться раньше, чем приходит основная часть отклика: это предзвон (pre-ringing). На ударных он размывает атаку: руководство FabFilter Pro-Q предупреждает, что в линейно-фазовом режиме бочка может потерять резкость. Второй недостаток — задержка (latency)задержка (latency) — Время прохождения сигнала через тракт от входа до выхода. Включает буферизацию, драйвер, преобразователи и алгоритмы; длительность одного блока не равна полной задержке. (M−1)/2(M - 1)/2 отсчётов: у фильтра из 4097 коэффициентов это 2048 отсчётов, 42,7 мс при 48 кГц. Хост выравнивает дорожки компенсацией задержки (delay compensation)компенсация задержки (delay compensation) — Выравнивание путей сигнала по времени: программа узнаёт задержку плагинов и задерживает остальные дорожки на недостающую величину., но играть через такой эквалайзер в реальном времени неудобно. Обычный эквалайзер на БИХ-фильтрах откликается сразу и без предзвона, зато сдвигает фазу около изменённой полосы.

Биквад

Фильтр второго порядка помнит два прошлых входа и два прошлых выхода:

y[n]=b0x[n]+b1x[n−1]+b2x[n−2]−a1y[n−1]−a2y[n−2],H(z)=b0+b1z−1+b2z−21+a1z−1+a2z−2y[n] = b_0x[n] + b_1x[n-1] + b_2x[n-2] - a_1y[n-1] - a_2y[n-2], \qquad H(z) = \frac{b_0 + b_1z^{-1} + b_2z^{-2}}{1 + a_1z^{-1} + a_2z^{-2}}

Передаточная функция — отношение двух квадратных многочленов, поэтому фильтр называют биквадратным, коротко биквадом (biquad) (J. O. Smith, BiQuad Section). У него два нуля и два полюса. Фильтры высокого порядка на практике раскладывают в цепочку секций первого и второго порядка: в одной большой формуле ошибки округления коэффициентов сильно сдвигают нули и полюсы (Sundararajan, §8.4, с. 315–318). Прямые формы выше второго порядка поэтому почти не используют (Zavalishin, §3.11, с. 81). Каждая полоса параметрического эквалайзера (parametric equalizer)параметрический эквалайзер (parametric equalizer) — Эквалайзер, у полос которого плавно регулируются центральная частота, усиление и ширина полосы. — один биквад.

Полюсы и добротность

Пусть полюсы — пара сопряжённых чисел re±jθre^{\pm j\theta}. По формуле корней квадратного уравнения знаменатель z2+a1z+a2z^2 + a_1z + a_2 задают коэффициенты (Bellanger, §6.2, с. 128–129):

a1=−2rcos⁡θ,a2=r2,Q≈θ2(1−r)a_1 = -2r\cos\theta, \qquad a_2 = r^2, \qquad Q \approx \frac{\theta}{2(1 - r)}
rr
радиус полюсов, расстояние от начала координат, без единиц;
θ\theta
угол полюсов, рад; частота θfs/(2π)\theta f_s/(2\pi), Гц;
QQ
добротность резонанса, приближённо для rr, близкого к 1.

Угол θ\theta задаёт частоту резонанса, а радиус rr — его остроту. Подъём АЧХ на резонансе обратно пропорционален расстоянию от полюса до окружности, 1−r1 - r (Bellanger, §6.2, с. 129–130). Ширина резонанса по уровню −3 дБ при rr, близком к 1, равна B≈−ln⁡r⋅fs/π≈(1−r)fs/πB \approx -\ln r \cdot f_s/\pi \approx (1 - r)f_s/\pi (J. O. Smith, Resonator Bandwidth). Добротность (quality factor, Q)добротность (quality factor, Q) — Отношение центральной частоты полосы к её ширине между частотами среза. Чем больше добротность, тем уже полоса. — отношение частоты к ширине полосы, Q=f0/BQ = f_0/B. Подставив f0=θfs/(2π)f_0 = \theta f_s/(2\pi), получим приближение в формуле (8): чем ближе полюсы к окружности, тем выше добротность.

Коэффициенты по частоте среза f0f_0 и добротности даёт кулинарная книга Роберта Бристоу-Джонсона, RBJ Audio EQ Cookbook (W3C). Для фильтра нижних частот (low-pass filter, LPF)фильтр нижних частот (low-pass filter, LPF) — Фильтр, который пропускает низкие частоты и ослабляет высокие. Перед дискретизацией помогает ограничить спектр входного сигнала.:

ω0=2πf0fs,α=sin⁡ω02Q,b0=b2=1−cos⁡ω02,b1=1−cos⁡ω0,a0=1+α,a1=−2cos⁡ω0,a2=1−α\begin{gathered} \omega_0 = \frac{2\pi f_0}{f_s}, \qquad \alpha = \frac{\sin\omega_0}{2Q}, \\ b_0 = b_2 = \frac{1 - \cos\omega_0}{2}, \quad b_1 = 1 - \cos\omega_0, \quad a_0 = 1 + \alpha, \quad a_1 = -2\cos\omega_0, \quad a_2 = 1 - \alpha \end{gathered}
f0f_0
частота среза, Гц;
a0a_0
делитель: все пять остальных коэффициентов делят на него, чтобы получить вид (7).

Для фильтра верхних частот (high-pass filter, HPF)фильтр верхних частот (high-pass filter, HPF) — Фильтр, который пропускает частоты выше частоты среза и ослабляет частоты ниже неё. В сведении убирает гул и низкочастотные помехи. меняется только числитель: b0=b2=(1+cos⁡ω0)/2b_0 = b_2 = (1 + \cos\omega_0)/2, b1=−(1+cos⁡ω0)b_1 = -(1 + \cos\omega_0). Числитель ФНЧ равен b0(1+z−1)2b_0(1 + z^{-1})^2: два нуля в точке z=−1z = -1, поэтому на fs/2f_s/2 АЧХ обнуляется. У ФВЧ оба нуля в точке z=1z = 1, на нулевой частоте. Формулы получены билинейным преобразованием аналогового фильтра с поправкой на искажение оси частот, поэтому частота f0f_0 стоит точно там, где задана (W3C, разд. 2). Формулы колокола и полок той же книги нужны эквалайзеру, их разберёт отдельная статья.

Таблица 2. ФНЧ RBJ с частотой среза 1 кГц при 48 кГц: полюсы и АЧХ при разной добротности. Ширина B — по радиусу полюса, B = −ln r · fs/π; при Q = 0,707 приближение не работает и дано для сравнения. Значения посчитаны кодом визуализации 5.
QРадиус rЧастота полюса, ГцАЧХ на 1 кГц, дБПик АЧХ, дБПик на, ГцB, Гц
0,7070,9116709−3,010,0001414
20,96799696,026,30936499
50,987099513,9814,02990199
100,993599920,0020,0199899,7

На частоте среза АЧХ ФНЧ RBJ равна QQ: 20lg⁡0,707=−3,0120\lg 0{,}707 = -3{,}01 дБ, 20lg⁡5=13,9820\lg 5 = 13{,}98 дБ. При Q=5Q = 5 и 10 ширина по радиусу полюса воспроизводит добротность: 1000/199≈5,01000/199 \approx 5{,}0 и 1000/99,7≈10,01000/99{,}7 \approx 10{,}0. При Q=0,707Q = 0{,}707 полюсы далеко от окружности, пика нет: АЧХ ровная почти до частоты среза, а за ней спадает примерно на 12 дБ на октаву (octave)октава (octave) — Музыкальный интервал между нотами одного названия в соседних регистрах. Соответствует отношению частот 2:1. — от 2 до 4 кГц на 12,1 дБ. Однополюсный фильтр спадает на 6 дБ на октаву.

Визуализация 5Нули и полюса
z-плоскость: нули и полюсы Полюсы r = 0,912, θ = 5,3° (709 Гц), сопряжённая пара под осью. Нули r = 1,000, θ = 180,0° (24,0 кГц). Полюсы внутри единичной окружности. 012 кГц24 кГцReIm
АЧХ, ФЧХ и импульсная характеристика биквада Биквад при 48 кГц: пара полюсов r = 0,912, θ = 5,3° (709 Гц) и пара нулей r = 1,000, θ = 180,0° (24,0 кГц). На z-плоскости с единичной окружностью угол точки соответствует частоте: от 0 справа до fs/2 = 24 кГц слева. На графиках АЧХ в дБ на логарифмической оси частот, ФЧХ и первые 200 отсчётов импульсной характеристики, тем же расчётом, что класс Biquad из раздела о коде. Полюсы: r = 0,912, θ = 5,3° (709 Гц). Нули: r = 1,000, θ = 180,0° (24,0 кГц). b0 = 0,003916, b1 = 0,007832, b2 = 0,003916, a1 = −1,815341, a2 = 0,831006; множитель числителя подобран так, что пик АЧХ равен 0 дБ. Фильтр устойчив: полюсы внутри окружности. Пик АЧХ на 0 Гц; полюсы далеко от окружности, и оценка Q по радиусу неточна. АЧХ |H|, дБ0−20−40−60ФЧХ arg H, градусы180900−90−180202050501001002002005005001 к1 к2 к2 к5 к5 к10 к10 к20 к20 кЧастота, ГцИмпульсная характеристика h[n], наибольший модуль 0,0595050100150199Номер отсчёта n
  • полюс
  • нуль
  • единичная окружность |z| = 1

Полюсы: r = 0,912, θ = 5,3° (709 Гц). Нули: r = 1,000, θ = 180,0° (24,0 кГц).

b0 = 0,003916, b1 = 0,007832, b2 = 0,003916, a1 = −1,815341, a2 = 0,831006; множитель числителя подобран так, что пик АЧХ равен 0 дБ.

Фильтр устойчив: полюсы внутри окружности. Пик АЧХ на 0 Гц; полюсы далеко от окружности, и оценка Q по радиусу неточна.

Нули, полюсы и прослушивание

Перетащите крестик или кружок на плоскости: пара под осью следует за ним зеркально. Те же положения задают ползунки.

0,912
709 Гц
1,000
24,0 кГц

Громкость. Розовый шум звучит резко, а узкий резонанс выделяет почти чистый тон: перед запуском убавьте громкость, особенно в наушниках.

30 %

Остановлен

Параметры и звук работают с включённым JavaScript. Показано начальное состояние.

Рис. 5. Биквад при 48 кГц: пара полюсов r = 0,912, θ = 5,3° (709 Гц) и пара нулей r = 1,000, θ = 180,0° (24,0 кГц). На z-плоскости с единичной окружностью угол точки соответствует частоте: от 0 справа до fs/2 = 24 кГц слева. На графиках АЧХ в дБ на логарифмической оси частот, ФЧХ и первые 200 отсчётов импульсной характеристики, тем же расчётом, что класс Biquad из раздела о коде.

В начальном состоянии визуализации 5 — ФНЧ RBJ с Q=0,707Q = 0{,}707: два нуля в точке −1-1 и полюсы с радиусом 0,912 на 709 Гц. Потяните полюс к окружности: на АЧХ появится пик, в импульсной характеристике — затухающие колебания его частоты, а в розовом шуме (pink noise)розовый шум (pink noise) — Шум, PSD которого приблизительно обратно пропорциональна частоте в рабочей полосе: спад около 3 дБ на октаву и примерно одинаковая мощность октав. — слышимый призвук. Пример «ФНЧ 1 кГц, Q = 5» ставит полюсы на радиус 0,987. Пример «Режекция 1 кГц» сажает нули на окружность у 1 кГц, а полюсы — рядом, на радиус 0,98: нули дают глубокий провал, полюсы сужают его, и остальные частоты почти не меняются. Так устроен режекторный фильтр (notch filter)режекторный фильтр (notch filter) — Фильтр с очень узким провалом, который убирает одну частоту и почти не трогает соседние, например фон сети или резонанс.. Вытащите полюс за окружность: импульсная характеристика начнёт расти, а звук отключится.

Прямая форма I и транспонированная прямая форма II

Одно и то же разностное уравнение (7) можно вычислять по-разному. Прямая форма I (direct form I, DF-I) считает его как написано и хранит четыре состояния: x[n−1]x[n-1], x[n−2]x[n-2], y[n−1]y[n-1], y[n−2]y[n-2]. Задержек вдвое больше необходимого, зато в целочисленной арифметике с дополнительным кодом внутренних переполнений не бывает, пока выход в допустимых пределах (J. O. Smith, Direct-Form I). Кулинарная книга RBJ называет её лучшим и простейшим способом для процессоров с аккумулятором двойной длины (W3C, разд. 2).

Транспонированная прямая форма II (transposed direct form II, TDF-II) обходится двумя состояниями (Sundararajan, §8.4, с. 317):

y[n]=b0x[n]+s1[n−1]s1[n]=b1x[n]−a1y[n]+s2[n−1]s2[n]=b2x[n]−a2y[n]\begin{aligned} y[n] &= b_0x[n] + s_1[n-1] \\ s_1[n] &= b_1x[n] - a_1y[n] + s_2[n-1] \\ s_2[n] &= b_2x[n] - a_2y[n] \end{aligned}
s1s_1, s2s_2
состояния: уже посчитанные части будущих выходов.

Транспонирование схемы не меняет передаточной функции (J. O. Smith, Transposed Direct-Forms). Подставив s1s_1 и s2s_2 в первую строку, можно убедиться, что y[n]y[n] совпадает с формулой (7). Для точности у TDF-II есть преимущество: нули в ней фактически стоят раньше полюсов, и большое усиление, которое дают одни полюсы, нули частично компенсируют ещё до них (J. O. Smith, Numerical Robustness of TDF-II). По этой схеме работает juce::dsp::IIR::Filter (juce_IIRFilter.h).

Смена коэффициентов на ходу

Всё сказанное верно, пока коэффициенты постоянны. Но ручку частоты среза крутят во время звучания, а LFO качает фильтр синтезатора. Состояния TDF-II — смесь прошлых входов и выходов, взвешенная старыми коэффициентами; после смены коэффициентов они уже не соответствуют новому фильтру. Фильтры с одинаковой передаточной функцией, но разной структурой при модуляции ведут себя по-разному (Zavalishin, §3.11, с. 81). Документация IIR::Filter для быстрой модуляции частоты среза советует фильтр переменных состояний, рассчитанный на это (juce_IIRFilter.h).

Разницу видно в опыте. Белый шум (white noise)белый шум (white noise) — Шум с постоянной спектральной плотностью мощности в рассматриваемой полосе. Полосы одинаковой ширины в герцах содержат одинаковую ожидаемую мощность. с размахом ±0,5 длительностью 1 с пропущен через три ФНЧ с одними и теми же коэффициентами в каждый момент: TDF-II, DF-I и фильтр переменных состояний из следующего раздела. Частота среза качается по синусоиде между 125 Гц и 8 кГц, на три октавы вверх и вниз от 1 кГц.

Таблица 3. Наибольший модуль выхода трёх ФНЧ при модуляции частоты среза между 125 Гц и 8 кГц. Вход — белый шум ±0,5, 1 с, 48 кГц. Расчёт тем же кодом, что визуализация 5.
Частота модуляции, ГцQTDF-IIDF-IПеременных состояний
551,521,521,52
50057,788,391,75
2000520,119,51,38
2000202,8·10¹⁹⁰3,7·10¹⁹¹2,66

При медленной модуляции три структуры дают одинаковый выход: в каждый момент фильтр почти неподвижен, и плавная автоматизация не вредит ни одной из них. При модуляции 500 Гц выход прямых форм в 4–5 раз выше, чем у фильтра переменных состояний, а при 2000 Гц и Q=20Q = 20 он уходит в бесконечность, хотя каждый «замороженный» фильтр устойчив. Для быстрой модуляции нужна другая структура.

Фильтр переменных состояний

Фильтр переменных состояний (state variable filter, SVF) — модель аналоговой схемы из двух интеграторов в общей петле обратной связи. Один расчёт даёт сразу три выхода: фильтры верхних и нижних частот и полосовой (Zavalishin, §4.1, с. 95–96). Цифровую версию строят методом TPT (topology-preserving transform): каждый интегратор схемы заменяют цифровым, а связи между ними оставляют как есть. Состояния фильтра — выходы интеграторов, а не взвешенные суммы прошлых отсчётов, и при модуляции он ведёт себя как аналоговый прототип (Zavalishin, §3.11, с. 81). Один шаг такого фильтра в JUCE выглядит так (juce_StateVariableTPTFilter.cpp):

g=tan⁡πfcfs,h=11+g/Q+g2,yHP=h(x−(g+1/Q) s1−s2),yBP=g yHP+s1,yLP=g yBP+s2,s1←g yHP+yBP,s2←g yBP+yLP\begin{gathered} g = \tan\frac{\pi f_c}{f_s}, \qquad h = \frac{1}{1 + g/Q + g^2}, \\ y_{HP} = h\bigl(x - (g + 1/Q)\,s_1 - s_2\bigr), \quad y_{BP} = g\,y_{HP} + s_1, \quad y_{LP} = g\,y_{BP} + s_2, \\ s_1 \leftarrow g\,y_{HP} + y_{BP}, \qquad s_2 \leftarrow g\,y_{BP} + y_{LP} \end{gathered}

Без модуляции ФНЧ переменных состояний с теми же частотой среза и QQ имеет ту же передаточную функцию, что ФНЧ RBJ: на белом шуме их выходы в коде из раздела о JUCE расходятся не больше чем на 9⋅10−89 \cdot 10^{-8}. Разница появляется только при смене параметров. У полюсов сохраняется смысл формулы (8), поэтому параметр resonance в JUCE — это и есть QQ: на частоте среза АЧХ равна 1/(2R)1/(2R), а JUCE вычисляет 2R2R как 1 / resonance (Zavalishin, §4.1, с. 97; juce_StateVariableTPTFilter.h).

Код на C++

Класс Biquad

Класс считает формулу (10) и хранит пять коэффициентов отдельно от двух состояний. Функция makeRbjFilter вычисляет коэффициенты ФНЧ и ФВЧ по формуле (9), а метод response — частотную характеристику по формуле (7) при z=ejωz = e^{j\omega}. Нужна только стандартная библиотека C++23.

C++
// Биквад в транспонированной прямой форме II и коэффициенты ФНЧ и ФВЧ по RBJ Audio EQ Cookbook.
#include <cmath>
#include <complex>
#include <numbers>

struct BiquadCoefficients
{
    double b0 = 1.0; // числитель
    double b1 = 0.0;
    double b2 = 0.0;
    double a1 = 0.0; // знаменатель, a0 = 1
    double a2 = 0.0;
};

// ФНЧ (lowPass = true) или ФВЧ второго порядка; все коэффициенты делятся на a0.
inline BiquadCoefficients makeRbjFilter (double sampleRate, double cutoffHz, double q, bool lowPass)
{
    const auto w0 = 2.0 * std::numbers::pi * cutoffHz / sampleRate;
    const auto cosW0 = std::cos (w0);
    const auto alpha = std::sin (w0) / (2.0 * q);
    const auto a0 = 1.0 + alpha;
    const auto edge = (lowPass ? 1.0 - cosW0 : 1.0 + cosW0) / 2.0; // b0 = b2

    return { .b0 = edge / a0,
             .b1 = (lowPass ? 2.0 : -2.0) * edge / a0,
             .b2 = edge / a0,
             .a1 = -2.0 * cosW0 / a0,
             .a2 = (1.0 - alpha) / a0 };
}

class Biquad
{
public:
    void setCoefficients (const BiquadCoefficients& newCoefficients) noexcept { c = newCoefficients; }
    void reset() noexcept { s1 = s2 = 0.0; }

    // y[n] = b0·x[n] + s1; s1 и s2 хранят ещё не сложенные части будущих выходов.
    float processSample (float input) noexcept
    {
        const auto x = static_cast<double> (input);
        const auto y = c.b0 * x + s1;
        s1 = c.b1 * x - c.a1 * y + s2;
        s2 = c.b2 * x - c.a2 * y;
        return static_cast<float> (y);
    }

    // H(e^jω) = (b0 + b1·e^−jω + b2·e^−2jω) / (1 + a1·e^−jω + a2·e^−2jω)
    std::complex<double> response (double frequencyHz, double sampleRate) const
    {
        const auto z1 = std::polar (1.0, -2.0 * std::numbers::pi * frequencyHz / sampleRate);
        const auto z2 = z1 * z1;
        return (c.b0 + c.b1 * z1 + c.b2 * z2) / (1.0 + c.a1 * z1 + c.a2 * z2);
    }

private:
    BiquadCoefficients c;   // параметры фильтра
    double s1 = 0.0;        // состояние, меняется каждый отсчёт
    double s2 = 0.0;
};

makeRbjFilter возвращает структуру через назначенные инициализаторы (C++20, designated initializers): имя каждого поля видно рядом со значением. Состояния хранятся в double: у резонансного фильтра полюсы близки к окружности, и ошибки округления float в обратной связи заметнее. Чтобы сменить частоту, достаточно вызвать setCoefficients; состояния при этом не сбрасываются, со всеми последствиями из раздела о смене коэффициентов.

Код собран clang++ -std=c++23 -Wall -Wextra -pedantic -Wconversion без предупреждений. Для ФНЧ 1 кГц с Q=0,7071Q = 0{,}7071 при 48 кГц response даёт 0,00 дБ на 100 Гц, −3,01 дБ на 1 кГц, −12,37 дБ на 2 кГц и −24,48 дБ на 4 кГц, а первые отсчёты импульсной характеристики — 0,003916; 0,014941; 0,027785. ФВЧ с теми же параметрами на 100 Гц даёт −40,03 дБ, а при Q=5Q = 5 ФНЧ поднимает частоту среза на 13,98 дБ, как в таблице 2.

Фильтры JUCE

В модуле juce_dsp есть КИХ- и БИХ-фильтры и фильтр переменных состояний. Класс ниже готовит биквад для двух каналов, КИХ-фильтр скользящего среднего и фильтр переменных состояний; процессор вызывает prepare из prepareToPlay и process из processBlock.

C++
// Три фильтра JUCE в одном классе: биквад для двух каналов, КИХ и фильтр переменных состояний.
#include <juce_dsp/juce_dsp.h>

class FilterSection
{
public:
    void prepare (double sampleRate, int maxBlockSize)
    {
        const juce::dsp::ProcessSpec stereo { sampleRate, static_cast<juce::uint32> (maxBlockSize), 2 };
        setLowPass (sampleRate, 1000.0f, 0.707f);
        lowPass.prepare (stereo);

        // Скользящее среднее четырёх отсчётов; FIR::Filter обрабатывает только один канал.
        const std::array<float, 4> taps { 0.25f, 0.25f, 0.25f, 0.25f };
        average.coefficients = new juce::dsp::FIR::Coefficients<float> (taps.data(), taps.size());
        average.prepare ({ sampleRate, static_cast<juce::uint32> (maxBlockSize), 1 });

        sweep.setType (juce::dsp::StateVariableTPTFilterType::lowpass);
        sweep.setCutoffFrequency (1000.0f);
        sweep.setResonance (0.707f); // в JUCE resonance — это Q
        sweep.prepare (stereo);
    }

    // Новые коэффициенты без выделения памяти: массив копируется в готовый объект Coefficients.
    void setLowPass (double sampleRate, float cutoffHz, float q)
    {
        *lowPass.state = juce::dsp::IIR::ArrayCoefficients<float>::makeLowPass (sampleRate, cutoffHz, q);
    }

    void process (juce::AudioBuffer<float>& buffer)
    {
        juce::dsp::AudioBlock<float> block { buffer };
        lowPass.process (juce::dsp::ProcessContextReplacing<float> { block });
    }

    juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<float>, juce::dsp::IIR::Coefficients<float>> lowPass;
    juce::dsp::FIR::Filter<float> average;
    juce::dsp::StateVariableTPTFilter<float> sweep;
};

IIR::Filter обрабатывает один канал, а ProcessorDuplicator создаёт по фильтру на канал и даёт им общий объект коэффициентов state. Coefficients::makeLowPass возвращает новый объект в динамической памяти, а ArrayCoefficients::makeLowPass — массив из шести чисел. Присваивание массива копирует его в уже существующий объект: конструктор Coefficients заранее резервирует место под восемь чисел, поэтому setLowPass можно вызывать и в аудиопотоке (audio thread)аудиопоток (audio thread) — Поток с повышенным приоритетом, который вызывает обработку звука для каждого блока. Каждый вызов должен закончиться до срока блока, поэтому в нём не выделяют память, не берут блокировки и не обращаются к диску. (juce_IIRFilter.h и .cpp). Безопасность смены коэффициентов между потоками JUCE оставляет вызывающему коду, поэтому setLowPass удобно вызывать в начале process, когда изменился параметр. Формулы makeLowPass в JUCE записаны через tan⁡(πf0/fs)\tan(\pi f_0/f_s), но дают те же коэффициенты, что формула (9).

FIR::Filter обрабатывает один канал: для стерео (stereo)стерео (stereo) — Аудиоформат с двумя каналами, обычно левым и правым. Кадр несжатых стереоданных содержит два отсчёта одного момента времени. его тоже оборачивают в ProcessorDuplicator. Фильтр переменных состояний принимает частоту среза и resonance; документация JUCE замечает, что и ему при резкой смене частоты может понадобиться сглаживание параметра (juce_StateVariableTPTFilter.h).

Код собран с JUCE 9.0.3 в консольном приложении с флагами предупреждений JUCE и -Wconversion без предупреждений. На 1 с белого шума выход класса Biquad расходится с IIR::Filter не больше чем на 1,6⋅10−61{,}6 \cdot 10^{-6} — JUCE хранит состояния в float, а Biquad в double, — а с ФНЧ StateVariableTPTFilter — не больше чем на 9⋅10−89 \cdot 10^{-8}. АЧХ коэффициентов lowPass на 1 кГц, по getMagnitudeForFrequency, равна −3,01 дБ.

Самопроверка

Вход 1, 2 и импульсная характеристика 1, 0, −1. Чему равна свёртка и сколько в ней отсчётов?

y[0]=1⋅1=1y[0] = 1 \cdot 1 = 1, y[1]=2⋅1+1⋅0=2y[1] = 2 \cdot 1 + 1 \cdot 0 = 2, y[2]=2⋅0+1⋅(−1)=−1y[2] = 2 \cdot 0 + 1 \cdot (-1) = -1, y[3]=2⋅(−1)=−2y[3] = 2 \cdot (-1) = -2. Выход 1, 2, −1, −2 — 2+3−1=42 + 3 - 1 = 4 отсчёта. Проверка: произведение сумм 3⋅0=03 \cdot 0 = 0 равно сумме выхода.

Какой отклик у фильтра y[n] = x[n] − x[n−2] на частоте fs/4 и почему?

Это КИХ-фильтр с H(z)=1−z−2H(z) = 1 - z^{-2}. На fs/4f_s/4 частота ω=π/2\omega = \pi/2, и e−jπ=−1e^{-j\pi} = -1: H=1−(−1)=2H = 1 - (-1) = 2. Нули фильтра — корни z2−1z^2 - 1, точки z=±1z = \pm 1, то есть частоты 0 и fs/2f_s/2; посередине между ними, на fs/4f_s/4, АЧХ наибольшая. Это простейший полосовой фильтр.

Полюсы биквада — пара 0,9·e^(±jπ/4). Найдите a1 и a2 и скажите, устойчив ли фильтр. На какой частоте резонанс при 48 кГц?

a1=−2⋅0,9⋅cos⁡45°≈−1,273a_1 = -2 \cdot 0{,}9 \cdot \cos 45° \approx -1{,}273, a2=0,81a_2 = 0{,}81. Радиус 0,9 меньше 1 — фильтр устойчив. Угол π/4\pi/4 соответствует fs/8=6f_s/8 = 6 кГц.

Линейно-фазовый КИХ-фильтр из 255 коэффициентов работает при 44,1 кГц. Какую задержку он вносит?

(255−1)/2=127(255 - 1)/2 = 127 отсчётов, 127/44 100≈2,9127/44\,100 \approx 2{,}9 мс — одинаково для всех частот.

Почему частоту среза фильтра синтезатора, который качает LFO со звуковой частотой, лучше делать на фильтре переменных состояний, а не на бикваде в TDF-II?

Состояния TDF-II рассчитаны под старые коэффициенты, и при быстрой их смене выход скачет, вплоть до неограниченного роста, как в таблице 3. Состояния фильтра переменных состояний — выходы интеграторов аналоговой схемы, и при модуляции он ведёт себя как прототип. Без модуляции передаточные функции обоих одинаковы.

Источники

  • Sundararajan D. Digital Signal Processing: An Introduction. §2.2–2.5, с. 46–57; §2.7, с. 59–60; §6.1, с. 196–197; §6.3.2, с. 217–218; §7.1–7.2, с. 230–237; §8.4, с. 315–318. в списке литературы → — свёртка как сумма откликов на импульсы и пример 4 ∗ 4, длина N + M − 1, линейность и инвариантность во времени, отклик на комплексную экспоненту, устойчивость через сумму модулей, КИХ и БИХ, z-преобразование, передаточная функция и устойчивость по полюсам, КИХ-фильтры, линейная фаза и групповая задержка, каноническая и транспонированная формы второго порядка, разложение на секции.
  • Bellanger M. Digital Signal Processing: Theory and Practice. §6.2, с. 127–131. в списке литературы → — чисто рекурсивная секция второго порядка: коэффициенты b₁ = −2r·cos θ и b₂ = r² (в обозначениях книги), АЧХ через расстояния до полюсов, подъём на резонансе обратно пропорционален расстоянию до окружности, ширина (1 − r)/π, групповая задержка и её отрицательные значения.
  • Smith J. O. III. Introduction to Digital Filters with Audio Applications. Phase and Group Delay, Group Delay, BiQuad Section, Resonator Bandwidth in Terms of Pole Radius, Direct-Form I, Transposed Direct-Forms, Numerical Robustness of TDF-II. в списке литературы → — фазовая и групповая задержка, задержка огибающей узкополосной группы, биквад и полюсы через радиус и угол, ширина резонанса −ln r/(πT), прямая форма I без внутренних переполнений, транспонирование без изменения передаточной функции, нули перед полюсами в TDF-II.
  • Bristow-Johnson R. Audio EQ Cookbook / ed. by R. Toy. W3C Working Group Note, 2021 — передаточная функция биквада, прямая форма I, коэффициенты ФНЧ и ФВЧ, учёт искажения частот билинейного преобразования.
  • Zavalishin V. The Art of VA Filter Design. §3.11, с. 79–81; §4.1, с. 95–97. в списке литературы → — прямые формы и их поведение при модуляции, метод TPT, точность прямых форм высокого порядка, фильтр переменных состояний с выходами ФВЧ, полосового и ФНЧ, АЧХ 1/(2R) на частоте среза.
  • JUCE 9.0.3. juce_IIRFilter.h, juce_IIRFilter.cpp, juce_IIRFilter_Impl.h — TDF-II, ArrayCoefficients и Coefficients::makeLowPass, нормировка на a₀, резерв на восемь коэффициентов, совет для быстрой модуляции.
  • JUCE 9.0.3. juce_FIRFilter.h — КИХ-фильтр для одного канала, граница 128 коэффициентов и класс Convolution.
  • JUCE 9.0.3. juce_StateVariableTPTFilter.h и juce_StateVariableTPTFilter.cpp — шаг фильтра переменных состояний, resonance и сглаживание частоты среза.
  • FabFilter. Pro-Q 4 Help: Processing mode — задержка и предзвон линейно-фазового режима.

Связи

Связи списком

Ссылается на

Открыть в общем графе

Поиск

Ищем по названиям, тексту статей и английским терминам. Например: «частота дискретизации», «Nyquist», «аналоговый сигнал».