Lanciare la risposta all'impulso in convoluzione


26

Durante la convoluzione su un segnale, perché dobbiamo invertire la risposta all'impulso durante il processo?


5
L'ultima metà di questa risposta potrebbe aiutarti a capire.
Dilip Sarwate,

3
Oltre a leggere la grande risposta di @ DilipSarwate, è un buon esercizio prendere un foglio di carta e calcolare graficamente l'output di un sistema LTI aggiungendo versioni ridimensionate e ridimensionate della risposta all'impulso.
Deve il

1
Nota che puoi capovolgere entrambi gli argomenti: il risultato è lo stesso.
Wakjah,

Risposte:


29

Adattato da una risposta a una domanda diversa (come menzionato in un commento) nella speranza che questa domanda non venga ripetutamente sollevata da Wiki della community come una delle domande principali ....

Non vi è alcun "capovolgimento" della risposta all'impulso da parte di un sistema lineare (invariante nel tempo). L'output di un sistema lineare invariante è la somma delle versioni ridimensionate e ritardate della risposta all'impulso, non della risposta all'impulso "capovolta".

Suddividiamo il segnale di ingresso in una somma di segnali di impulsi di unità in scala. La risposta del sistema al segnale a impulsi dell'unità , 0 , 0 , 1 , 0 , 0 , è la risposta all'impulso o la risposta all'impulso h [ 0 ] , h [ 1 ] , , h [ n ] , e così via dal proprietà di ridimensionamento del singolo valore di input x [ 0 ]x, 0, 0, 1, 0, 0,

h[0], h[1],, h[n],
x[0]oppure, se si preferisce crea una risposta x [ 0 ] h [ 0 ] , x [ 0 ] h [ 1 ] , , x
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],

