Inverter a resposta ao impulso em convolução

26

Durante a convolução em um sinal, por que precisamos inverter a resposta ao impulso durante o processo?

winuall
fonte
5
A segunda metade desta resposta pode ajudá-lo a entender.
Dilip Sarwate
3
Além de ler a excelente resposta do @ DilipSarwate, é um bom exercício pegar uma folha de papel e calcular graficamente a saída de um sistema de LTI, adicionando versões com escala de tempo e deslocadas da resposta ao impulso.
DEVE
11
Observe que você pode inverter qualquer argumento - o resultado é o mesmo.
Wakjah 28/11/12

Respostas:

29

Adaptado de uma resposta para uma pergunta diferente (como mencionado em um comentário) na esperança de que essa pergunta não seja levantada repetidamente pelo Community Wiki como uma das principais perguntas ....

Não há "inversão" da resposta ao impulso por um sistema linear (invariável no tempo). A saída de um sistema linear invariável no tempo é a soma das versões escalonadas e atrasadas da resposta ao impulso, não a resposta ao impulso "invertida".

Dividimos o sinal de entrada em uma soma de sinais de pulso unitários em escala. A resposta do sistema ao sinal de pulso da unidade é a resposta de impulso ou resposta de pulso e, pela propriedade de escala, o valor de entrada único ou, se você preferir cria uma resposta , 0 , 0 , 1 , 0 , 0 , h [ 0 ] , h [ 1 ] , , h [ n ] , x [ 0 ] x [ 0 ] ( , 0 , 0 , 1 , 0 , 0 , ) = 0 , 0 ,x, 0, 0, 1, 0, 0,

h[0], h[1],, h[n],
x[0]
x[0](, 0, 0, 1, 0, 0,)= 0, 0, x[0], 0, 0,
x[0]h[0],  x[0]h[1],,  x[0]h[n],

Da mesma forma, o valor de entrada único ou cria cria uma resposta Observe o atraso na resposta para . Podemos continuar mais nesse sentido, mas é melhor mudar para uma forma mais tabular e mostrar as várias saídas alinhadas corretamente no tempo. Nós temos x[1]

x[1](, 0, 0, 0, 1, 0,)= 0, 0, 0, x[1], 0,
0,x[1]h[0],  x[1]h[1],,  x[1]h[n1],x[1]h[n]
x[1]
time012nn+1x[0]x[0]h[0]x[0]h[1]x[0]h[2]x[0]h[n]x[0]h[n+1]x[1]0x[1]h[0]x[1]h[1]x[1]h[n1]x[1]h[n]x[2]00x[2]h[0]x[2]h[n2]x[2]h[n1]x[m]000x[m]h[nm]x[m]h[nm+1]
\ ddots \ end {array} As linhas no array acima são precisamente as versões em escala e atrasadas da resposta ao impulso que se somam à resposta ao sinal de entrada . yx Mas se você fizer uma pergunta mais específica, como

Qual é a saída no tempo ?n

então você pode obter a resposta somando a ésima coluna para obter a amada fórmula de convolução que confunde gerações de estudantes, porque a resposta ao impulso parece estar "invertida" ou retrocedendo no tempo. Mas, o que as pessoas parecem esquecer é que, em vez disso, poderíamos ter escrito para que seja a entrada que parece "invertida" ou retrocedendo no tempo! Em outras palavras, são seres humanosn

y[n]=x[0]h[n]+x[1]h[n1]+x[2]h[n2]++x[m]h[nm]+=m=0x[m]h[nm],
n
y[n]=x[n]h[0]+x[n1]h[1]+x[n2]h[2]++x[0]h[n]+=m=0x[nm]h[m],
que inverte a resposta de impulso (ou a entrada) ao calcular a resposta no tempo usando a fórmula de convolução, mas o próprio sistema não faz nada disso.n
Dilip Sarwate
fonte
4

Aqui está um exemplo de C / C ++ que mostra que a convolução pode ser feita sem o uso inverso da resposta ao impulso. Se você inspecionar a convolve_scatter()função, nenhuma variável será negada em qualquer lugar. Isso é convolução de dispersão, onde cada amostra de entrada é dispersa (somada) para várias amostras de saída na memória, usando pesos dados pela resposta ao impulso. Isso é um desperdício, porque as amostras de saída precisarão ser lidas e gravadas várias vezes.

