Во время свертки на сигнале, почему мы должны перевернуть импульсную реакцию во время процесса?
Во время свертки на сигнале, почему мы должны перевернуть импульсную реакцию во время процесса?
Ответы:
Адаптировано из ответа на другой вопрос (как упомянуто в комментарии) в надежде, что этот вопрос не будет неоднократно подниматься вики-сообществом как один из главных вопросов ....
Не происходит «переворачивания» импульсного отклика линейной (не зависящей от времени) системой. Выход линейной не зависящей от времени системы представляет собой сумму масштабированных и задержанных во времени версий импульсного отклика, а не «перевернутого» импульсного отклика.
Разобьем входной сигнал на сумму масштабированных единичных импульсных сигналов. Отклик системы на единичный импульсный сигнал является импульсным откликом или импульсным откликом
Вот пример C / C ++, который показывает, что свертка может быть сделана без обратного импульсного отклика. Если вы проверяете convolve_scatter()
функцию, ни одна переменная нигде не отменяется. Это свертка рассеяния, при которой каждая входная выборка разбрасывается (суммируется) на несколько выходных выборок в памяти, используя веса, заданные импульсной характеристикой. Это расточительно, потому что выходные образцы нужно будет прочитать и записать несколько раз.
Обычно свертка делается как сборка свертки, как в convolve_gather()
. В этом методе каждая выходная выборка формируется отдельно путем сбора (суммирования) входных выборок с обратным импульсным откликом в качестве весов. Выходная выборка находится в регистре процессора, который используется в качестве аккумулятора, пока это делается. Обычно это метод выбора, потому что для каждой отфильтрованной выборки будет только одна запись в память. Теперь доступно больше операций чтения из памяти, но только столько, сколько было чтения из памяти в методе рассеяния.
#include <stdio.h>
const int Nx = 5;
const int x[Nx] = {1, 0, 0, 0, 2};
const int Ny = 3;
const int y[Ny] = {1, 2, 3};
const int Nz = Nx+Ny-1;
int z[Nz];
void convolve_scatter() { // z = x conv y
for (int k = 0; k < Nz; k++) {
z[k] = 0;
}
for (int n = 0; n < Nx; n++) {
for (int m = 0; m < Ny; m++) {
z[n+m] += x[n]*y[m]; // No IR reversal
}
}
}
void convolve_gather() { // z = x conv y
for (int k = 0; k < Nz; k++) {
int accu = 0;
for (int m = 0; m < Ny; m++) {
int n = k+m - Ny + 1;
if (n >= 0 && n < Nx) {
accu += x[n]*y[Ny-m-1]; // IR reversed here
}
}
z[k] = accu;
}
}
void print() {
for (int k = 0; k < Nz; k++) {
printf("%d ", z[k]);
}
printf("\n");
}
int main() {
convolve_scatter();
print();
convolve_gather();
print();
}
Это свертывает последовательности:
1 0 0 0 2
1 2 3
и используя оба метода свертки:
1 2 3 0 2 4 6
Я не могу представить, чтобы кто-либо использовал метод рассеяния, если только фильтр не меняется во времени, и в этом случае два метода будут давать разные результаты, и один из них может быть более подходящим.
Это только «перевернуто» для точечных вычислений.
@Dilip объясняет, что представляет собой интеграл / суммирование свертки, но чтобы объяснить, почему одна из двух входных функций (часто h(t)
) переключается для целей вычисления, рассмотрим систему с дискретным временем с входным x[n]
и импульсным откликом h[n]
:
Вы можете взять свою входную функцию x[n]
и для каждой ненулевой выборки * x[n]
рассчитать масштабированный импульсный отклик от выборки n
и далее до тех пор, пока сдвиг по времени не h[n]
уменьшится до нуля (предполагая причинность h[n]
). Это не будет включать в себя не «листать» (точнее «обращения времени») : либо x[n]
или h[n]
. Тем не менее, в конце вы должны добавить / наложить все эти масштабированные + смещенные «эхо» импульсной характеристики для каждого ненулевого значения x[n]
.
x[0]
k
h[n]
x[n]
, который есть x[0]h[0]
. Затем увеличение k
на единицу сместится h[n]
на один шаг вправо, так что h[n]
вторая запись ( h[1]
) с обращенной по времени теперь будет лежать поверх x[0]
, ожидая умножения. Это даст желаемый вклад x[0]h[1]
во времени n=1
, так же, как это было бы сделано в предыдущем методе.x[n]
h[n]
y[n]
При индексе c [n] свертка a [n] и b [n] такова, что:
«c [n] является суммой всех произведений (a [k] b [m]), таких что m + k = n», поэтому m = n - k или k = n - m, что означает, что одна из последовательностей должен быть перевернут.
Теперь, почему свертка ведет себя так в первую очередь? Из-за его связи с умножением многочленов.
Умножение двух полиномов приводит к новому полиному с коэффициентами. Коэффициенты полинома произведения определяют операцию свертки. Теперь при обработке сигналов передаточные функции - преобразования Лапласа или z-преобразования - являются этими полиномами, причем каждый коэффициент соответствует разной временной задержке. Сопоставление коэффициентов произведения и мультипликатов приводит к тому, что «умножение в одном представлении соответствует свертке в преобразованном представлении».
Во время свертки не должно происходить никакого «переворота» импульсного отклика ...
Однако, если вы хотите предотвратить любое изменение фазы, вы можете свернуть сигнал с импульсным откликом, а затем обратить вспять импульсный отклик и повторно свернуть, чтобы отменить фазовые эффекты.
В автономной обработке вы можете так же легко повернуть сигнал после первой свертки, чтобы прийти к такому же выводу (как предлагают комментарии).
Теперь форма рукопожатия четко показывает симметрию, которая здесь задействована, и что никакого «переворачивания» не происходит. Однако преобразование этого в правильный одномерный интеграл требует превращения одного из двух аргументов в фактическую переменную интегрирования. Это либо так, либо нахождение жесткой симметричной формы, не связанной с маханием рукой. Последнее сложнее. По сути, вы должны вернуть нормализацию, создавая что-то (при использовании дельта-функции Дирака) как Если вы затем переставите одним способом, вы получите и из свойства просеивания оператора Дирака