Accesso riservato

Esercitazione 2

Modulazione di ampiezza

Autore/Autrice

Paolo Rossi, 235651

Data di Pubblicazione

30 gennaio 2026

Per la consegna dell’esercitazione si faccia riferimento a questo link. Mentre le librerie sono rimandate nell’icona Librerie.

1 Funzioni e parametri generali

# FUNZIONE: Generazione segnale sinusoidale con diverse armoniche
signal <- function(t, pars, rad = FALSE) { 
  stopifnot(is.data.frame(pars))
  with(pars, {
    if (!rad) {
      phi <- phi/180*pi
      f <- 2*pi*f
    }
    map_dbl(t, \(t) sum( map_vec(seq_along(w) , \(i) w[i]*sin(t*f[i] + phi[i] ))))
  })
}
# Parametri
fc <- 2000        # Frequenza di campionamento (Hz)
fm <- 10          # Frequenza del segnale di misura (Hz)
fr <- 15          # Frequenza del rumore (Hz)
fp <- 300         # Frequenza della portante (Hz)
m <- 0.8          # Indice di modulazione (0 < m < 1)
duration <- 2     # Durata del segnale (secondi)

2 Generazione dei segnali

# Vettore temporale
t <- seq(0, duration, by = 1/fc)

# Parametri del segnale di misura
pars_m <- tibble(
  w = c(1, 0.5, 0.3), f = c(fm, 2*fm, 4*fm), phi = c(0, 0, 0))

# Generiamo il segnale di misura:
ym <- tibble(
  t = t,
  y = signal(t, pars_m),
  yn = y + rnorm(length(t), 0, pars_m$w[1]/10),
  f = 0:(length(t)-1)/max(t),
  fft = fft(yn),
  intensity = Mod(fft) / length(t)*2,
  phase = Arg(fft)/pi*180
)

p1 <- ym %>% ggplot(aes(x = t, y = yn)) +
  geom_line(color = "#F8766D") +
  labs(x = "Tempo (s)", y = "Segnale", title = "Segnale di misura")

# Rumore interferente
pars_r <- tibble(
  w = c(1, 0.5, 0.8), f = c(fr, 3*fr, 9*fr), phi = c(0, 40, 90))

r <- tibble(
  t = t,
  y = signal(t, pars_r),
  f = 0:(length(t)-1)/max(t),
  fft = fft(y),
  intensity = Mod(fft) / length(t)*2,
  phase = Arg(fft)/pi*180
)

p2 <- r %>% ggplot(aes(x = t, y = y)) +
  geom_line(color = "#56B4E9") +
  labs(x = "Tempo (s)", y = "Segnale", title = "Rumore interferente")

p1/p2

2.1 Modulazione

# Onda portante: carrier <- cos(2 * pi * fp * t)
# Aggiungiamo alla struttura associata alla misura il segnale modulato:
ym <- ym %>% mutate(
    yn_m = (1 + m * ym$yn) * cos(2 * pi * fp * t),
    fft_m = fft(yn_m),
    intensity_m = Mod(fft_m) / length(t)*2,
    phase_m = Arg(fft_m)/pi*180
  )

ym %>% pivot_longer(
    cols = c(yn, yn_m)
  ) %>% mutate(
    name = factor(name, levels = c("yn_m", "yn"))
  ) %>% ggplot(aes(x = t, y = value, colour = name)) +
  geom_line() +
  scale_colour_discrete(labels = c(
    "yn_m" = "Modulato",
    "yn" = "Misurato"
  )) +
  labs(x = "Tempo (s)", y = "Segnale", colour = "Segnale")

plot_ly() %>%
  add_bars(data = ym, x = ~f, y = ~intensity, name = "Segnale", marker = list(color = "blue")) %>%
  add_bars(x = r$f, y = r$intensity, name = "Rumore", marker = list(color = "red")) %>%
  add_bars(data = ym, x = ~f, y = ~intensity_m, name = "Segnale Modulato", marker = list(color = "green")) %>%
  layout(title = "Spettro di Intensità",
       xaxis = list(title = "Frequenza (Hz)", range = c(0, 500), showgrid = TRUE),
       yaxis = list(title = "Intensità", showgrid = TRUE),
       legend = list(x = 0.25, y = 0.9))

2.2 Esposizione del segnale modulato al rumore

