Русская Википедия:Свёртка последовательностей

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Свёртка последовательностей — линейное преобразование двух числовых последовательностей. Результатом свёртки является последовательность, элементы которой получаются в результате перемножения и суммирования элементов исходных последовательностей таким образом, что члены одной последовательности берутся с возрастанием индексов, а члены другой — с убыванием (что и служит основанием для принятого названия данной операции). Различают линейную и циклическую свёртки, которые используются для конечных и периодических последовательностей соответственно.

Свёртка последовательностей <math>a</math> и <math>b</math> обозначается как <math>a * b</math>.

Свёртка последовательностей является частным случаем свёртки функций. Свёртка также тесно связана с взаимной корреляцией.

Типы свёрток

К традиционным типам свёрток относятся:

  • линейная (апериодическая) свёртка;
  • циклическая (круговая, периодическая) свёртка;
  • свёртка с помощью дискретного преобразования Фурье.

Расчёт свёрток

Рассмотрим правила и последовательность расчёта каждого вида свёртки.

Расчёт линейной свёртки

Пусть заданы две числовые последовательности:

<math> a = \left\{ a_0, a_1, \ldots, a_{N_1-1} \right\}, </math>
<math> b = \left\{ b_0, b_1, \ldots, b_{N_2-1} \right\}. </math>

Для расчёта линейной свёртки этих последовательностей необходимо выполнить следующие действия:

  • произвести расчёт количества элементов выходной последовательности по формуле:
<math>N_{out}=N_1+N_2-1,</math>
где:
<math>N_{out}</math> — количество элементов в выходной последовательности;
<math>N_1</math> — количество элементов в первой последовательности;
<math>N_2</math> — количество элементов во второй последовательности;
  • дополнить нулями обе последовательности так, чтобы количество элементов в обеих последовательностях было равно <math>N_{out}</math>;
  • симметрично отобразить одну из последовательностей относительно оси ординат;
  • произвести перемножение этих двух последовательностей.

В результате выполнения всех описанных выше операций получим линейную свёртку <math>c</math> последовательностей <math>a</math> и <math>b</math>, элементы которой вычисляются по одной из двух формул:

<math> c_i = \sum\limits_{k=0}^{N_1-1} a_k b_{i-k}, \; i = 0,\ldots,N_{out}-1,</math>

либо

<math> c_i = \sum\limits_{k=0}^{N_2-1} a_{i-k} b_k, \; i = 0,\ldots,N_{out}-1.</math>

Здесь подразумевается, что при <math>i-k < 0</math> элементы соответствующей последовательности равны нулю.

Убедиться в эквивалентности формул и, как следствие, в коммутативности операции свёртки можно с помощью простой замены индексов <math>j = i-k</math> в одной из формул.

Расчёт циклической свёртки

Рассмотрим теперь две числовые последовательности одинаковой длины <math>N</math>:

<math> a = \left\{ a_0, a_1, \ldots, a_{N-1} \right\}, </math>
<math> b = \left\{ b_0, b_1, \ldots, b_{N-1} \right\}. </math>

Для получения периодической круговой свёртки <math>c'</math> необходимо представить, что эти последовательности располагаются на двух окружностях, одна из которых находится внутри другой. Значения каждой из этих последовательностей равноудалены друг от друга. Для получения каждого значения круговой свёртки необходимо представить, что одна из последовательностей движется по окружности относительно другой по часовой стрелке. Сначала возьмём первое значение последовательности, которая вращается, последовательно умножим на значения другой последовательности и просуммируем результаты умножений и получим первое значение выходной последовательности <math>c'</math>. Затем данные действия повторим для каждого значения последовательности, которая вращается относительно другой. Количество элементов в выходной последовательности будет равно <math>N</math>.

Иными словами, элементы циклической свёртки <math>c'</math> вычисляются по формуле

<math> c'_i = \sum\limits_{k=0}^{N-1} a_k b_{((i-k))}, \; i = 0,\ldots,N-1,</math>

где <math>((i-k)) = (i-k) \bmod{N}</math>.

Полученная последовательность эквивалентна свёртке двух периодических сигналов, то есть можно рассматривать последовательности <math>a</math> и <math>b</math> как определённые для всех <math>i \in \mathbb{Z}</math> по формулам <math>a_i = a_{((i))}</math> и <math>b_i = b_{((i))}</math>.

Расчёт апериодической свёртки

Для получения апериодической свёртки выполняется все те же операции, что и для получения круговой свёртки, но при этом последовательности могут иметь разное количество элементов (например, <math>N_1</math> и <math>N_2</math>) и их необходимо дополнить нулями до количества <math>N_{out}=N_1+N_2-1</math>. При выполнении данного вида свёртки устраняется эффект кругового наложения, который возникает при круговой свёртке. Это альтернативный способ вычисления линейной свёртки.

Связь линейной и циклической свёрток

