Salta al contenuto
Note per Studenti Esercizio - Convoluzione a blocchi con la DFT

Esercizio - Convoluzione a blocchi con la DFT

In questa pagina 4

Testo (lezioni 15-17, corso Multimedia Signal Processing, UniPD; esempi svolti a lezione). Si considerano x[n]={1,2,3,4}x[n]=\{1,2,3,4\}, h[n]={1,1,1,1}h[n]=\{1,1,1,1\} e poi x[n]={1,2,3,4,5,6}x[n]=\{1,2,3,4,5,6\}, h[n]={1,1,1}h[n]=\{1,1,1\}.

  1. Calcolare la convoluzione lineare ylin=x∗hy_{\rm lin}=x*h e la convoluzione circolare ycircy_{\rm circ} a N=4N=4 di x={1,2,3,4}x=\{1,2,3,4\} con h={1,1,1,1}h=\{1,1,1,1\}; spiegare la differenza e verificare che con N≥Dx+M−1N\ge D_x+M-1 (zero-padding) le due coincidono.
  2. Per x={1,…,6}x=\{1,\dots,6\} e h={1,1,1}h=\{1,1,1\}, calcolare x∗hx*h con overlap-add (blocchi di L=4L=4, DFT a N=6N=6).
  3. Lo stesso con overlap-save (N=6N=6, L=N−M+1=4L=N-M+1=4).
  4. Scrivere in Python i due algoritmi e verificarli su un segnale casuale di 10001000 campioni con un FIR di 3333 coefficienti.

Teoria usata: Convoluzione a blocchi - overlap-add e overlap-saveLa convoluzione lineare y = x * h (h lungo M) si può calcolare con la FFT scegliendo N >= Dx + M - 1 (potenza di 2): costo per campione circa 3 k log2 N contro k M del calcolo diretto, quindi la FFT conviene per M abbastanza grande (con Dx circa M, già da M = 16). Per segnali lunghi o infiniti si divide x in blocchi. Overlap-add: blocchi disgiunti di lunghezza L, ognuno convoluto con h (lunghezza L+M-1 con FFT di N >= L+M-1) e le code di M-1 campioni si sommano. Overlap-save: blocchi di N campioni sovrapposti di M-1, convoluzione circolare, si scartano i primi M-1 campioni di ogni uscita (corrotti dall'aliasing). Stesso costo.Convoluzione a blocchi - overlap-add e overlap-save →, 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 →, 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 →.

Punto 1: lineare e circolare

Lineare: ylin[n]=∑ℓx[ℓ]h[n−ℓ]y_{\rm lin}[n]=\sum_\ell x[\ell]h[n-\ell] ha lunghezza Dx+M−1=4+4−1=7D_x+M-1=4+4-1=7: ylin={1, 3, 6, 10, 9, 7, 4}.y_{\rm lin}=\{1,\ 3,\ 6,\ 10,\ 9,\ 7,\ 4\}. Circolare a N=4N=4: ycirc[n]=∑ℓ=03x[ℓ]h[(n−ℓ)4]y_{\rm circ}[n]=\sum_{\ell=0}^{3}x[\ell]h[(n-\ell)_4]. Poiché hh è costante e vale 11 su tutti i 44 posti, ogni uscita è la somma di tutti i campioni, 1+2+3+4=101+2+3+4=10: ycirc={10, 10, 10, 10}.y_{\rm circ}=\{10,\ 10,\ 10,\ 10\}. Il confronto: la circolare ha solo 44 campioni, perché la coda della lineare (9,7,49,7,4 in n=4,5,6n=4,5,6) si ripiega sui primi posti: ycirc[0]=ylin[0]+ylin[4]=1+9y_{\rm circ}[0]=y_{\rm lin}[0]+y_{\rm lin}[4]=1+9, ycirc[1]=3+7y_{\rm circ}[1]=3+7, ycirc[2]=6+4y_{\rm circ}[2]=6+4, ycirc[3]=10y_{\rm circ}[3]=10: tutte le somme valgono 1010. Con zero-padding a N=8≥7N=8\ge7: xp={1,2,3,4,0,0,0,0}x_p=\{1,2,3,4,0,0,0,0\}, hp={1,1,1,1,0,0,0,0}h_p=\{1,1,1,1,0,0,0,0\} la circolare è {1,3,6,10,9,7,4,0}\{1,3,6,10,9,7,4,0\}, uguale alla lineare (più uno zero). Verificato con np.fft.

Punto 2: overlap-add

Blocchi non sovrapposti di L=4L=4: x0={1,2,3,4}x_0=\{1,2,3,4\}, x1={5,6}x_1=\{5,6\} (il secondo è più corto: si completa con zeri). Con N=6≥L+M−1=4+3−1N=6\ge L+M-1=4+3-1: si completano x0x_0, x1x_1 e hh a 66 campioni, si calcola yi=IDFT(DFT(xi)⋅DFT(h))y_i=\text{IDFT}\big(\text{DFT}(x_i)\cdot\text{DFT}(h)\big).

  • y0={1,3,6,9,7,4}y_0=\{1,3,6,9,7,4\} (indici 0..50..5);
  • y1={5,11,11,6,0,0}y_1=\{5,11,11,6,0,0\}, da traslare di L=4L=4: occupa gli indici 4..94..9.

Somma:

nn 0 1 2 3 4 5 6 7 8 9
y0y_0 1 3 6 9 7 4
y1y_1 5 11 11 6 0 0
yy 1 3 6 9 12 15 11 6 0 0

L'uscita lineare vera ha 6+3−1=86+3-1=8 campioni, {1,3,6,9,12,15,11,6}\{1,3,6,9,12,15,11,6\}: gli ultimi due zeri sono padding. La sovrapposizione (M−1=2M-1=2 campioni, in n=4n=4 e 55) è dove si sommano le due code: 7+5=127+5=12 e 4+11=154+11=15.

Punto 3: overlap-save

Blocchi di N=6N=6 campioni, sovrapposti di M−1=2M-1=2; il primo parte da due zeri.

  • b0={0,0,1,2,3,4}b_0=\{0,0,1,2,3,4\}: circolare con hh: {7,4,1,3,6,9}\{7,4,1,3,6,9\}. Si scartano i primi M−1=2M-1=2 campioni (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\} (ultimi due campioni del blocco precedente, poi 5,65,6 e padding): 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\}, uguale a x∗hx*h. I campioni scartati sono quelli in cui la convoluzione circolare ha ripiegato la coda: 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 somma ai due zeri iniziali.