Allo stesso modo, il singolo valore di input o crea x [ 1 ] ( , 0 , 0 , 0 , 1 , 0 , ) = 0 , ] h [ 1 ] , x [ 1 ] h 0 ] x [ 0 ] h [ 0 ] x [ 0 ] h [ 1X[1] crea una risposta 0 , x [ 1 ] h [ 0 ] , x [ 1

X[1](, 0, 0, 0, 1, 0,)= 0, 0, 0, X[1], 0,
Nota il ritardo nella risposta a x [ 1 ] . Possiamo continuare ulteriormente in questo senso, ma è meglio passare a una forma più tabulare e mostrare i vari output allineati correttamente nel tempo. Abbiamo tempo 0 1 2 n n + 1 x [
0,X[1]h[0],  X[1]h[1],,  X[1]h[n-1],X[1]h[n]
X[1] Le righe nell'array sopra sono precisamente le versioni ridimensionate e ritardate di la risposta all'impulso che si somma alla rispostayal segnale di ingressox. Ma se fai una domanda più specifica come
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[n-1]X[1]h[n]X[2]00X[2]h[0]X[2]h[n-2]X[2]h[n-1]X[m]000X[m]h[n-m]X[m]h[n-m+1]
yX

Qual è l'output al momento ?n

n

y[n]=x[0]h[n]+x[1]h[n1]+x[2]h[n2]++x[m]h[nm]+=m=0x[m]h[nm],
y[n]=x[n]h[0]+x[n1]h[1]+x[n2]h[2]++x[0]h[n]+=m=0x[nm]h[m],
n

4

Ecco un esempio in C / C ++ che mostra che la convoluzione può essere fatta senza usare la risposta all'impulso al contrario. Se si controlla la convolve_scatter()funzione, nessuna variabile viene negata da nessuna parte. Si tratta di una convoluzione di scattering in cui ogni campione di input viene sparso (sommato) in più campioni di output in memoria, utilizzando i pesi forniti dalla risposta all'impulso. Questo è uno spreco perché i campioni di output dovranno essere letti e scritti più volte.

Normalmente la convoluzione viene eseguita come raccolta della convoluzione, come in convolve_gather(). In questo metodo, ciascun campione di output viene formato separatamente, raccogliendo (sommando) campioni di input, con la risposta all'impulso invertita come pesi. L'esempio di output risiede nel registro di un processore usato come accumulatore mentre ciò è fatto. Questo è normalmente il metodo di scelta, perché ci sarà una sola scrittura in memoria per ogni campione filtrato. Ora ci sono più letture di memoria dell'input, ma solo quante erano le letture di memoria dell'output nel metodo scattering.

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

Convolge le sequenze:

1 0 0 0 2
1 2 3

e usando entrambi i risultati dei metodi di convoluzione:

1 2 3 0 2 4 6

Non riesco a immaginare nessuno che usi il metodo scattering, a meno che il filtro non vari nel tempo, nel qual caso i due metodi produrranno risultati diversi e uno potrebbe essere più appropriato.


Interessante! Quindi qual è la conclusione finale che mi interessa vedere
scienziato fallito

La tua preoccupazione architettonica è interessante. Considerando le cache disponibili, le istruzioni SIMD (SSE, AVX) e le architetture multi core, il metodo sparso sembra più adatto per i calcoli paralleli? Ma non ho eseguito un'analisi dettagliata però ...
Fat32

@ Fat32 neanche io! Vuoi dire che l'accumulo nella raccolta della convoluzione potrebbe diventare un collo di bottiglia con più core che lavorano su moltiplicazioni? Ciò potrebbe essere mitigato dando a ciascun nucleo il proprio accumulatore e sommandolo alla fine. Penso che questo sovraccarico non sarebbe molto paragonato alle scritture di memoria aggiuntiva nella convoluzione sparsa.
Olli Niemitalo,

In realtà ero più interessato all'efficienza della forma sparsa che alla strozzatura delle forme di raccolta . I miei codici di filtro C attuali sono (molto probabilmente) nella forma di raccolta, ma quando si tratta di codici ASM tendo a scriverli nelle estensioni SIMD SSE che sono più adatto a forma sparsa. Devo aggiornare i miei punti, tuttavia :-))) L'IO della memoria è sicuramente un problema rispetto all'accumulo dei registri. E probabilmente mi manca la penalità della memoria ripetuta IO ...
Fat32

Qualcuno conosce parole migliori di scattering e raccolta? Non sono sicuro che siano riservati ai kernel convoluzione sparsa.
Olli Niemitalo,

3

È solo "capovolto" per il calcolo puntuale.

@Dilip spiega cosa rappresenta l'integrale / somma della convoluzione, ma per spiegare perché una delle due funzioni di input (spesso h(t)) viene capovolta ai fini del calcolo, si consideri un sistema a tempo discreto con input x[n]e risposta all'impulso h[n]:

  • Potresti prendere la tua funzione di input x[n], e per ogni campione diverso da zero * x[n]calcolare la risposta all'impulso in scala dal campione ne avanti fino a quando il tempo spostato non si h[n]abbassa a zero (assumendo un causale h[n]). Ciò non implicherebbe alcun "capovolgimento" (o "inversione del tempo" più preciso) di uno x[n]o h[n]. Tuttavia, alla fine dovresti aggiungere / sovrapporre tutti questi 'echi' scalati + spostati della risposta all'impulso per ogni diverso da zero x[n].

  • Oppure , per comodità, è possibile invertire una delle funzioni relative all'origine del tempo (in genere 0), effettuando il calcolo {moltiplicare, aggiungere, moltiplicare, aggiungere, ...} anziché {moltiplicare, moltiplicare, ..., aggiungere , Inserisci, ...}. Ciò provoca lo stesso segnale di uscita perché eseguirà esattamente lo stesso moltiplicare e aggiungere operazioni. Ad esempio, pensare al contributo di uscita da un segnale di ingresso diverso da zero al tempo 0 x[0]. Quando k= 0 per l'equazione

    k=x[k]h[nk]
    h[n]x[n], che è x[0]h[0]. Quindi, incrementando kdi uno si sposterà h[n]alla destra di una volta, in modo tale che la h[n]seconda voce ( h[1]) del tempo invertito ora si stenda sopra x[0], in attesa di essere moltiplicata. Ciò produrrà il contributo desiderato x[0]h[1]in tempo n=1, proprio come sarebbe stato fatto nel metodo precedente.

x[n]

x[n]=0
h[n]y[n]

n

@Dilip. Tutti n sono uguali, ad eccezione di "h [n] spostato nel tempo", che implica "h [nk]", dove "k" è una costante utilizzata per spostare la risposta all'impulso al punto desiderato del segnale x [n ]. ovvero: h [n-2] per calcolare la risposta al segnale in x [2].
abc

3

All'indice c [n], la convoluzione di a [n] e b [n] è tale che:

"c [n] è una somma di tutti i prodotti (a [k] b [m]) tale che m + k = n," quindi m = n - k o k = n - m, il che significa che una delle sequenze deve essere capovolto.

Ora, perché la convoluzione si comporta in questo modo in primo luogo? A causa della sua connessione con i polinomi moltiplicativi.

Moltiplicando due polinomi si ottiene un nuovo polinomio con i coefficienti. I coefficienti del polinomio del prodotto definiscono l'operazione di convoluzione. Ora, nell'elaborazione del segnale, le funzioni di trasferimento - trasformazioni di Laplace o trasformazioni di z sono questi polinomi, con ciascun coefficiente corrispondente ad un diverso ritardo. La corrispondenza dei coefficienti del prodotto e dei moltiplicatori porta al fatto che "la moltiplicazione in una rappresentazione corrisponde alla convoluzione nella rappresentazione trasformata".

inserisci qui la descrizione dell'immagine


0

Durante la convoluzione, non è necessario che si verifichi alcun "capovolgimento" della risposta all'impulso ...

Tuttavia, se si desidera impedire qualsiasi alterazione di fase, è possibile convolgere un segnale con una risposta all'impulso e quindi invertire la risposta all'impulso e riconvolgere per annullare gli effetti di fase.

Nell'elaborazione offline, è possibile invertire altrettanto facilmente il segnale dopo la prima convoluzione per arrivare alla stessa conclusione (come suggeriscono i commenti).


3
y(t)=x(τ)h(tτ)dτh(t)X(t)*h(t)=h(t)*X(t)

@JasonR Ah, whoops! A volte è difficile capire a cosa si rivolga la domanda. Izhak, una volta che avrai capito la risposta che stavi cercando, capirai dove stavo andando. Ignorami per ora!
apprese il

0

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

t1,t2f(t1)g(t2)δ(t-t1-t2)dt1dt2
Se poi riorganizzi in un modo, ottieni
t1f(t1)dt1t2g(t2)δ(t-t1-t2)dt2
e dalla proprietà setacciatrice dell'operatore Dirac
t1f(t1)dt1g(t-t1)
che è l'integrale originale con un po 'di rinomina.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.