# Effetto interferente sul segnale modulato:
ym <- ym %>% mutate(
    yn_m_n = yn_m + r$y,
    fft_m = fft(yn_m_n),
    intensity_m = Mod(fft_m) / length(t)*2,
    phase_m = Arg(fft_m)/pi*180
  )

plot_ly() %>%
  add_lines(data = ym, x = ~f, y = ~intensity_m, type = "bar", name = "Segnale", marker = list(color= "blue")) %>%
  layout(title = "Spettro segnale modulato affetto da rumore",
       xaxis = list(title = "Frequenza (Hz)", range = c(0, 500), showgrid = TRUE),
       yaxis = list(title = "Intensità", showgrid = TRUE))
plot_ly() %>%
  add_lines(data = ym, x = ~t, y = ~yn_m, name = "Segnale modulato") %>%
  add_lines(data = ym, x = ~t, y = ~yn_m_n, name = "Con effetto interferente") %>%
  layout(title = "Segnale modulato affetto da rumore", 
         xaxis = list(title = "Tempo (s)"), 
         yaxis = list(title = "Segnale"))

3 Ricostruzione del segnale misurato

La ricostruzione del segnale misurato segue principalmente i seguenti passaggi:

  1. eliminazione del rumore interferente;

  2. demodulazione, per ottenere il segnale misurato;

  3. un eventuale filtraggio per attenuare il rumore bianco.

3.1 Eliminazione del rumore interferente

Osservando lo spettro del segnale modulato esposto al rumore interferente, è evidente come le componenti di rumore siano separate da quelle del segnale modulato, che si trova ad alta frequenza. Pertanto, può essere implementato un filtro digitale passa-alto offline per selezionare solo quello modulato.

Filtro passa-alto.

Inizialmente è stato scelto un filtro Butterworth, il cui ordine e frequenza di taglio sono stati selezionati a tentativi, affinché attenuassero il più possibile l’ultima componente di rumore a 135 Hz senza ridurre eccessivamente il segnale modulato.

f_cutoff <- 200
flt.butter <- butter(4, f_cutoff/(fc/2), type = "high")  # filtro Butterworth passa-alto

ggbodeplot_digital(flt.butter, fc, fmin = 1e1) + geom_vline(xintercept = f_cutoff, linetype = 2, color = "red")

ym.flt <- tibble(
  t = ym$t,
  yn = ym$yn,
  yn_m = ym$yn_m,
  yn_m_n = ym$yn_m_n,
  yn_m_n.flt = signal::filtfilt(flt.butter, yn_m_n),   # estrae il segnale modulato
  f = 0:(length(t)-1)/max(t),
  fft = fft(yn_m_n.flt),
  intensity = Mod(fft)/length(t)*2,
  phase = Arg(fft)*180/pi
) 

ym.flt %>% dplyr::filter(f <= fc/2) %>% plot_ly(x = ~f) %>%
  add_lines(y = ~intensity) %>%
  layout(xaxis = list(title="Frequenza (Hz)"), yaxis=list(title="Intensità"), title="Filtraggio del segnale modulato con filtro Butterworth")

Tuttavia, nello spettro compare ancora una componente di rumore e il segnale in banda trasmessa risulta leggermente attenuato. Dunque, viene implementato un filtro di tipo Chebishev II, il quale a parità di ordine del Butterfly possiede una banda di transizione più ripida. Questo genere di filtro introdurrà un ripple in banda di stop, che però verrà attenuato mediante un filtraggio delle basse frequenze, che è richiesto per eliminare il rumore bianco. Nello specifico, a tentativi è stato scelto un taglio pari alla componente di più alta frequenza del rumore interferente.

f_cutoff <- max(pars_r$f)
flt.cheby <- cheby2(4, 20, f_cutoff/(fc/2), type = "high")  # N.B.: 20dB di riduzione del ripple in stop band

ggbodeplot_digital(flt.cheby, fc, fmin = 1e1) + geom_vline(xintercept = f_cutoff, linetype = 2, color = "red")

ym.flt <- ym.flt %>% mutate(
  yn_m_n.flt = signal::filtfilt(flt.cheby, yn_m_n),   # estrae il segnale modulato
  f = 0:(length(t)-1)/max(t),
  fft = fft(yn_m_n.flt),
  intensity = Mod(fft)/length(t)*2,
  phase = Arg(fft)*180/pi
) 