Punto 4: il codice

python
import numpy as np

def overlap_add(x, h, L):
    M = len(h)
    N = 1 << int(np.ceil(np.log2(L + M - 1)))          # potenza di 2 >= L+M-1
    H = np.fft.fft(h, N)                               # DFT di h, una volta sola
    y = np.zeros(len(x) + M - 1)
    for s in range(0, len(x), L):
        blk = x[s:s + L]
        yk = np.real(np.fft.ifft(np.fft.fft(blk, N) * H))[:len(blk) + M - 1]
        y[s:s + len(yk)] += yk                         # somma delle code sovrapposte
    return y

def overlap_save(x, h, N):
    M = len(h)
    L = N - M + 1                                       # campioni validi per blocco
    H = np.fft.fft(h, N)
    xp = np.concatenate([np.zeros(M - 1), x, np.zeros(N)])   # M-1 zeri iniziali
    out = []
    for s in range(0, len(x) + M - 1, L):
        blk = xp[s:s + N]
        if len(blk) < N:
            blk = np.concatenate([blk, np.zeros(N - len(blk))])
        yk = np.real(np.fft.ifft(np.fft.fft(blk) * H))
        out.append(yk[M - 1:])                          # si scartano i primi M-1 campioni
    return np.concatenate(out)[:len(x) + M - 1]

rng = np.random.default_rng(3)
x = rng.normal(size=1000); h = rng.normal(size=33)
print(np.allclose(overlap_add(x, h, 100), np.convolve(x, h)))     # True
print(np.allclose(overlap_save(x, h, 128), np.convolve(x, h)))    # True

Entrambi i controlli stampano True (eseguito). Con x={1,…,6}x=\{1,\dots,6\} e h={1,1,1}h=\{1,1,1\} le funzioni danno {1,3,6,9,12,15,11,6}\{1,3,6,9,12,15,11,6\}.

