Salta al contenuto
Note per Studenti Convoluzione a blocchi - overlap-add e overlap-save

Convoluzione a blocchi - overlap-add e overlap-save

In questa pagina 6

Filtrare un segnale x[n]x[n] con un FIR di risposta impulsiva h[n]h[n] lunga MM vuol dire calcolare y[n]=∑k=0M−1h[k]x[n−k]y[n]=\sum_{k=0}^{M-1}h[k]x[n-k] (Sistemi LTI e convoluzione discretaUn sistema lineare e tempo-invariante (LTI) è completamente descritto dalla sua risposta impulsiva h[n]: y[n] = Σ x[k] h[n-k] = x[n] * h[n] (somma di convoluzione). Si ricava scomponendo x in impulsi traslati e usando linearità e invarianza. La convoluzione è commutativa, associativa e distributiva; una cascata di LTI equivale a un solo filtro con h = h1 * h2 e l'ordine non conta. Se x ha lunghezza N e h lunghezza L, y ha lunghezza N+L-1. Si calcola col metodo della finestra scorrevole o a tabella. I FIR sono LTI; altri sistemi (n·x[n], x[-n], x²) non lo sono.Sistemi LTI e convoluzione discreta →). Con la formula diretta ogni campione di uscita costa MM moltiplicazioni e M−1M-1 somme. Con la FFT si può fare di meglio per filtri lunghi, ma la DFT fornisce una convoluzione circolare (Trasformata di Fourier discreta (DFT) e convoluzione circolareLa DFT di N campioni x[0..N-1] è X[k] = sum x[n] e^{-j2pi kn/N}, k = 0..N-1 (IDFT: x[n] = (1/N) sum X[k] e^{j2pi kn/N}); vede il segnale come periodico di periodo N e dà N campioni equispaziati della DTFT, cioè X(z) valutata sulle radici N-esime dell'unità. Se x ha durata M <= N non c'è aliasing temporale e lo zero-padding (N > M) infittisce solo i campioni della stessa DTFT. Proprietà: traslazione circolare, simmetria coniugata X[k] = X*[N-k], prodotto = convoluzione circolare. La convoluzione circolare coincide con la lineare solo se N >= Dx + M - 1; altrimenti la coda si ripiega sull'inizio. La FFT calcola la DFT con (N/2) log2 N moltiplicazioni invece di N^2.Trasformata di Fourier discreta (DFT) e convoluzione circolare →) e lavora su segnali di lunghezza finita: serve un metodo per ottenere quella lineare e per trattare segnali molto lunghi (o infiniti, come un flusso audio). Questa nota riassume il calcolo con la FFT, il confronto di costo e i due metodi a blocchi.

Convoluzione lineare con la DFT

Il procedimento, per xx di lunghezza DxD_x e hh di lunghezza MM (uscita lunga Dy=Dx+M−1D_y=D_x+M-1):

  1. Si sceglie N≥DyN\ge D_y; per sfruttare la FFT, NN potenza di due: N=min⁡{2m: 2m≥Dy}N=\min\{2^m:\ 2^m\ge D_y\}.
  2. Si completano xx e hh con zeri fino a NN campioni (zero-padding).
  3. Si calcolano le DFT X[k]X[k] e H[k]H[k] (due FFT), si moltiplica Y[k]=X[k]H[k]Y[k]=X[k]H[k] (NN moltiplicazioni) e si antitrasforma (una FFT inversa).

Con N≥DyN\ge D_y non c'è aliasing temporale e y[n]=ycirc[n]y[n]=y_{\rm circ}[n] per 0≤n≤N−10\le n\le N-1; con N<DyN<D_y la coda si ripiega sull'inizio.

