Для начала - немного теории. Свертка - это последовательный процесс, заключающийся в сложении N точек входной функции, умноженных на коэффициенты (таблицу свертки), для получения одной точки результирующей функции. Данная операция проводится столько раз, сколько точек будет содержать результирующая функция.
Проще всего этот процесс, наверное, будет понятен по иллюстрации: справа изображена свертка некой функции (зеленые клетки) с помощью таблицы свертки {0, 1, 1} (желтые клетки), результат - столбик значений (функция) в синих клетках. Получение первых трех значений результирующей функции показано подробно - значения трех последовательных элементов исходной функции умножаются на значения таблицы свертки, результат складывается и записывается в одну ячейку результата.
- Видно, что количество точек результирующей функции всегда меньше, чем количество точек исходной. Конкретно говоря, их меньше на N-1 штук, где N - размер таблицы свертки.
- Мы применяли симметричную свертку - т.е. свертку относительно середины отрезка. Если пометить центральный элемент таблицы свертки <вот так>, то наша свертка записывалась бы в виде {0, <1>, 1}. К примеру, одноточечная свертка {<1>} оставит функцию как есть - не отняв ни одного отсчета и не изменив ни одного значения, а {<2>} - усилит функцию (увеличит каждый её элемент) в два раза. Свертка {0, <0>, 1} просто сдвинет функцию на один отсчет. Собственно говоря, для такой операции мы могли бы воспользоваться и просто несимметричной сверткой из двух точек - {<0>, 1}.
Видно, что сама по себе свертка - простой и понятный процесс. Вся хитрость и мощь заключена в том, как, с какими параметрами, этот процесс можно применить - то есть в таблице свертки. К вопросу о том, что же такое таблица свертки (далее называемая просто сверткой) и мы сейчас и перейдем.
Для наглядного представления процесса бывает очень удобно изображать таблицу свертки в виде графика, аналогичного обрабатываемым функциям. Все дальнейшие иллюстрации будут проходить с использованием картинок, подобной данной:
На картинке изображена исходная функция, построена таблица свертки ("холостая" - т.е. состоящая из множества нулей и одной единички, просто сдвигающая функцию) и изображен сам результат свертки этой функции этой таблицей. Применяемая во всех дальнейших примерах таблица свертки прикладывается симметрично, т.е. центр процесса свертки находится в центре таблицы (и, соответственно, посередине графика "таблица свертки"), сама таблица состоит из 41 точки (20 точек в одну сторону, центральная точка и 20 точек в другую сторону). Оговорюсь сразу, что эффект сдвига функции, который имеет место на предыдущей иллюстрации, нас нисколько не интересуют - суть обработки заключается не в этом.
Пример N1 - Одиночное эхо.
Начнем с простого. Данная свертка иллюстрирует получение одиночного эха, равного по амплитуде половине от исходного сигнала. Можно легко догадаться, что второй импульс (всплеск) свертки просто дублирует сигнал еще один раз через определенное число отсчетов.
Отвлечемся еще немного и поговорим о концепции, которая неразрывно связана со сверткой - импульсная функция (impulse response). Импульсная функция - характеристика процесса, отвечающая на вопрос: что сделает процесс с одиночным импульсом? Попытаемся получить импульсную функцию свертки, т.е. скормим нашему процессу одиночный импульс в качестве входной функции и посмотрим, что он с ним сделает:
Можно заметить, что свертка послала в выходной результат... себя. Очень важный вывод: таблица свертки - это импульсная функция производимого процесса. Перефразируемся: для создания процесса, отвечающего данной импульсной функции, надо просто "сверстать" данные этой импульсной функцией. Как получить импульсную функцию? Очень просто: нужно всего лишь пропустить через искомую систему импульс...
Пример N2 - Реальное эхо.
Последовательность действий проста до гениальности: мы берем микрофон и идем в некую пещеру. Устанавливаем аппаратуру, включаем запись и издаем "импульс" - вернее, максимально приближенное к нему явление: например, какой-нибудь предельно резкий удар. Записываем эхо нашего импульса. Что мы получили? Мы получили способ полностью воссоздать акустику помещения - по крайней мере в той степени, в какой нам это гарантирует неизменность звука при неизменности импульсной функции. Это важный момент, который следует понимать: не все параметры процесса определяются импульсной функцией, но большинство важных для человека - всё же определяется. Итак, мы записали затихающее реальное эхо импульса и теперь свертываем им наш собственный звук:
Пожалуйста, эхо. Эхо именно того помещения, которое закодировано в таблице свертки (то есть в импульсной функции реального эха) - со всеми тональными тонкостями, звуковой окраской и параметрами затухания (при условии достаточной длинны свертки).
Пример N3 - Частотная фильтрация
Настала пора синтезировать собственную таблицу свертки. На этот раз мы будем делать фильтрацию звука - да, обыкновенный частотный фильтр, причем частотный фильтр "высшего класса", не вносящий фазовых искажений - FIR фильтр, вернее, его частный случай - windowed-sinc. Я всё же не буду объяснять, как синтезируются подобные таблицы сверток - это не входит в тему данной статьи, просто посмотрите на готовые результаты.
Фильтр, задерживающий низкие частоты и увеличивающий содержание высоких частот (таблица свертки схематично нарисована пальцем, но и такая вполне работает):
Фильтр, задерживающий высокие частоты (таблица свертки схематично нарисована пальцем, но и такая вполне работает):
[оговорюсь: если предыдущий фильтр еще как-то похож на windowed-sinc, то последний - просто бред сивой кобылы :). На самом деле импульсная функция (таблица свертки) должна иметь затухающие в обе стороны колебания, а не одинокий горб, как у меня. Но тем не менее даже это грубое приближение, как видно, вполне фильтрует, хотя и вносит существенные искажения, надо полагать...]
Пример N4 - Комбинированная свертка
Еще один простейший пример - однократное эхо, имеющее глухую окраску - т.е. эхо, сопряженное с фильтром высоких частот:
Первый одиночный импульс таблицы свертки оставляет в неизменной форме исходный сигнал, а второй - фильтрующий горбик - с некоторой задержкой добавляет отфильтрованный вариант сигнала, содержащий только низкие частоты.
Это - лишь малая часть всего того, что можно сделать с помощью свертки. Комбинируя различные приемы построения таблиц можно добиваться очень разнообразных эффектов - как я уже говорил, 90% всех функций типичного музыкального редактора можно реализовать с помощью сверток. Сверткой запросто делаются следующие эффекты (в любой комбинации):
- накладываемые задержки
- любая частотная фильтрация
- вариации фаз сигналов
Поверьте, это не так уж мало - с помощью этого набора процессов легко делается хорус, вокодеры, фланжеры, любая реверберация (даже самая естественная) и эхо, любые эквалайзеры и фильтрация, а также великое множество других эффектов. Стоит один раз тщательно рассчитать таблицу свертки, и любой из этих эффектов можно запросто выполнять чуть ли не в реальном времени - так, например, реализовано большое число сложных эффектов в популярном редакторе CoolEdit.
Подводя итог: Свертка - процесс, который реализует некое преобразование, заданное через импульсную функцию этого преобразования. Свертка позволяет в точности воспроизвести множество процессов, имея их импульсную функцию, а также легко осуществить самую разнообразную обработку, синтезируя импульсную функцию по неким известным заранее законам.