Osservazione sul costo. Per ogni blocco servono una FFT diretta, un prodotto di NN numeri e una FFT inversa; H=DFT(h)H=\text{DFT}(h) è calcolata una sola volta. Per M=33M=33 e N=128N=128 ogni blocco produce L=96L=96 campioni validi con circa 2⋅N2log⁡2N+N=10242\cdot\frac N2\log_2N+N=1024 moltiplicazioni complesse, cioè circa 10.710.7 per campione (contro 3333 moltiplicazioni reali per campione del calcolo diretto, da confrontare tenendo conto che una moltiplicazione complessa ne vale circa quattro reali).

Versione ripasso

Punto 1. ylin=x∗hy_{\rm lin}=x*h ha lunghezza Dx+M−1=7D_x+M-1=7. Con x={1,2,3,4}x=\{1,2,3,4\} e h={1,1,1,1}h=\{1,1,1,1\}: ylin={1,3,6,10,9,7,4}y_{\rm lin}=\{1,3,6,10,9,7,4\}. La circolare a N=4N=4 dà ycirc={10,10,10,10}y_{\rm circ}=\{10,10,10,10\}: la coda 9,7,49,7,4 si ripiega sui primi posti (1+91+9, 3+73+7, 6+46+4, 1010). Con zero-padding a N≥7N\ge7 la circolare coincide con la lineare.

Punto 2 - overlap-add. Blocchi x0={1,2,3,4}x_0=\{1,2,3,4\}, x1={5,6}x_1=\{5,6\}, N=6≥L+M−1=6N=6\ge L+M-1=6, yi=IDFT(DFT(xi)⋅DFT(h))y_i=\text{IDFT}(\text{DFT}(x_i)\cdot\text{DFT}(h)).

  • y0={1,3,6,9,7,4}y_0=\{1,3,6,9,7,4\} negli indici 0..50..5;
  • y1={5,11,11,6,0,0}y_1=\{5,11,11,6,0,0\} traslato di L=4L=4, negli indici 4..94..9.
  • Somma: y={1,3,6,9,12,15,11,6}y=\{1,3,6,9,12,15,11,6\}. Le code si sommano in n=4n=4 (7+57+5) e n=5n=5 (4+114+11).

Punto 3 - overlap-save. N=6N=6, M−1=2M-1=2 campioni scartati, L=N−M+1=4L=N-M+1=4.

  • b0={0,0,1,2,3,4}b_0=\{0,0,1,2,3,4\}: 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\}: circolare {3,7,12,15,11,6}\{3,7,12,15,11,6\}, 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\}, uguale a x∗hx*h.

Punto 4 - codice. overlap_add(x,h,L) e overlap_save(x,h,N) verificati su 10001000 campioni casuali con 3333 coefficienti: entrambi True contro np.convolve. Costo per blocco: una FFT diretta, un prodotto di NN elementi, una FFT inversa; H=DFT(h)H=\text{DFT}(h) si calcola una volta.

Teoria: Convoluzione a blocchi - overlap-add e overlap-saveLa convoluzione lineare y = x * h (h lungo M) si può calcolare con la FFT scegliendo N >= Dx + M - 1 (potenza di 2): costo per campione circa 3 k log2 N contro k M del calcolo diretto, quindi la FFT conviene per M abbastanza grande (con Dx circa M, già da M = 16). Per segnali lunghi o infiniti si divide x in blocchi. Overlap-add: blocchi disgiunti di lunghezza L, ognuno convoluto con h (lunghezza L+M-1 con FFT di N >= L+M-1) e le code di M-1 campioni si sommano. Overlap-save: blocchi di N campioni sovrapposti di M-1, convoluzione circolare, si scartano i primi M-1 campioni di ogni uscita (corrotti dall'aliasing). Stesso costo.Convoluzione a blocchi - overlap-add e overlap-save →, 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 →, 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 →.

Errori tipici:

  • Confrontare la circolare a N=4N=4 con la lineare senza fare lo zero-padding: la coda si ripiega e le uscite cambiano.
  • In overlap-add sommare i blocchi senza traslarli di LL.
  • In overlap-save non scartare i primi M−1M-1 campioni di ogni blocco circolare.
  • Dimenticare che una moltiplicazione complessa vale circa quattro reali nel confronto dei costi.

Teoria collegata