Fast Fourier Transform - algoritmo ricorsivo e trasformata inversa
In questa pagina 5
La FFT è un algoritmo divide and conquer (vedi Divide and conquer - proprietà di sottostruttura e albero delle chiamateUn algoritmo divide and conquer nasce da una proprietà di sottostruttura (funzioni Divide e Conquer, base n0) con sottoistanze di taglia strettamente minore; l'albero delle chiamate ne descrive l'esecuzione, e il D&C non ha memoria (ripete le sottoistanze uguali). Esempio completo: MAX di un array, con correttezza per induzione, ricorrenza e conteggio esatto n-1 tramite il teorema sugli alberi binari pieni.Divide and conquer - proprietà di sottostruttura e albero delle chiamate →) per calcolare la DFT (definita in DFT, matrice di Fourier e radici n-esime dell'unitàla DFT di ordine n valuta un polinomio di grado limitato da n sulle n radici n-esime dell'unità, y_i = p(ω^i) con ω = e^{2πi/n}; è il prodotto per la matrice di Fourier F_n, una Vandermonde invertibile. Le radici formano un gruppo moltiplicativo e valgono tre lemmi: cancellazione (ω_{dn}^{dk} = ω_n^k, ω_n^{n/2} = -1), dimezzamento (i quadrati delle n radici sono le n/2 radici n/2-esime, ciascuna due volte) e somma (la somma delle potenze di ω^k vale n se k è multiplo di n, 0 altrimenti). Teorema di convoluzione lineare: (c|0) = DFT^{-1}{2n}(DFT{2n}(a|0) ⊙ DFT_{2n}(b|0)).DFT, matrice di Fourier e radici n-esime dell'unità →) in tempo invece di . Qui il punto di vista è quello dell'algoritmo: sottostruttura, correttezza per induzione, ricorrenza con soluzione esatta. Gli stessi passi, letti come fattorizzazione della matrice di Fourier e come analisi spettrale, sono in Trasformata di Fourier discreta (DFT) e FFTUn segnale discreto periodico di periodo $NT$ ha una trasformata discreta e periodica, la DFT: $S(kF)=\sum_{n=0}^{N-1}T,s(nT)e^{-i2\pi kn/N}$, con $F=1/(NT)$, e $s(nT)=\sum_{k=0}^{N-1}F,S(kF)e^{i2\pi kn/N}$. Dipende da soli $N$ numeri, si calcola senza approssimazioni e con la FFT costa $N\log_2N$ invece di $N^2$. I coefficienti di Fourier del segnale periodico sono $S_k=F,S(kF)$. La DFT dà anche campioni della trasformata di un segnale discreto o continuo a durata limitata (con zero-padding), ma la scalatura $T$ e l'asse delle frequenze vanno gestiti con cura.Trasformata di Fourier discreta (DFT) e FFT → e FFT e zero-padding - TF, TFtd e asse delle pulsazioniLa FFT dei campioni di un segnale a durata finita, moltiplicata per il passo $T_c$, approssima la trasformata di Fourier: $X(\omega_k)\approx T_c,\mathtt{fft}(x,M)[k]$ con $\omega_k=\frac{2\pi k}{MT_c}$ (e fattore di fase $e^{-j\omega t_0}$ se l'asse parte da $t_0$). Lo zero-padding ($M>N$) infittisce i punti della stessa TFtd senza aggiungere informazione; la risoluzione dipende dalla durata osservata. Per un segnale reale $|X|$ è simmetrico: il picco in $k$ ha un gemello in $M-k$.FFT e zero-padding - TF, TFtd e asse delle pulsazioni →.
D'ora in avanti è una potenza di due. La restrizione non pesa per la convoluzione: si può sempre fare il padding fino alla potenza di due successiva.
La proprietà di sottostruttura
Caso base. : il polinomio è costante, , e la sua valutazione in è . Quindi (si restituisce comunque un vettore, di una componente).
Divisione. Per si dividono i coefficienti in base alla parità dell'indice: che sono i coefficienti dei polinomi di grado limitato da (Non è una divisione in due metà contigue, come nella ricerca del massimo o nei blocchi delle matrici.)
Identità polinomiale. Per ogni :
Dimostrazione. è la somma dei monomi di grado pari di ; è la somma dei monomi di grado dispari.
Esempio. dà e , e infatti .
Teorema (sottostruttura). Siano , , . Per :
Dimostrazione. Per le prime componenti: Per le ultime , con :
Ogni coppia di valutazioni sullo stesso punto produce, con le due combinazioni , due valori distinti di : i termini comuni si calcolano una volta sola. Questa coppia di formule si chiama butterfly (farfalla).
L'algoritmo
FFT(a)
n <- a.len
if n = 1 then return a { base }
a0 <- (a[0], a[2], ..., a[n-2]) { divide: indici pari }
a1 <- (a[1], a[3], ..., a[n-1]) { divide: indici dispari }
y0 <- FFT(a0); y1 <- FFT(a1) { recurse }
ON <- e^(i 2 pi / n) { conquer: ON = w_n }
ONI <- 1 { all'inizio dell'iterazione i, ONI = w_n^i }
for i <- 0 to n/2 - 1
t <- ONI * y1[i]
y[i] <- y0[i] + t
y[i + n/2] <- y0[i] - t
ONI <- ONI * ON
return yCorrettezza. Induzione sull'esponente con . Per è il caso base. Per , la taglia delle sottoistanze è e per ipotesi induttiva y0 e y1 sono e . Il ciclo calcola, con ONI (invariante: alla fine dell'iterazione vale ), le due formule del teorema di sottostruttura.
Costo esatto. Ogni iterazione del ciclo fa operazioni tra complessi: due prodotti (t e ONI) e due somme/differenze. Il ciclo ha iterazioni: lavoro di ricombinazione . Quindi
Soluzione esatta: . Dimostrazione per induzione. . Se , allora . (Verificato contando le operazioni di un'implementazione per .)
Lo stesso risultato segue dal Master Theorem - enunciato, casi e applicazioniMaster Theorem per T(n) = aT(n/b) + w(n): si confronta w(n) con la funzione soglia n^(log_b a). Caso 1 (w minore di una potenza polinomiale): Theta(n^(log_b a)); caso 2 (w della stessa taglia): Theta(n^(log_b a) log n); caso 3 (w maggiore e regolare): Theta(w(n)). Prova completa dai livelli dell'albero, versione estesa (parti intere, n0 qualsiasi), esempi, e l'uso scorretto quando nessun caso si applica (w = n log n).Master Theorem - enunciato, casi e applicazioni →: sottoistanze di taglia , soglia , lavoro dello stesso ordine: caso 2, . L'albero delle chiamate ha livelli, foglie, e a ogni livello il lavoro totale è (Albero della ricorrenza e formula generale per le ricorrenzeL'albero della ricorrenza ha la forma dell'albero delle chiamate dell'istanza peggiore e T(n) è la somma dei lavori dei nodi. Per la famiglia T(n) = s(n)T(f(n)) + w(n) con base T0 per n <= n0, contando i nodi per livello con le iterate di f e il livello f*(n,n0) si ottiene la formula chiusa T(n) = somma_l [prodotto_j s(f^(j)(n))] w(f^(l)(n)) + [prodotto s] T0, verificata per induzione e applicata a esempi (merge sort, Hanoi, ricorrenze con radice).Albero della ricorrenza e formula generale per le ricorrenze →; richiami sull'ordine di grandezza in Notazione asintoticaDefinizioni di O, Omega, Theta e o piccolo con le costanti c ed n0; esempi con costanti esplicite; proprietà (polinomi, esponenziali, logaritmi, somme, implicazioni tra notazioni); sommatorie notevoli; terminologia (logaritmica, lineare, polinomiale, esponenziale).Notazione asintotica →).
Osservazione. Se le potenze sono precalcolate in una tabella, ogni iterazione fa un prodotto e due somme: operazioni per livello, cioè in tutto. Il costo del corso conta anche l'aggiornamento di ONI.
Esempio
, . Le sottoistanze sono e ; con , :
- e .
- (): , .
- (): , , .
Risultato , uguale alla DFT calcolata dalla definizione.
Esempio
. Le foglie dell'albero, lette da sinistra, sono (indici in ordine di bit invertiti).
| livello | trasformate calcolate |
|---|---|
| , , , | |
| , pari | , , , |
| , dispari | (stessi passaggi con e ) |
All'ultimo livello e , :
| 0 | ||||
| 1 | ||||
| 2 | ||||
| 3 |
Quindi . Si noti la simmetria coniugata () che vale perché è reale.
La trasformata inversa
L'inversa è l'interpolazione da ai coefficienti.
Teorema (matrice inversa di Fourier). per .
Dimostrazione. Sia . L'elemento di è Se la ragione è e la somma vale : l'elemento è . Se , allora , che non contiene multipli di : per il lemma di somma la somma è . Quindi , e per matrici quadrate una inversa sinistra è anche destra (Matrice inversaL'inversa di una matrice quadrata A è la matrice A⁻¹ con A A⁻¹ = A⁻¹ A = I; esiste se e solo se rango(A) = n e si calcola con Gauss-Jordan riducendo (A | I) fino a (I | A⁻¹).Matrice inversa →).
è quindi una Vandermonde sulle potenze negative divisa per (le sue righe sono una permutazione di quelle di ). Esplicitamente Cioè l'interpolazione da è una valutazione del polinomio che ha come coefficienti i valori , nei punti , seguita da una divisione per .
Primo metodo: FFT sulle potenze negative. I lemmi di cancellazione, dimezzamento e somma valgono anche con come radice principale (le radici sono le stesse), quindi la FFT funziona identica con al posto di :
FFT_NEG(y)
n <- y.len
if n = 1 then return y
y0 <- (y[0], y[2], ..., y[n-2]); y1 <- (y[1], y[3], ..., y[n-1])
a0 <- FFT_NEG(y0); a1 <- FFT_NEG(y1)
ON_NEG <- e^(-i 2 pi / n) { = w_n^(-1) }
ONI <- 1
for i <- 0 to n/2 - 1
t <- ONI * a1[i]
a[i] <- a0[i] + t
a[i + n/2] <- a0[i] - t
ONI <- ONI * ON_NEG
return a
INV_FFT(y)
n <- y.len
a <- FFT_NEG(y)
for i <- 0 to n-1
a[i] <- a[i] / n
return aLa divisione per va fatta fuori dalla ricorsione, una volta sola: se fosse dentro, ogni livello dividerebbe per la propria taglia e si accumulerebbe il fattore sbagliato. Il costo è .
Secondo metodo: stessa FFT e rovesciamento. Poiché , la valutazione di nei punti è la DFT di letta in ordine rovesciato: dove per un vettore si pone (l'indice resta al suo posto, gli altri si ribaltano).
INV_FFT(y)
n <- y.len
a' <- FFT(y)
a[0] <- a'[0] / n
for i <- 1 to n-1
a[i] <- a'[n-i] / n
return aEsempio. (dall'esempio di prima). : per esempio . Rovesciando: ; dividendo per : , i coefficienti originali.
Prodotto di polinomi con la FFT
LIN_CONV(a, b)
n <- a.len { n potenza di due }
ya <- FFT((a | 0_n)); yb <- FFT((b | 0_n)) { valutazione su Omega_2n }
for i <- 0 to 2n-1
yc[i] <- ya[i] * yb[i]
return INV_FFT(yc) { restituisce (c | 0) }Costo esatto. Tre trasformate di ordine , ciascuna operazioni; in più prodotti e moltiplicazioni per nell'inversa:
Verificato con un'implementazione che conta le operazioni, per , e confrontando il risultato con numpy.convolve.
Per la convoluzione per definizione il costo è . Il confronto per qualche valore:
| 8 | 16 | 32 | 64 | 128 | 1024 | |
|---|---|---|---|---|---|---|
| definizione | 113 | 481 | 1985 | 8065 | 32513 | 2095105 |
| LIN_CONV | 416 | 1024 | 2432 | 5632 | 12800 | 139264 |
Grafico interattivo: Operazioni per moltiplicare due polinomi con n coefficienti: per definizione 2n² − 2n + 1, con la FFT 12 n log₂(2n) + 4n; le curve si incrociano tra n = 32 (conviene la definizione, 1985 contro 2432) e n = 64 (conviene la FFT, 8065 contro 5632)
Per piccoli la definizione è più economica (costanti più basse): è lo stesso fenomeno che motiva gli algoritmi ibridi (Algoritmo di Strassen e ibridazioneStrassen calcola il prodotto n x n con 7 chiamate ricorsive invece di 8, usando 10 somme/sottrazioni nel divide e 8 nel conquer: T(n) = 7T(n/2) + (9/2)n^2, Theta(n^(log2 7)) con soluzione esatta 7n^(log2 7) - 6n^2; la costante 7 è più che tripla di quella dell'iterativo (2) e Strassen batte l'iterativo solo da n = 655 (per le potenze di 2, da 1024). L'ibridazione cambia il caso base (iterativo per n <= n0): costo n^(log2 7)(2n0+5)/n0^(log2 7 - 2) - 6n^2, minimo per n0 = 8 con costante ~3.92.Algoritmo di Strassen e ibridazione →).
Taglie generiche. Se non è una potenza di due basta portare entrambi i vettori alla lunghezza , la prima potenza di due almeno pari a (e minore di ). Per vettori di lunghezze diverse e si porta tutto alla prima potenza di due . Il costo resta .
Nota numerica. Con numeri in virgola mobile le radici sono approssimate e il risultato ha piccoli errori (ad esempio parti immaginarie dell'ordine di al posto di ); con coefficienti interi si arrotonda. Un uso diverso della stessa idea, per convolvere segnali molto lunghi a blocchi, è in 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 →.
Domande d'esame
- Scrivere e risolvere la ricorrenza del numero di operazioni tra complessi della FFT, contando 4 operazioni per ogni iterazione del ciclo di ricombinazione. Traccia: , , soluzione , oppure caso 2 del Master Theorem.
- Perché la divisione per della trasformata inversa si esegue fuori dalla ricorsione? Traccia: l'inversa è per la valutazione sulle potenze negative; la FFT ricorsiva su non ha il fattore, che va applicato una sola volta al risultato finale.
- Dato , ricavare usando soltanto la FFT diretta. Traccia: , si rovescia in e si divide per : .
Esercizi svolti: Esercizio - matrice di Fourier per una matrice generica a sinistra e a destra e per aI + bU (compito del 27 gennaio 2025, es. 2); Esercizio - convoluzione con il vettore delle potenze di due in tempo lineare (compito del 5 settembre 2025, es. 2); Esercizio - domande di prima parte su polinomi, DFT e FFT (simulazioni d'esame).
Versione ripasso
- Sottostruttura (, vedi DFT, matrice di Fourier e radici n-esime dell'unitàla DFT di ordine n valuta un polinomio di grado limitato da n sulle n radici n-esime dell'unità, y_i = p(ω^i) con ω = e^{2πi/n}; è il prodotto per la matrice di Fourier F_n, una Vandermonde invertibile. Le radici formano un gruppo moltiplicativo e valgono tre lemmi: cancellazione (ω_{dn}^{dk} = ω_n^k, ω_n^{n/2} = -1), dimezzamento (i quadrati delle n radici sono le n/2 radici n/2-esime, ciascuna due volte) e somma (la somma delle potenze di ω^k vale n se k è multiplo di n, 0 altrimenti). Teorema di convoluzione lineare: (c|0) = DFT^{-1}{2n}(DFT{2n}(a|0) ⊙ DFT_{2n}(b|0)).DFT, matrice di Fourier e radici n-esime dell'unità →): . Si dividono i coefficienti in pari e dispari ; identità (monomi pari + monomi dispari). Per : e . Dimostrazione: identità polinomiale, dimezzamento , e per le ultime componenti e .
- FFT: base ; divide in pari/dispari; due chiamate di taglia ; ciclo
for i <- 0 to n/2-1:t <- ONI*y1[i],y[i] <- y0[i]+t,y[i+n/2] <- y0[i]-t,ONI <- ONI*ON. Correttezza per induzione su con (ipotesi sulle due sottoistanze,ONI). - Costo: operazioni per iterazione, iterazioni: , . Soluzione esatta (induzione: ); caso 2 del Master Theorem - enunciato, casi e applicazioniMaster Theorem per T(n) = aT(n/b) + w(n): si confronta w(n) con la funzione soglia n^(log_b a). Caso 1 (w minore di una potenza polinomiale): Theta(n^(log_b a)); caso 2 (w della stessa taglia): Theta(n^(log_b a) log n); caso 3 (w maggiore e regolare): Theta(w(n)). Prova completa dai livelli dell'albero, versione estesa (parti intere, n0 qualsiasi), esempi, e l'uso scorretto quando nessun caso si applica (w = n log n).Master Theorem - enunciato, casi e applicazioni → (soglia , lavoro ). Con potenze precalcolate . Albero: livelli, foglie, lavoro per livello.
- Esempio : : , ; , , , .
- Esempio : ; pari , dispari ; simmetria coniugata perché è reale.
- Inversa: . Dimostrazione: , vale se e altrimenti perché non è multiplo di (lemma di somma). Quindi con : l'interpolazione da è una valutazione sulle potenze negative.
- INV_FFT, metodo 1: FFT_NEG (stessa FFT con ), poi dividere per fuori dalla ricorsione; costo . Metodo 2: con , perché . Esempio: , rovescio , diviso : .
- LIN_CONV: padding a , due FFT, prodotto , INV_FFT; costo contro della definizione (la FFT conviene da : contro ). Taglie non potenze di due: padding a ; lunghezze : prima potenza di due . Overlap-add: 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 →.
- Pseudocodice dell'inversa:
FFT_NEGè la FFT conON_NEG <- e^(-i 2 pi / n);INV_FFT(y):a <- FFT_NEG(y); for i <- 0 to n-1: a[i] <- a[i]/n; return a. Metodo 2:a' <- FFT(y); a[0] <- a'[0]/n; for i <- 1 to n-1: a[i] <- a'[n-i]/n. - Domande tipo: ricorrenza della FFT con e soluzione ; perché la divisione per è fuori dalla ricorsione (l'inversa è per la valutazione sulle potenze negative, e la ricorsione non ha quel fattore); come ricavare da con la sola FFT diretta: , rovescio e divisione per danno .
- Esercizi svolti: Esercizio - matrice di Fourier per una matrice generica a sinistra e a destra e per aI + bU (compito del 27 gennaio 2025, es. 2); Esercizio - convoluzione con il vettore delle potenze di due in tempo lineare (compito del 5 settembre 2025, es. 2); Esercizio - domande di prima parte su polinomi, DFT e FFT (simulazioni d'esame).
- Errori tipici: dividere per dentro la ricorsione; usare al posto di nell'inversa; dimenticare di rovesciare gli indici nel metodo 2 (l'indice resta); applicare la FFT a taglie non potenze di due senza padding.
Esercizi su questo argomento
- Esercizio - convoluzione con il vettore delle potenze di due in tempo lineare (compito del 5 settembre 2025, es. 2)
- Esercizio - domande di prima parte su polinomi, DFT e FFT (simulazioni d'esame)
- Esercizio - matrice di Fourier per una matrice generica a sinistra e a destra e per aI + bU (compito del 27 gennaio 2025, es. 2)
- Esercizio - polinomio con tutte le radici dell'unità tranne 1 e -1, valutazione e DFT dei coefficienti (compito del 26 giugno 2025, es. 1)
- Esercizio - prodotto di matrici circolanti e convoluzione ciclica con la DFT (esercizi su supercircolanti e circolanti, es. CR 10)