ym.flt %>% dplyr::filter(f <= fc/2) %>% plot_ly(x = ~f) %>%
  add_lines(y = ~intensity) %>%
  layout(xaxis = list(title="Frequenza (Hz)"), yaxis=list(title="Intensità"), title="Filtraggio del segnale modulato con filtro Chebyshev II")

Infatti, ora lo spettro mostra il rumore essere quasi inesistente e il segnale trasmesso quasi privo di attenuazione.

ym.flt %>% plot_ly(x = ~t) %>%
  add_lines(y = ~yn_m_n, name = "Con rumore interferente") %>%
  add_lines(y = ~yn_m, name = "Modulato") %>%
  add_lines(y = ~yn_m_n.flt, name = "Filtrato") %>%
  layout(xaxis = list(title = "Tempo (s)"), yaxis = list(title = "Segnale"), title = "Estrazione del segnale modulato")

A conferma del corretto procedimento di filtraggio è il fatto che il segnale ottenuto corrisponde a quello modulato prima dell’esposizione al rumore.

3.2 Demodulazione

Demodulazione.

Il processo di demodulazione è quello che permette di separare il segnale misurato dalla portante. A tal fine, viene scelta la demodulazione sincrona [suggerimento ChatGPT], in cui il segnale modulato viene moltiplicato per un’armonica pura con stessa frequenza e fase della portante (per questo si chiama “sincrona”). Nello specifico, i passaggi da seguire sono i seguenti:

  1. :
\[\begin{aligned} y_{mix} :&= y_{mod}(t) \cdot \cos(2\pi f_p t) \\ &= (1 + m y(t)) \cos^2(2\pi f_p t) \\ &= (1+my(t))\frac{1+\cos(4\pi f_p t)}{2} \\ &= \frac{1}2 (1+m y(t)) + \frac{1}2 (1+my(t))\cos(4 \pi f_p t) . \end{aligned}\]
  1. Filtraggio passa-basso: il segnale ottenuto dal mixing è caratterizzato da una componente a bassa frequenza (pari al più a \(f_{max}\) del segnale misurato) ed una ad alta frequenza (pari a \(2f_p\)): \[ LP\{y_{mix}\}(f_{max} < f_{cutoff} \ll 2f_p) \longrightarrow y_{flt} \approx 1+my(t) . \]

  2. Rielaborazione matematica per ottenere il segnale misurato:

\[ \frac{1}m (y_{flt} - 1) = y(t) . \]

In particolare, il filtro passa-basso permette anche di attenuare il ripple dal filtro Chebyshev e il rumore bianco.

ym.flt <- ym.flt %>% select(-fft, -intensity, -phase, -f) %>% mutate(
  y_mix = (2*yn_m_n.flt*cos(2*pi*fp*t) - 1)/m   # demodulazione + rielaborazione matematica
)

# Filtro passa-basso
# Taglio al doppio della freq. max del segnale misurato
# per far passare l'intero suo spettro
f_cut2 <- 2*max(pars_m$f)
flt.butter.lp <- butter(2, f_cut2/(fc/2))

ggbodeplot_digital(flt.butter.lp, fc, fmin = 1) + geom_vline(xintercept = f_cut2, linetype = 2, color = "red")

ym.flt <- ym.flt %>% mutate(
  y_flt2 = filtfilt(flt.butter.lp, y_mix)
)

ym.flt %>% plot_ly(x = ~t) %>%
  add_lines(y = ~yn_m_n.flt, name = "Filtrato") %>%
  add_lines(y = ~y_flt2, name = "Demodulato") %>%
  layout(xaxis = list(title="Tempo (s)"), yaxis=list(title="Segnale"), title = "Demodulazione")

Comparazione con la misura originale.

(ym.flt %>% pivot_longer(cols = c("yn", "y_flt2")) %>%
  mutate(
    name = factor(name, levels = c("yn", "y_flt2"))
  ) %>% ggplot(aes(x = t, y = value, colour = name)) +
  geom_line() +
  scale_colour_discrete(labels = c(yn = "Originale", y_flt2 = "Demodulato")) +
  labs(x = "Tempo (s)", y = "Segnale", colour = "Segnale")) %>% ggplotly()

Si osservi come il processo di demodulazione ha permesso anche di filtrare il rumore.