Описанный выше подход позволяет установить связь между вычислением линейной и циклической свёрток. Для этого в формуле для элементов циклической свёртки разделим сумму на две, соответствующие случаям <math>i-k \geqslant 0</math> и <math>i-k < 0</math>:

<math> c'_i = \sum\limits_{k=0}^i a_k b_{i-k} + \sum\limits_{k=i+1}^{N-1} a_k b_{N+i-k}. </math>

Полагая теперь в первой сумме <math>b_{i-k} = 0</math> при <math>k>i</math>, а во второй <math>b_{N+i-k} = 0</math> при <math>k<i</math>, можно изменить границы суммирования и получить связь линейной и циклической свёрток в виде

<math> c'_i = \sum\limits_{k=0}^{N-1} a_k b_{i-k} + \sum\limits_{k=0}^{N-1} a_k b_{N+i-k} = c_i + c_{N+i}, \; i = 0,\ldots,N-1. </math>

Линейную свёртку можно вычислять как циклическую, если второе слагаемое в этой формуле равно нулю, то есть равны нулю произведения <math>a_k b_{N+i-k}</math> для всех <math>i</math> и <math>k</math>. Чтобы обеспечить выполнение этого условия, можно выбирать длину <math>N</math> циклической свёртки так, чтобы она была не меньше, чем <math>N_{out}=N_1+N_2-1</math>, дополняя при этом входные последовательности нулями.

Вычисление свёртки с помощью преобразования Фурье

Для вычисления свёртки с помощью дискретного преобразования Фурье необходимо дополнить нулями обе входные последовательности так, чтобы количество элементов в этих последовательностях равнялось <math>N_{out}</math>. Далее необходимо произвести прямое преобразование Фурье каждой из последовательностей. Затем преобразованные последовательности поэлементно перемножаются, после чего производится обратное преобразование результата умножения.

Вычисление свёртки описанным способом осуществимо благодаря теореме о свёртке.

Для проверки правильности расчётов линейной, циклической или свёртки с помощью преобразования Фурье можно произвести дополнительно расчёт одной из двух других типов свёртки, так как выходные последовательности должны быть равны при одинаковых входных последовательностях.

Вычислительная сложность

Вычисление свёртки требует <math>O(N^2)</math> операций. Это количество может быть существенно уменьшено с помощью вычисления свёртки различными быстрыми алгоритмами.

Чаще всего для уменьшения количества операций свёртка вычисляется с помощью двух преобразований Фурье, каждое из которых рассчитывается с помощью быстрых алгоритмов. Это позволяет снизить вычислительную сложность операции свёртки до <math>O(N \log N)</math>.

Уменьшение размерности пространства при многомерной свёртке

Пусть в пространстве <math>\mathbb{Z}^n</math> заданы два дискретных комплексных сигнала <math>f</math> и <math>g</math>. Определим свёртку <math>y=f*g</math> этих сигналов как

<math> y(k_1,\ldots,k_n) = \sum\limits_{i_1 = -\infty}^{+\infty} \ldots \sum\limits_{i_n = -\infty}^{+\infty} f(i_1,\ldots,i_n) g(k_1-i_1,\ldots,k_n-i_n). </math>

Зададим также операцию понижения размерности пространства на измерение <math>i_j</math> или суммирования сигнала по <math>i_j</math> как

<math>f[ \mathbb{Z}^n - i_j ] = \sum\limits_{i_j = -\infty}^{+\infty} f(i_1,\ldots,i_n), j \in 1...n.</math>

Теорема. Для произвольного измерения <math>i_j</math> пространства <math>\mathbb{Z}^n</math> результат свёртки <math>y=f*g</math> с последующим суммированием по <math>i_j</math> есть <math>y[\mathbb{Z}^n - i_j]</math>, что эквивалентно предварительному суммированию по <math>i_j</math> сигналов <math>f</math> и <math>g</math> с последующей свёрткой: <math>y[\mathbb{Z}^n - i_j] = f[\mathbb{Z}^n - i_j]*g[\mathbb{Z}^n - i_j]</math>. [1]

Пример программы

Ниже приведён пример реализации линейной свёртки, написанный на C++:

/*
 * Размер выходной последовательности равен M + N - 1
 */
vector<double> conv(const vector<double>& x, const vector<double>& h) {
	if ((x.size() == 0) && (h.size() == 0)) {
		return vector<double>();
	}

	vector<double> a;
	vector<double> b;
	if (x.size() < h.size()) {
		a = x;
		b = h;
	} else {
		a = h;
		b = x;
	}

	vector<double> result(a.size() + b.size() - 1, 0);
	for (size_t k = 0; k < a.size(); k++) {
		for (size_t l = 0; l < b.size(); l++) {
			result[l + k] += a[k] * b[l];
		}
	}
	return result;
}

См. также

Примечания

Шаблон:Примечания

Литература