Esempio. Se Dy=9D_y=9 serve N=16N=16; se Dy=27D_y=27, N=32N=32 (come nell'appunto del corso).

Costo: quando conviene la FFT

Il costo del metodo diretto per campione è TD=kDMT_D=k_DM (kDk_D dipende dal processore). Il metodo FFT ha costo per campione TF=1N(3 TFFT+N kmult)≃3 kFlog⁡2N,T_F=\frac1N\big(3\,T_{\rm FFT}+N\,k_{\rm mult}\big)\simeq3\,k_F\log_2N, dove TFFT=kFNlog⁡2NT_{\rm FFT}=k_FN\log_2N è il costo di una FFT, il fattore 33 conta le due FFT e la FFT inversa, e il termine N kmultN\,k_{\rm mult} delle NN moltiplicazioni si trascura. Assumendo kF≃kDk_F\simeq k_D: TFTD≃3log⁡2NM.\frac{T_F}{T_D}\simeq\frac{3\log_2N}{M}. La FFT conviene quando questo rapporto è minore di 11. Due casi tipici.

Caso 1: Dx≃MD_x\simeq M. Allora N≃Dx+M−1≃2MN\simeq D_x+M-1\simeq2M e TFTD≃3log⁡2(2M)M=3(1+log⁡2M)M\frac{T_F}{T_D}\simeq\frac{3\log_2(2M)}{M}=\frac{3(1+\log_2M)}{M}.

MM 232^3 242^4 252^5 262^6 272^7 282^8 292^9 2102^{10}
TF/TDT_F/T_D 12/8=1.512/8=1.5 15/16=0.9415/16=0.94 18/32=0.5618/32=0.56 21/64=0.3321/64=0.33 0.190.19 0.110.11 0.0590.059 33/1024=0.03233/1024=0.032

Per MM piccolo (8) è più veloce il calcolo diretto; per M=16M=16 si è in pareggio; per MM grande la FFT è molto più veloce (verificato con Python: 3(k+1)/2k3(k+1)/2^k per M=2kM=2^k).

Caso 2: Dx≫MD_x\gg M. Allora N≃DxN\simeq D_x e TFTD≃3log⁡2DxM<1\frac{T_F}{T_D}\simeq\frac{3\log_2D_x}{M}<1 se Dx<2M/3D_x<2^{M/3}.

MM 25=322^5=32 26=642^6=64 27=1282^7=128 28=2562^8=256
DxD_x massimo ≈1.6⋅103\approx1.6\cdot10^3 ≈2.6⋅106\approx2.6\cdot10^6 ≈7⋅1012\approx7\cdot10^{12} ≈5⋅1025\approx5\cdot10^{25}

Quindi, se il filtro è corto, il calcolo diretto è meglio; se è lungo, la FFT è molto più veloce, anche per segnali lunghissimi. Resta però il problema pratico: una FFT enorme richiede di aspettare tutto il segnale (non va per l'elaborazione in tempo reale) e occupa molta memoria. Si risolve a blocchi.

Convoluzione a blocchi

Si suddivide x[n]x[n] in blocchi, si convolve ogni blocco con h[n]h[n] (con la FFT, su NN piccolo) e si ricombinano i risultati in modo opportuno. I due metodi, con la stessa complessità, sono overlap-add e overlap-save.

Overlap-add

Metodo (overlap-add, "sovrapponi e somma"). Sia hh di lunghezza MM e si divida xx in blocchi non sovrapposti di lunghezza LL (L>ML>M per semplicità): xi[n]=x[n] wR[n−iL],wR[n]=u[n]−u[n−L],x[n]=∑i=0∞xi[n]  (x causale).x_i[n]=x[n]\,w_R[n-iL],\qquad w_R[n]=u[n]-u[n-L],\qquad x[n]=\sum_{i=0}^{\infty}x_i[n]\ \ (x\text{ causale}). Per la linearità y[n]=∑ixi[n]∗h[n]=∑iyi[n]y[n]=\sum_ix_i[n]*h[n]=\sum_iy_i[n] con yi=xi∗hy_i=x_i*h di lunghezza L+M−1L+M-1 e supporto {iL,…,(i+1)L+M−2}\{iL,\dots,(i+1)L+M-2\}.

I blocchi yiy_i e yi+1y_{i+1} hanno supporti [iL,(i+1)L+M−2][iL,(i+1)L+M-2] e [(i+1)L,(i+2)L+M−2][(i+1)L,(i+2)L+M-2]: si sovrappongono per M−1M-1 campioni, quelli di indice (i+1)L≤n≤(i+1)L+M−2(i+1)L\le n\le(i+1)L+M-2. Quindi in ogni istante nn la somma ha uno o due termini non nulli: y[n]={yi−1[n]+yi[n]iL≤n≤iL+M−2(sovrapposizione con il blocco precedente)yi[n]iL+M−2<n<(i+1)L(solo il blocco i)y[n]=\begin{cases}y_{i-1}[n]+y_i[n]&iL\le n\le iL+M-2\quad(\text{sovrapposizione con il blocco precedente})\\ y_i[n]&iL+M-2<n<(i+1)L\quad(\text{solo il blocco }i)\end{cases}

Per calcolare ogni yi=xi∗hy_i=x_i*h con la FFT, per evitare l'aliasing la DFT deve avere lunghezza N≥L+M−1N\ge L+M-1. La DFT di hh (H[k]H[k], a NN punti) si calcola una volta sola. Per ogni blocco: FFT di xix_i completato con zeri a NN, prodotto con H[k]H[k], FFT inversa; poi si traslano le uscite di iLiL e si sommano le code sovrapposte.

Esempio (lezione). x={1,2,3,4,5,6}x=\{1,2,3,4,5,6\}, h={1,1,1}h=\{1,1,1\} (M=3M=3), L=4L=4 e N=6≥L+M−1=6N=6\ge L+M-1=6. Blocchi: x0={1,2,3,4}x_0=\{1,2,3,4\} e x1={5,6}x_1=\{5,6\}. Con zero-padding a 66 campioni: y0=x0∗h={1,3,6,9,7,4}y_0=x_0*h=\{1,3,6,9,7,4\} (indici 00-55) e y1=x1∗h={5,11,11,6}y_1=x_1*h=\{5,11,11,6\}, che parte da n=4n=4. Somma:

nn 0 1 2 3 4 5 6 7
y0y_0 1 3 6 9 7 4
y1y_1 (traslata di 4) 5 11 11 6
yy 1 3 6 9 12 15 11 6

Il risultato coincide con la convoluzione lineare diretta {1,3,6,9,12,15,11,6}\{1,3,6,9,12,15,11,6\} (verificato con Python). Nell'appunto del corso compaiono due zeri finali: sono il padding della DFT a N=6N=6 sul secondo blocco, non fanno parte del risultato.

Grafico interattivo: Overlap-add: uscita del blocco 0, y0 = {1, 3, 6, 9, 7, 4}, indici 0-5

Grafico interattivo: Overlap-add: uscita del blocco 1 traslata di L = 4, y1 = {5, 11, 11, 6} da n = 4: le code si sovrappongono in n = 4 e 5

Grafico interattivo: Overlap-add: somma y = y0 + y1 = {1, 3, 6, 9, 12, 15, 11, 6}, uguale alla convoluzione lineare di x = {1..6} con {1,1,1}

Overlap-save

L'idea è opposta: invece di sommare le code, si evita di avere code. I blocchi di ingresso sono sovrapposti di M−1M-1 campioni, si calcola la convoluzione circolare a NN punti, e si scartano i campioni che non coincidono con la convoluzione lineare.

Metodo (overlap-save, "sovrapponi e conserva"). Sia NN la lunghezza della DFT e L=N−M+1L=N-M+1 il numero di campioni validi per blocco. Ogni blocco di ingresso ha lunghezza NN ed è formato da [ M−1[\,M-1 campioni sovrapposti (gli ultimi del blocco precedente) ∣\mid LL campioni nuovi ]\,]. Il primo blocco ha M−1M-1 zeri iniziali. Per ogni blocco: Yi[k]=Xi[k]H[k]Y_i[k]=X_i[k]H[k], yi=y_i= IDFT, e si scartano i primi M−1M-1 campioni di yiy_i; i restanti LL vanno in uscita.

Perché funziona. La convoluzione circolare a NN punti ripiega la coda dell'uscita lineare, lunga N+M−1N+M-1, sull'inizio: sono corrotti i primi M−1M-1 campioni (esattamente quelli in cui il filtro "vede" l'ingresso oltre il bordo del blocco), mentre gli altri N−M+1=LN-M+1=L coincidono con la convoluzione lineare. Nei primi M−1M-1 posti del blocco ci sono i campioni del blocco precedente, che servono proprio a rendere corretti i campioni successivi.

Esempio (lezione). Stessi dati, x={1,…,6}x=\{1,\dots,6\}, h={1,1,1}h=\{1,1,1\} (M=3M=3), N=6N=6, L=N−M+1=4L=N-M+1=4. Blocchi sovrapposti di M−1=2M-1=2:

  • b0={0,0,1,2,3,4}b_0=\{0,0,1,2,3,4\} (due zeri iniziali): convoluzione circolare {7,4,1,3,6,9}\{7,4,1,3,6,9\}; si scartano i primi due (7,47,4) e si tengono {1,3,6,9}\{1,3,6,9\}.
  • b1={3,4,5,6,0,0}b_1=\{3,4,5,6,0,0\} (gli ultimi due campioni del blocco, poi i nuovi 5,65,6 e zeri): circolare {3,7,12,15,11,6}\{3,7,12,15,11,6\}; si scartano 3,73,7 e si tengono {12,15,11,6}\{12,15,11,6\}.

Uscita: {1,3,6,9}∪{12,15,11,6}={1,3,6,9,12,15,11,6}\{1,3,6,9\}\cup\{12,15,11,6\}=\{1,3,6,9,12,15,11,6\}, uguale alla convoluzione lineare (verificato con Python). I campioni scartati (7,47,4 e 3,73,7) sono proprio quelli corrotti dall'aliasing: per b0b_0 la convoluzione lineare è {0,0,1,3,6,9,7,4}\{0,0,1,3,6,9,7,4\} e la coda 7,47,4 si ripiega sui primi due posti, dove c'erano gli zeri.

Confronto e scelta

overlap-add overlap-save
blocchi di ingresso disgiunti, lunghezza LL sovrapposti di M−1M-1, lunghezza NN
DFT N≥L+M−1N\ge L+M-1, ingresso con zero-padding NN scelto, L=N−M+1L=N-M+1
uscita del blocco L+M−1L+M-1 campioni, con coda NN campioni di cui M−1M-1 corrotti
ricombinazione somma delle code di M−1M-1 campioni scarto dei primi M−1M-1 campioni
aliasing temporale evitato con il padding accettato e poi scartato

I due metodi hanno la stessa complessità: per ogni blocco due FFT (blocco e inversa; H[k]H[k] è calcolata una volta sola) e NN moltiplicazioni. Si sceglie NN potenza di due, di solito alcune volte MM (come regola pratica N≈4MN\approx4M-8M8M): con NN troppo vicino a MM i campioni validi L=N−M+1L=N-M+1 sono pochi e si butta via molto lavoro; con NN troppo grande cresce il fattore log⁡2N\log_2N e la memoria. In tempo reale il filtro introduce una latenza di almeno LL campioni (il blocco va raccolto prima di essere elaborato) più il ritardo del filtro stesso, (M−1)/2(M-1)/2 se è a fase lineare (Sistemi a fase lineare e assenza di distorsioneUn sistema non deforma il segnale se y[n] = K x[n-n0]: modulo costante e fase lineare -n0 w, cioè ritardo di gruppo costante n0. Un sistema reale e causale ha fase lineare (generalizzata) se e solo se è FIR con risposta impulsiva simmetrica h[n] = h[N-n] (ampiezza pari, fase -N w/2) o antisimmetrica h[n] = -h[N-n] (ampiezza dispari, fase -N w/2 + pi/2). Il ritardo di gruppo è N/2: intero se N è pari (vale la condizione di non distorsione), semi-intero se N è dispari (uscita interpolata e ritardata). Un IIR causale non può essere simmetrico, quindi non ha fase lineare esatta.Sistemi a fase lineare e assenza di distorsione →).

Il codice Python dei due metodi, confrontati con np.convolve, è in Esercizio - Convoluzione a blocchi con la DFT.

Domande d'esame

  1. Spiegare come si calcola la convoluzione lineare di due sequenze finite con la DFT e quando conviene rispetto al calcolo diretto. Traccia: N≥Dx+M−1N\ge D_x+M-1 (potenza di 2), zero-padding, Y=XHY=XH; costo TF≃3klog⁡2NT_F\simeq3k\log_2N per campione contro TD=kMT_D=kM; rapporto 3log⁡2N/M3\log_2N/M; caso Dx≃MD_x\simeq M (tabella: pareggio a M=16M=16) e Dx≫MD_x\gg M (Dx<2M/3D_x<2^{M/3}).
  2. Descrivere il metodo overlap-add e dimostrare la formula di ricombinazione. Traccia: x=∑xix=\sum x_i, y=∑yiy=\sum y_i, supporto [iL,(i+1)L+M−2][iL,(i+1)L+M-2], sovrapposizione di M−1M-1 campioni, tre intervalli della somma, N≥L+M−1N\ge L+M-1, esempio numerico {1..6}∗{1,1,1}\{1..6\}*\{1,1,1\}.
  3. Descrivere overlap-save e confrontarlo con overlap-add. Traccia: blocchi di NN con M−1M-1 campioni sovrapposti, L=N−M+1L=N-M+1, convoluzione circolare, primi M−1M-1 campioni scartati perché corrotti dal ripiegamento; stessa complessità; scelta di NN; latenza.

Versione ripasso

  • Lineare con la DFT. Per xx di lunghezza DxD_x e hh di lunghezza MM: N≥Dy=Dx+M−1N\ge D_y=D_x+M-1 (potenza di 22), zero-padding di xx e hh, Y[k]=X[k]H[k]Y[k]=X[k]H[k], antitrasformata. Con N≥DyN\ge D_y non c'è aliasing. Esempio: Dy=9D_y=9 dà N=16N=16; Dy=27D_y=27 dà N=32N=32.
  • Costo per campione. Diretto: TD=kDMT_D=k_DM. FFT: TF≃3kFlog⁡2NT_F\simeq3k_F\log_2N. Rapporto TF/TD≃3log⁡2N/MT_F/T_D\simeq3\log_2N/M; la FFT conviene se è minore di 11.
  • Caso Dx≃MD_x\simeq M. N≃2MN\simeq2M e TF/TD≃3(1+log⁡2M)/MT_F/T_D\simeq3(1+\log_2M)/M: per M=8M=8 il diretto è più veloce (1,51{,}5), per M=16M=16 si è in pareggio (0,940{,}94), per M=1024M=1024 la FFT costa 0,0320{,}032 volte.
  • Caso Dx≫MD_x\gg M. N≃DxN\simeq D_x: la FFT conviene se Dx<2M/3D_x<2^{M/3}, con DxD_x massimo circa 1,6⋅1031{,}6\cdot10^3 per M=32M=32.
  • Limite pratico. Una FFT enorme aspetta tutto il segnale e occupa memoria: si lavora a blocchi.
  • Overlap-add ("sovrapponi e somma"). Blocchi xix_i disgiunti di lunghezza LL, con x=∑ixix=\sum_ix_i e y=∑iyiy=\sum_iy_i, yi=xi∗hy_i=x_i*h lunga L+M−1L+M-1 e supporto {iL,…,(i+1)L+M−2}\{iL,\dots,(i+1)L+M-2\}. I blocchi si sovrappongono di M−1M-1 campioni, che si sommano. N≥L+M−1N\ge L+M-1; la H[k]H[k] si calcola una sola volta.
  • Esempio overlap-add. x={1,…,6}x=\{1,\dots,6\}, h={1,1,1}h=\{1,1,1\}, L=4L=4, N=6N=6: y0={1,3,6,9,7,4}y_0=\{1,3,6,9,7,4\}, y1={5,11,11,6}y_1=\{5,11,11,6\} traslata di 44; la somma è {1,3,6,9,12,15,11,6}\{1,3,6,9,12,15,11,6\}.
  • Overlap-save ("sovrapponi e conserva"). Blocchi di NN campioni, sovrapposti di M−1M-1 (il primo con M−1M-1 zeri iniziali), L=N−M+1L=N-M+1 campioni validi per blocco. Si calcola la circolare a NN punti e si scartano i primi M−1M-1 campioni, che sono corrotti dal ripiegamento della coda.
  • Esempio overlap-save. Con N=6N=6, M=3M=3: b0={0,0,1,2,3,4}b_0=\{0,0,1,2,3,4\} dà circolare {7,4,1,3,6,9}\{7,4,1,3,6,9\}, si tengono {1,3,6,9}\{1,3,6,9\}; b1={3,4,5,6,0,0}b_1=\{3,4,5,6,0,0\} dà circolare {3,7,12,15,11,6}\{3,7,12,15,11,6\}, si tengono {12,15,11,6}\{12,15,11,6\}.
  • Confronto. Stessa complessità: due FFT per blocco e NN moltiplicazioni. Overlap-add somma le code; overlap-save scarta i campioni corrotti. Regola pratica N≈4MN\approx4M-8M8M.
  • Tempo reale. Latenza di almeno LL campioni più il ritardo del filtro, (M−1)/2(M-1)/2 se è a fase lineare (Sistemi a fase lineare e assenza di distorsioneUn sistema non deforma il segnale se y[n] = K x[n-n0]: modulo costante e fase lineare -n0 w, cioè ritardo di gruppo costante n0. Un sistema reale e causale ha fase lineare (generalizzata) se e solo se è FIR con risposta impulsiva simmetrica h[n] = h[N-n] (ampiezza pari, fase -N w/2) o antisimmetrica h[n] = -h[N-n] (ampiezza dispari, fase -N w/2 + pi/2). Il ritardo di gruppo è N/2: intero se N è pari (vale la condizione di non distorsione), semi-intero se N è dispari (uscita interpolata e ritardata). Un IIR causale non può essere simmetrico, quindi non ha fase lineare esatta.Sistemi a fase lineare e assenza di distorsione →).
  • Perché funziona overlap-save. La circolare a NN punti ripiega la coda dell'uscita lineare, lunga N+M−1N+M-1, sull'inizio: sono corrotti i primi M−1M-1 campioni, esattamente quelli in cui il filtro vede l'ingresso oltre il bordo del blocco. Gli altri N−M+1=LN-M+1=L coincidono con la lineare.
  • Tabella DxD_x massimo. Con M=64M=64 la FFT resta vantaggiosa fino a Dx≈2,6⋅106D_x\approx2{,}6\cdot10^6; con M=128M=128 fino a ≈7⋅1012\approx7\cdot10^{12}; con M=256M=256 fino a ≈5⋅1025\approx5\cdot10^{25}.
  • Errore tipico. Dimenticare che le M−1M-1 campioni del blocco precedente servono a rendere corretti quelli successivi (overlap-save), o sommare le code sbagliate (overlap-add).

Esercizi su questo argomento

Teoria collegata