Salta al contenuto
Note per Studenti Esercizio - laboratorio 4, segnali continui aperiodici e risoluzione

Esercizio - laboratorio 4, segnali continui aperiodici e risoluzione

In questa pagina 6

Testo (laboratorio 4 del corso Teoria dei Segnali, UniPD, file lab4.m parte 14 e parte14_variazioni.m). Un impulso rettangolare continuo di ampiezza A=2A=2 V e semidurata T2=5T_2=5 s, s(t)=As(t)=A per ∣t∣≤T2|t|\le T_2, viene campionato su [−T1,T1)[-T_1,T_1) con NN punti, passo dt=2T1Ndt=\frac{2T_1}N. Calcolarne la trasformata con la FFT, S=dt⋅fftS=dt\cdot\text{fft} con riordino delle due metà, e confrontarla con S(f)=2AT2sinc⁡(2T2f)S(f)=2AT_2\operatorname{sinc}(2T_2f). Discutere come NN e T1T_1 cambiano il passo in frequenza df=1N dt=12T1df=\frac1{N\,dt}=\frac1{2T_1} e l'estensione dell'asse ±12 dt\pm\frac1{2\,dt}, nei tre casi N=120, T1=70N=120,\ T_1=70; N=1000, T1=70N=1000,\ T_1=70; N=1000, T1=13N=1000,\ T_1=13, e dire quando compare aliasing.

Teoria usata: Trasformata di FourierLa trasformata di Fourier $S(f)=\int s(t)e^{-i2\pi ft}dt$ associa a un segnale continuo (anche aperiodico) la sua rappresentazione in frequenza; l'antitrasformata $s(t)=\int S(f)e^{i2\pi ft}df$ lo ricostruisce, perché gli esponenziali $e^{i2\pi ft}$ sono ortogonali su tutto $\mathbb R$ ($\int e^{i2\pi ft}dt=\delta(f)$). Per un segnale reale $S(-f)=S^*(f)$. Si calcola per i segnali notevoli (rect $\leftrightarrow$ sinc, $e^{-\alpha t}\mathbf 1(t)\leftrightarrow\frac1{\alpha+i2\pi f}$, gaussiana, $\delta\leftrightarrow1$, $1\leftrightarrow\delta$, gradino) e per i segnali periodici, la cui trasformata è un treno di impulsi di area $S_n$ in $nF$.Trasformata di Fourier →, Campionamento e ricostruzioneIl campionamento $s_c(nT)=s(nT)$ trasforma un segnale continuo in uno discreto e, in frequenza, ripete lo spettro con periodo $F_c=1/T$: $S_c(f)=\sum_kS(f-kF_c)$. Se le repliche si sovrappongono si ha aliasing e il segnale non è recuperabile. Un interpolatore $\mathbb Z(T)\to\mathbb R$ con risposta impulsiva $g$ produce $\tilde s(t)=\sum_nT g(t-nT)s(nT)$ e $\tilde S=G,S_c$. Teorema del campionamento: se $s$ ha banda $B$ e $F_c\ge2B$, l'interpolatore ideale $G=\operatorname{rect}(f/F_c)$ ricostruisce esattamente $s(t)=\sum s(nT)\operatorname{sinc}(F_c(t-nT))$. Se le ipotesi non valgono c'è un errore, in banda e fuori banda, riducibile con un prefiltro anti-aliasing.Campionamento e ricostruzione →, 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 →, Segnali notevoli - gradino, rect, tri, sinc ed esponenzialiI segnali di uso più frequente sono la costante, la sinusoide $A_0\cos(2\pi f_0t+\varphi_0)$ e l'esponenziale complesso $Ae^{i2\pi f_0t}$ (periodici, a potenza finita), il gradino $\mathbf 1(t)$ e il segno, e gli impulsi a energia finita: $\operatorname{rect}$ (area $D$), $\operatorname{tri}$, $\operatorname{sinc}$ (area $1$), la gaussiana $e^{-\pi t^2}$ e gli esponenziali smorzati. Per ciascuno si sanno a memoria forma, area ed energia; gli altri segnali si ottengono da questi con traslazioni, scalature, somme e differenze.Segnali notevoli - gradino, rect, tri, sinc ed esponenziali →, Proprietà della trasformata di FourierLe regole della trasformata di Fourier trasformano operazioni sui segnali in operazioni sulle trasformate: linearità, ribaltamento, coniugio, traslazione nel tempo ($\times e^{-i2\pi ft_0}$) e in frequenza, convoluzione $\leftrightarrow$ prodotto, cambio di scala $s(at)\to\frac1{|a|}S(f/a)$, derivazione ($\times i2\pi f$), integrazione, regola di simmetria ($S(t)\to s(-f)$). Area $S(0)=\int s$, teorema di Parseval $\int|s|^2=\int|S|^2$. Durata e banda sono inversamente legati e un segnale non può avere durata e banda entrambe limitate; la banda del prodotto è la somma delle bande. Con queste regole si ricavano quasi tutte le trasformate senza integrare.Proprietà della trasformata di Fourier → (traslazione nel tempo e fase).