Normalmente, a convolução é feita como convolução de coleta , como em convolve_gather(). Nesse método, cada amostra de saída é formada separadamente, reunindo (somando) amostras de entrada, com a resposta ao impulso reverso como pesos. A amostra de saída reside no registro de um processador usado como acumulador enquanto isso é feito. Normalmente, esse é o método de escolha, porque haverá apenas uma gravação de memória por cada amostra filtrada. Agora há mais leituras de memória da entrada, mas apenas quantas leituras de memória da saída no método de dispersão.

#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();
}

Ele envolve as seqüências:

1 0 0 0 2
1 2 3

e usando as saídas dos dois métodos de convolução:

1 2 3 0 2 4 6

Não consigo imaginar alguém usando o método de dispersão, a menos que o filtro varie no tempo; nesse caso, os dois métodos produzirão resultados diferentes e um poderá ser mais apropriado.

Olli Niemitalo
fonte
Interessante! Então, o que é conclusão final Estou interessado para ver
Falha Scientist
Sua preocupação arquitetônica é interessante. Considerando os caches disponíveis, as instruções SIMD (SSE, AVX) e as arquiteturas com vários núcleos, o método disperso parece mais adequado para cálculos paralelos? Mas eu não realizei uma análise detalhada ...
Fat32 23/08
@ Fat32 também não! Você quer dizer que a acumulação na coleta de convolução pode se tornar um gargalo com vários núcleos trabalhando em multiplicações? Isso poderia ser mitigado, dando a cada núcleo seu próprio acumulador e somando-o no final. Eu acho que essa sobrecarga não seria muito comparada com as gravações adicionais de memória em convolução dispersa.
Olli Niemitalo 23/08
Na verdade, eu estava mais preocupado com a eficiência do formulário disperso do que com o gargalo dos formulários de coleta . Meus códigos de filtragem C atuais estão (provavelmente) no formulário de coleta, mas quando se trata de códigos ASM, costumo escrevê-los em extensões SIMD SSE, que são mais adequado à forma dispersa. Eu tenho que atualizar meus tets, no entanto :-))) A memória IO é definitivamente um problema em comparação com o acúmulo de registros. E, provavelmente, eu estou perdendo a pena da memória repetido IO ...
Fat32
Alguém sabe palavras melhores do que espalhar e reunir? Não tenho certeza se eles estão reservados para kernels de convolução esparsos.
Olli Niemitalo
3

É apenas 'invertido' para computação pontual.

O @Dilip explica o que a integral / soma de convolução representa, mas para explicar por que uma das duas funções de entrada (geralmente h(t)) é ativada para fins de computação, considere um sistema de tempo discreto com x[n]resposta de entrada e impulso h[n]:

  • Você pode usar sua função de entrada x[n]e, para cada amostra diferente de zero *, x[n]calcular a resposta de impulso escalonada da amostra ne depois até que o deslocamento no tempo diminua h[n]para zero (assumindo um causal h[n]). Isso não envolveria 'inversão' (ou mais precisamente 'reversão de tempo') de um x[n]ou de outro h[n]. No entanto, no final, você teria que adicionar / sobrepor todos esses 'ecos' escalados + deslocados da resposta ao impulso para cada diferente de zero x[n].

  • Ou , por conveniência, você pode reverter uma das funções sobre a origem da hora (geralmente 0), fazendo seu cálculo {multiplicar, adicionar, multiplicar, adicionar, ...} em vez de {multiplicar, multiplicar, ..., adicionar , adicionar, ...}. Isso resulta no mesmo sinal de saída, porque ele executará exatamente as mesmas operações de multiplicação e adição. Por exemplo, pense na contribuição da saída de um sinal de entrada diferente de zero no tempo 0 x[0]. Quando k= 0 para a equação a resposta ao impulso será revertida apenas no tempo, mas não deslocada, fornecendo a primeira resposta de amostra para a qual é . Então, incrementar um passo mudará para o passo certo uma vez, de modo que o tempo invertido

    k=x[k]h[nk]
    h[n]x[n]x[0]h[0]kh[n]h[n]A segunda entrada ( h[1]) estará agora em cima x[0], esperando para ser multiplicada. Isso produzirá a contribuição desejada x[0]h[1]no momento n=1, exatamente como teria sido feito no método anterior.

* Eu digo diferente de zero x[n]porque a resposta ao impulso é redimensionada para zero, contribuindo assim para a saída final .

x[n]=0
h[n]y[n]
abc
fonte
"Você pode usar sua função de entrada x [n] e, para cada amostra diferente de zero * x [n], calcule a resposta de impulso em escala da amostra n e em diante até que o h [n] alternado no tempo desça para zero (assumindo uma causal h [n]) "Os cinco que ocorrem nesta frase têm o mesmo número ou são diferentes? n
usar o seguinte código
@Dilip. Todos os n são iguais, exceto 'h-n com deslocamento no tempo', o que implica 'h [nk]', onde 'k' é uma constante usada para mudar a resposta do impulso para o ponto desejado do sinal x [n ] ou seja: h [n-2] para calcular a resposta ao sinal em x [2].
abc
3

No índice c [n], a convolução de a [n] e b [n] é tal que:

"c [n] é um somatório de todos os produtos (a [k] b [m]) tal que m + k = n", então m = n - k ou k = n - m, o que significa que uma das seqüências tem que ser invertido.

Agora, por que a convolução se comporta dessa maneira em primeiro lugar? Por causa de sua conexão com polinômios multiplicadores.

A multiplicação de dois polinômios resulta em um novo polinômio com coeficientes. Os coeficientes do polinômio do produto definem a operação de convolução. Agora, no processamento do sinal, as funções de transferência - transformadas de Laplace ou z-transformadas são esses polinômios, com cada coeficiente correspondendo a um atraso de tempo diferente. A combinação dos coeficientes do produto e dos multiplicandos resulta no fato de que "a multiplicação em uma representação corresponde à convolução na representação transformada".

insira a descrição da imagem aqui

Mahesh Shastry
fonte
0

Durante a convolução, nenhum "giro" da resposta ao impulso precisa ocorrer ...

No entanto, se você deseja impedir qualquer alteração de fase, pode distorcer um sinal com uma resposta de impulso e, em seguida, reverter a resposta de impulso e recolocar para cancelar os efeitos de fase.

No processamento off-line, você pode reverter o sinal facilmente após a primeira convolução para chegar à mesma conclusão (como sugerem os comentários).

learnvst
fonte
3
Ele está se referindo à "reversão do tempo" na resposta ao impulso na integral de convolução: . Como alguém já apontou, você não precisa inverter a resposta do impulso ; você pode inverter qualquer um dos termos (por exemplo, ). Acho que ele está tentando descobrir qual é a interpretação qualitativa dessa ação "flip-and-slide". y(t)=x(τ)h(tτ)dτh(t)x(t)h(t)=h(t)x(t)
Jason R
@JasonR Ah, opa! Às vezes, é difícil ver o que a pergunta está chegando. Izhak, depois que você entender a resposta que estava procurando, entenderá para onde eu estava indo. Me ignore por enquanto!
learnvst
0

Basta escrever a integral de convolução como um nomeadamente a integração do produto de e sobre todos os pares de argumento que soma de .

f(τ)g(tτ)dτ
t1+t2=tf(t1)g(t2)dt1dt2
fgt

Agora, a forma de ondulação das mãos mostra claramente a simetria envolvida aqui e que não há "inversão". Converter isso em uma integral unidimensional adequada, no entanto, exige que um dos dois argumentos seja a variável de integração real. É isso ou encontrar uma forma simétrica rígida que não envolva a movimentação das mãos. O último é mais complicado. Basicamente, é necessário recuperar a normalização, criando algo (ao usar a função / distribuição do Dirac delta) como Se você reorganizar de uma maneira, obterá e da propriedade de peneiração do operador Dirac

t1,t2f(t1)g(t2)δ(tt1t2)dt1dt2
t1f(t1)dt1t2g(t2)δ(tt1t2)dt2
t1f(t1)dt1g(tt1)
que é a integral original com um pouco de renomeação.

fonte