Cosa si vuole calcolare e perché

La trasformata di un segnale continuo non periodico è S(f)=∫s(t) e−i2πftdtS(f)=\int s(t)\,e^{-i2\pi ft}dt (Trasformata di FourierLa trasformata di Fourier $S(f)=\int s(t)e^{-i2\pi ft}dt$ associa a un segnale continuo (anche aperiodico) la sua rappresentazione in frequenza; l'antitrasformata $s(t)=\int S(f)e^{i2\pi ft}df$ lo ricostruisce, perché gli esponenziali $e^{i2\pi ft}$ sono ortogonali su tutto $\mathbb R$ ($\int e^{i2\pi ft}dt=\delta(f)$). Per un segnale reale $S(-f)=S^*(f)$. Si calcola per i segnali notevoli (rect $\leftrightarrow$ sinc, $e^{-\alpha t}\mathbf 1(t)\leftrightarrow\frac1{\alpha+i2\pi f}$, gaussiana, $\delta\leftrightarrow1$, $1\leftrightarrow\delta$, gradino) e per i segnali periodici, la cui trasformata è un treno di impulsi di area $S_n$ in $nF$.Trasformata di Fourier →). Un calcolatore ha solo NN campioni s(tm)s(t_m), quindi calcola la somma di Riemann S(f)≈∑mdt  s(tm) e−i2πftmS(f)\approx\sum_m dt\;s(t_m)\,e^{-i2\pi ft_m} in un numero finito di frequenze f=k dff=k\,df. La FFT dà esattamente questa somma per k=0,…,N−1k=0,\dots,N-1, con due precisazioni:

  • il fattore dtdt è lo stesso del TT di S(kF)=∑T s e…S(kF)=\sum T\,s\,e^{\dots} (laboratorio 4, parti 1-8): ogni campione pesa dtdt;
  • la FFT vuole che il primo elemento sia l'istante t=0t=0, perciò il vettore (che parte da −T1-T_1) va riordinato: i campioni da t=0t=0 in poi vanno davanti, quelli dei tempi negativi dietro (per la periodicità, sono equivalenti ai tempi T1,…,2T1T_1,\dots,2T_1).

Le due domande del laboratorio sono: quanto fitta è la griglia in frequenza (la risoluzione) e fin dove arriva (l'estensione dell'asse), e come dipendono da NN e T1T_1.

Parte 14 - il caso N=1000N=1000, T1=70T_1=70

python
import numpy as np
import matplotlib.pyplot as plt

# PARTE 14 - rect continuo (ampiezza A = 2, semi-durata T2 = 5 s) campionato su [-T1, T1) con N punti
N = 1000
T1 = 70

dt = 2 * T1 / N                        # passo di campionamento: durata totale 2 T1 divisa per N
t = np.arange(N) * dt - T1             # istanti da -T1 a T1 - dt

A = 2
T2 = 5

s = A * (np.abs(t) <= T2)              # il rect: A dove |t| <= T2

plt.figure(figsize=(10, 6))
plt.subplot(2, 2, 1)
plt.plot(t, s)
plt.xlabel('Tempo [s]'); plt.ylim(-0.5, A + 0.5); plt.grid(True)

# trasformata analitica S(f) = 2 A T2 sinc(2 T2 f)
fa = np.linspace(-3, 3, 6001)          # MATLAB [-3:0.001:3]
Sa = A * 2 * T2 * np.sinc(fa * (2 * T2))

plt.subplot(2, 2, 4)
plt.plot(fa, np.real(Sa), color='blue', label='Parte reale')
plt.plot(fa, np.imag(Sa), color='red', label='Parte immaginaria')
plt.grid(True); plt.xlabel('Frequenza [Hz]'); plt.xlim(-3, 3); plt.legend()

# trasformata numerica: il tempo 0 deve stare al primo posto del vettore
s = np.concatenate((s[N // 2:], s[:N // 2]))           # MATLAB [s(N/2+1:N), s(1:N/2)]

df = 1 / (N * dt)                      # passo in frequenza: 1 / durata totale
f = np.arange(-N // 2, N // 2) * df    # asse centrato: da -N/2 df a (N/2 - 1) df

S = dt * np.fft.fft(s)                 # il fattore dt e' la scalatura "area" della trasformata di un segnale continuo
S = np.concatenate((S[N // 2:], S[:N // 2]))           # riordino: frequenze negative a sinistra

plt.subplot(2, 2, 2)
plt.plot(f, np.real(S), color='blue', label='Parte reale')
plt.plot(f, np.imag(S), color='red', label='Parte immaginaria')
plt.grid(True); plt.xlabel('Frequenza [Hz]'); plt.xlim(-3, 3); plt.legend()
plt.show()

campioni_rect = int(np.sum(np.abs(t) <= T2))
print(f"dt = {dt:.3f} s, df = 1/(N dt) = 1/(2 T1) = {df:.5f} Hz, asse da {f[0]:.3f} a {f[-1]:.3f} Hz (= +-1/(2 dt) = {1 / (2 * dt):.3f})")
print(f"campioni a 2: {campioni_rect}  (larghezza numerica {campioni_rect * dt:.3f} s contro 2 T2 = {2 * T2} s)")
print(f"S(0) numerico = {S[N // 2].real:.4f}  (= dt * somma = A * larghezza numerica);  S(0) teorico = 2 A T2 = {2 * A * T2}")
sel = np.abs(f) <= 3
print(f"errore massimo |S - Sa| per |f| <= 3: {np.max(np.abs(S[sel] - A * 2 * T2 * np.sinc(f[sel] * 2 * T2))):.4f}")
print(f"parte immaginaria massima: {np.max(np.abs(S.imag)):.1e}  (il rect e' pari: la trasformata e' reale)")

Risultato:

dt = 0.140 s, df = 1/(N dt) = 1/(2 T1) = 0.00714 Hz, asse da -3.571 a 3.564 Hz (= +-1/(2 dt) = 3.571)
campioni a 2: 71  (larghezza numerica 9.940 s contro 2 T2 = 10 s)
S(0) numerico = 19.8800  (= dt * somma = A * larghezza numerica);  S(0) teorico = 2 A T2 = 20
errore massimo |S - Sa| per |f| <= 3: 0.1579
parte immaginaria massima: 1.3e-15  (il rect e' pari: la trasformata e' reale)

La trasformata analitica. s(t)=Arect⁡t2T2s(t)=A\operatorname{rect}\frac t{2T_2} (un rect di larghezza 2T2=102T_2=10 e altezza A=2A=2, Segnali notevoli - gradino, rect, tri, sinc ed esponenzialiI segnali di uso più frequente sono la costante, la sinusoide $A_0\cos(2\pi f_0t+\varphi_0)$ e l'esponenziale complesso $Ae^{i2\pi f_0t}$ (periodici, a potenza finita), il gradino $\mathbf 1(t)$ e il segno, e gli impulsi a energia finita: $\operatorname{rect}$ (area $D$), $\operatorname{tri}$, $\operatorname{sinc}$ (area $1$), la gaussiana $e^{-\pi t^2}$ e gli esponenziali smorzati. Per ciascuno si sanno a memoria forma, area ed energia; gli altri segnali si ottengono da questi con traslazioni, scalature, somme e differenze.Segnali notevoli - gradino, rect, tri, sinc ed esponenziali →) ha trasformata S(f)=A⋅2T2sinc⁡(2T2f)=20sinc⁡(10f)S(f)=A\cdot2T_2\operatorname{sinc}(2T_2f)=20\operatorname{sinc}(10f): reale e pari, S(0)=20S(0)=20 (l'area A⋅2T2A\cdot2T_2), zeri nei multipli di 12T2=0,1\frac1{2T_2}=0{,}1 Hz, decadimento 1f\frac1f delle code. La parte immaginaria è nulla (segnale pari).

Grafico interattivo: Trasformata del rect di ampiezza 2 e semidurata 5: S(f) = 20 sinc(10 f), reale e pari, con S(0) = 20 (l'area), lobo principale tra ±0,1 Hz e zeri nei multipli di 0,1 Hz

Il campionamento e l'asse dei tempi. Con N=1000N=1000 e T1=70T_1=70 il passo è dt=1401000=0,14dt=\frac{140}{1000}=0{,}14 s; t=m dt−T1t=m\,dt-T_1 va da −70-70 a 69,8669{,}86. I campioni con ∣t∣≤5|t|\le5 sono 7171 (i campioni sono nei punti −70+0,14 m-70+0{,}14\,m e ±5\pm5 non ne è uno), quindi la larghezza numerica del rect è 71⋅0,14=9,9471\cdot0{,}14=9{,}94 s e non 1010 s: la FFT vede un rect leggermente più stretto, con area A⋅9,94=19,88A\cdot9{,}94=19{,}88. Questa è la causa del S(0)=19,88S(0)=19{,}88 invece di 2020. È un effetto del campionamento dei bordi, non della FFT.

Il riordino e gli assi. s = concatenate((s[N//2:], s[:N//2])) mette in testa l'elemento di indice N/2=500N/2=500, che è l'istante t=−70+500⋅0,14=0t=-70+500\cdot0{,}14=0. La FFT restituisce le frequenze nell'ordine 0,df,…,(N2−1)df,−N2df,…,−df0,df,\dots,(\frac N2-1)df,-\frac N2df,\dots,-df: si riordina anche S e si costruisce f = np.arange(-N//2, N//2) * df con

df=1N dt=12T1=1140=0,00714 Hz.df=\frac1{N\,dt}=\frac1{2T_1}=\frac1{140}=0{,}00714\text{ Hz}.

L'asse va da −N2df=−3,571-\frac N2df=-3{,}571 Hz a 3,5643{,}564 Hz, cioè ±12 dt\pm\frac1{2\,dt}. Il risultato è reale (parte immaginaria ∼10−15\sim10^{-15}) e riproduce 20sinc⁡(10f)20\operatorname{sinc}(10f) con un errore massimo di 0,160{,}16 su un picco di 2020 (meno dell'1%1\%).

Le due regole: risoluzione e estensione

  • Passo in frequenza df=1N dt=12T1df=\dfrac1{N\,dt}=\dfrac1{2T_1}: dipende solo dalla durata totale 2T12T_1 della finestra di osservazione. Una finestra lunga dà una griglia fitta, "alta definizione". È la dualità di prima: campionare in frequenza con passo dfdf equivale a ripetere il segnale nel tempo con periodo 1df=2T1\frac1{df}=2T_1, e questo non deve sovrapporre le copie (serve 2T1≥2T_1\ge durata del segnale =2T2=2T_2).
  • Estensione dell'asse ±12 dt\pm\dfrac1{2\,dt}: dipende solo dal passo di campionamento dtdt. È la metà della frequenza di campionamento Fc=1dtF_c=\frac1{dt}: oltre non si può vedere, e quello che oltre c'è si ripiega dentro (aliasing).
  • Numero di righe N=2T1dt=1/dtdfN=\dfrac{2T_1}{dt}=\dfrac{1/dt}{df} (l'ampiezza totale dell'asse, 1dt\frac1{dt}, divisa per il passo): con NN fisso, aumentare T1T_1 migliora la risoluzione ma peggiora l'estensione (e viceversa). Per migliorare entrambe bisogna aumentare NN.

Le variazioni: tre scelte di NN e T1T_1

python
# VARIAZIONI - la stessa analisi con tre scelte diverse di N e T1
def spettro_rect(N, T1, A=2, T2=5):
    dt = 2 * T1 / N
    t = np.arange(N) * dt - T1
    s = A * (np.abs(t) <= T2)
    s = np.concatenate((s[N // 2:], s[:N // 2]))
    df = 1 / (N * dt)
    f = np.arange(-N // 2, N // 2) * df
    S = dt * np.fft.fft(s)
    S = np.concatenate((S[N // 2:], S[:N // 2]))
    return t, f, S, dt, df

def S_vera(f, A=2, T2=5):
    return A * 2 * T2 * np.sinc(f * 2 * T2)

casi = [(120, 70), (1000, 70), (1000, 13)]
risultati = {}
print("   N   T1      dt        df        f_max=1/(2dt)   righe per lobo      S(0)      errore (|f| <= 0.4)")
for N_, T1_ in casi:
    t_, f_, S_, dt_, df_ = spettro_rect(N_, T1_)
    risultati[(N_, T1_)] = (t_, f_, S_, dt_, df_)
    sel = np.abs(f_) <= 0.4
    err = np.max(np.abs(S_[sel] - S_vera(f_[sel])))
    righe_lobo = 0.2 / df_                       # il lobo principale e' largo 2 * (1/(2 T2)) = 0.2 Hz
    print(f"{N_:>5} {T1_:>3} {dt_:>9.4f} {df_:>9.5f} {1 / (2 * dt_):>13.3f} {righe_lobo:>14.1f} {S_[N_ // 2].real:>12.4f} {err:>14.4f}")

Risultato:

   N   T1      dt        df        f_max=1/(2dt)   righe per lobo      S(0)      errore (|f| <= 0.4)
  120  70    1.1667   0.00714         0.429           28.0      21.0000         1.3791
 1000  70    0.1400   0.00714         3.571           28.0      19.8800         0.1205
 1000  13    0.0260   0.03846        19.231            5.2      20.0200         0.0200
caso dtdt dfdf asse righe nel lobo principale (0,20{,}2 Hz) S(0)S(0) commento
N=120N=120, T1=70T_1=70 1,1671{,}167 s 0,007140{,}00714 Hz ±0,43\pm0{,}43 Hz 2828 21,0021{,}00 griglia fitta, asse corto: aliasing forte
N=1000N=1000, T1=70T_1=70 0,140{,}14 s 0,007140{,}00714 Hz ±3,57\pm3{,}57 Hz 2828 19,8819{,}88 stessa risoluzione, asse 8 volte più lungo
N=1000N=1000, T1=13T_1=13 0,0260{,}026 s 0,03850{,}0385 Hz ±19,2\pm19{,}2 Hz 55 20,0220{,}02 asse molto esteso, griglia sparsa

Caso 1: N=120N=120, T1=70T_1=70 ("poco fitto il segnale nel tempo: range di frequenze limitato; lunga estensione nel tempo: trasformata ad alta definizione"). Il passo di campionamento è grosso, dt=1,17dt=1{,}17 s, e l'asse arriva solo a ±0,43\pm0{,}43 Hz: il lobo principale (±0,1\pm0{,}1 Hz) è disegnato con 2828 righe, ma si vedono pochi lobi laterali (solo quelli fino a 0,430{,}43 Hz). Il rect è rappresentato da soli 99 campioni, di larghezza 9⋅1,167=10,59\cdot1{,}167=10{,}5 s, e S(0)=21S(0)=21 invece di 2020. L'errore massimo sul confronto con la sinc per ∣f∣≤0,4|f|\le0{,}4 Hz è 1,41{,}4, cioè il 7%7\% del picco: qui l'aliasing è forte.

Caso 2: N=1000N=1000, T1=70T_1=70. Stessa durata (2T1=1402T_1=140 s) quindi stessa risoluzione df=0,00714df=0{,}00714 Hz, ma dt=0,14dt=0{,}14 s e l'asse è otto volte più lungo, ±3,57\pm3{,}57 Hz: ora il grafico mostra una trentina di lobi per lato (il file MATLAB limita l'asse a [−3,3][-3,3], dove cadono zeri ogni 0,10{,}1 Hz). L'errore massimo scende a 0,120{,}12 (0,6%0{,}6\% del picco).

Caso 3: N=1000N=1000, T1=13T_1=13 ("molto fitto il segnale nel tempo: range di frequenze ampio; corta estensione nel tempo: trasformata a bassa risoluzione"). La finestra è corta, 2T1=262T_1=26 s, quindi il passo in frequenza è grosso, df=126=0,0385df=\frac1{26}=0{,}0385 Hz: nel lobo principale (0,20{,}2 Hz) cadono solo 55 righe e la curva sembra poligonale. L'asse è molto esteso, ±19,2\pm19{,}2 Hz, e l'errore sulle righe è piccolo, 0,020{,}02 (un rect largo 1010 s sta bene nei 2626 s della finestra: 2T1>2T22T_1>2T_2, nessuna sovrapposizione nel tempo). Con T1<T2=5T_1<T_2=5 s il rect verrebbe troncato dalla finestra, e con T1T_1 appena sopra 55 s le copie periodiche del rect (periodo 2T12T_1) quasi si toccherebbero.

Un errore da non fare è leggere in questi tre casi la risoluzione come un effetto di NN da solo: il caso 1 e il 2 hanno NN diverso e la stessa risoluzione; il caso 2 e il 3 hanno lo stesso NN e risoluzioni diverse. Conta 2T12T_1 per dfdf e dtdt per l'estensione.

Quando compare l'aliasing e il legame con Sc=rep⁡SS_c=\operatorname{rep}S

I campioni s(m dt)s(m\,dt) del rect sono i campioni di un segnale non a banda limitata (la sinc di S(f)S(f) decade come 1f\frac1f e non si annulla mai). Campionarlo con passo dtdt equivale a replicare lo spettro con periodo Fc=1dtF_c=\frac1{dt} (formula del campionamento, Campionamento e ricostruzioneIl campionamento $s_c(nT)=s(nT)$ trasforma un segnale continuo in uno discreto e, in frequenza, ripete lo spettro con periodo $F_c=1/T$: $S_c(f)=\sum_kS(f-kF_c)$. Se le repliche si sovrappongono si ha aliasing e il segnale non è recuperabile. Un interpolatore $\mathbb Z(T)\to\mathbb R$ con risposta impulsiva $g$ produce $\tilde s(t)=\sum_nT g(t-nT)s(nT)$ e $\tilde S=G,S_c$. Teorema del campionamento: se $s$ ha banda $B$ e $F_c\ge2B$, l'interpolatore ideale $G=\operatorname{rect}(f/F_c)$ ricostruisce esattamente $s(t)=\sum s(nT)\operatorname{sinc}(F_c(t-nT))$. Se le ipotesi non valgono c'è un errore, in banda e fuori banda, riducibile con un prefiltro anti-aliasing.Campionamento e ricostruzione →):

Sc(f)=rep⁡FcS(f)=∑k=−∞∞S(f−kFc).S_c(f)=\operatorname{rep}_{F_c}S(f)=\sum_{k=-\infty}^{\infty}S\bigl(f-kF_c\bigr).

La FFT (cioè dt⋅fftdt\cdot\text{fft}) calcola proprio Sc(f)S_c(f) nei punti f=k dff=k\,df, non S(f)S(f). Il confronto con la formula teorica ha quindi due cause di scarto: l'aliasing (le copie centrate in ±Fc, ±2Fc,…\pm F_c,\ \pm2F_c,\dots danno un contributo a ogni ff) e la larghezza numerica del rect (7171 campioni, ecc.), che nella formula rep⁡S\operatorname{rep}S sono già incluse perché è il segnale campionato davvero. Per verificarlo, il blocco seguente confronta SS con una somma di 2⋅20000+12\cdot20000+1 copie della sinc vera:

python
# Il legame con il campionamento: S numerico = ripetizione (rep) dello spettro vero con periodo Fc = 1/dt
K = np.arange(-20000, 20001)
print("   N   T1   errore massimo |S - rep S| (su tutte le righe con |f| <= 3)    contro |S - S_vera|")
for N_, T1_ in casi:
    t_, f_, S_, dt_, df_ = risultati[(N_, T1_)]
    sel = np.where(np.abs(f_) <= 3)[0][::max(1, N_ // 120)]       # un sottoinsieme di righe, per non rallentare
    rep = np.array([np.sum(S_vera(f_[i] - K / dt_)) for i in sel])
    print(f"{N_:>5} {T1_:>3}   {np.max(np.abs(S_[sel] - rep)):.5f}                                               {np.max(np.abs(S_[sel] - S_vera(f_[sel]))):.4f}")

# In f = 0 la ripetizione somma al valore vero 20 le code dei sinc centrati in k/dt
for N_, T1_ in casi:
    t_, f_, S_, dt_, df_ = risultati[(N_, T1_)]
    code = np.sum(S_vera(0 - K / dt_)) - S_vera(0)
    print(f"N = {N_:>4}, T1 = {T1_:>2}: S(0) numerico = {S_[N_ // 2].real:.4f}, 20 + code dei sinc ripetuti = {20 + code:.4f}   (Fc = 1/dt = {1 / dt_:.3f} Hz)")
   N   T1   errore massimo |S - rep S| (su tutte le righe con |f| <= 3)    contro |S - S_vera|
  120  70   0.00004                                               1.4318
 1000  70   0.00001                                               0.1549
 1000  13   0.00000                                               0.0202
N =  120, T1 = 70: S(0) numerico = 21.0000, 20 + code dei sinc ripetuti = 21.0000   (Fc = 1/dt = 0.857 Hz)
N = 1000, T1 = 70: S(0) numerico = 19.8800, 20 + code dei sinc ripetuti = 19.8800   (Fc = 1/dt = 7.143 Hz)
N = 1000, T1 = 13: S(0) numerico = 20.0200, 20 + code dei sinc ripetuti = 20.0200   (Fc = 1/dt = 38.462 Hz)

Lo scarto da rep⁡S\operatorname{rep}S è al più 4⋅10−54\cdot10^{-5} nei tre casi (contro 1,4; 0,15; 0,021{,}4;\ 0{,}15;\ 0{,}02 dallo spettro vero SS), e in f=0f=0 la somma delle code porta il 2020 vero a 21,0021{,}00 (caso 1), 19,8819{,}88 (caso 2), 20,0220{,}02 (caso 3), esattamente i valori della FFT. Il numero S(0)≠20S(0)\ne20 non è un errore di calcolo: è il valore giusto della trasformata del segnale campionato.

L'entità dell'aliasing dipende da quanto vale lo spettro vero in ±Fc2\pm\frac{F_c}2: dal limite ∣S(f)∣≤Aπf=0,64f|S(f)|\le\frac{A}{\pi f}=\frac{0{,}64}{f} si ha circa 1,51{,}5 in f=0,43f=0{,}43 (caso 1, 7% di S(0)S(0)), 0,180{,}18 in f=3,57f=3{,}57 (caso 2, meno dell'1%1\%), 0,0330{,}033 in f=19,2f=19{,}2 (caso 3, circa 0,17%0{,}17\%). Più dtdt è piccolo, più il bordo dell'asse è lontano e più la coda ripiegata è bassa. In concreto, nel caso 1 le copie centrate in ±Fc=±0,857\pm F_c=\pm0{,}857 Hz si sovrappongono alla sinc vera proprio nella zona ∣f∣≲0,43|f|\lesssim0{,}43 che si disegna:

Grafico interattivo: Caso N = 120, T1 = 70: il campionamento con dt = 7/6 s replica lo spettro S(f) = 20 sinc(10 f) con periodo Fc = 1/dt = 6/7 ≈ 0,857 Hz; le tre copie (originale e due vicine) si sovrappongono, e nella banda mostrata dalla FFT (|f| < 0,43 Hz, tratteggio) i lobi delle copie si sommano a quello vero

I tre confronti con il grafico analitico si possono rivedere con un solo disegno (il codice qui sotto riproduce la figura del file parte14_variazioni.m, con la curva teorica tratteggiata):

python
# I tre casi, come nel file parte14_variazioni.m
fig, assi = plt.subplots(3, 2, figsize=(11, 10))
fa = np.linspace(-3, 3, 6001)
for riga, (N_, T1_) in enumerate(casi):
    t_, f_, S_, dt_, df_ = risultati[(N_, T1_)]
    assi[riga, 0].plot(t_, A * (np.abs(t_) <= T2))
    assi[riga, 0].set_xlabel('Tempo [s]'); assi[riga, 0].set_ylabel('Ampiezza [V]'); assi[riga, 0].set_ylim(-0.5, A + 0.5); assi[riga, 0].grid(True)
    assi[riga, 0].set_title(f'N = {N_}, T1 = {T1_}')
    assi[riga, 1].plot(fa, S_vera(fa), 'k--', label='analitica')
    assi[riga, 1].plot(f_, S_.real, 'b.-', label='fft (parte reale)')
    assi[riga, 1].set_xlabel('Frequenza [Hz]'); assi[riga, 1].set_ylabel('[Vs]'); assi[riga, 1].set_xlim(-3, 3); assi[riga, 1].grid(True); assi[riga, 1].legend()
plt.tight_layout()
plt.show()

Controllo

  • df=12T1df=\frac1{2T_1}: 0,007140{,}00714 (casi 1-2) e 0,03850{,}0385 (caso 3); estensione ±12dt\pm\frac1{2dt}: 0,430{,}43, 3,573{,}57, 19,219{,}2 Hz.
  • S(0)S(0): 21,0021{,}00; 19,8819{,}88; 20,0220{,}02 (area numerica = A⋅dt⋅A\cdot dt\cdot numero di campioni a 2); valore vero 2AT2=202AT_2=20.
  • dt⋅fftdt\cdot\text{fft} coincide con ∑kS(f−kFc)\sum_kS(f-kF_c) a meno di 4⋅10−54\cdot10^{-5}.

Versione ripasso

  • Calcolo. S(k df)≈dt⋅fftS(k\,df)\approx dt\cdot\text{fft} sui campioni riordinati (tempo 0 davanti); confronto con S(f)=2AT2sinc⁡(2T2f)=20sinc⁡(10f)S(f)=2AT_2\operatorname{sinc}(2T_2f)=20\operatorname{sinc}(10f).
  • Risoluzione. df=1N dt=12T1df=\frac1{N\,dt}=\frac1{2T_1}: dipende dalla durata della finestra (lunga ⇒\Rightarrow fitta). Estensione ±12dt\pm\frac1{2dt}: dipende dal passo.
  • Tre casi. N=120N=120, T1=70T_1=70: df=0,0071df=0{,}0071, asse ±0,43\pm0{,}43 Hz, aliasing forte; N=1000N=1000, T1=70T_1=70: stessa dfdf, asse ±3,57\pm3{,}57 Hz; N=1000N=1000, T1=13T_1=13: df=0,0385df=0{,}0385, asse ±19,2\pm19{,}2 Hz, pochi punti per lobo.
  • Aliasing. La fft dà Sc=rep⁡1/dtSS_c=\operatorname{rep}_{1/dt}S (a 4⋅10−54\cdot10^{-5}), non SS: sinc a banda illimitata, S(0)=21; 19,88; 20,02S(0)=21;\ 19{,}88;\ 20{,}02 invece di 2020.
  • Condizione. 2T1≥2T22T_1\ge2T_2 (nessuna sovrapposizione nel tempo).

Teoria collegata