Distorsion dans les Systèmes Linéaires¶
Dans ce notebook, nous allons explorer les effets d’un canal linéaire et du bruit thermique sur un signal modulé.
Le signal modulé est affecté par :
- La réponse impulsionnelle du canal .
- Un bruit thermique .
L’équation mathématique qui modélise le système est la suivante :
Où :
- représente la convolution.
- est un bruit additif gaussien blanc (AWGN).
Nous allons simuler ces effets et visualiser comment le signal est modifié à chaque étape.
Source
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider, IntSlider
def signal_modulation_demo(fc=50, noise_std=0.1):
"""
fc : Fréquence de la porteuse (Hz)
noise_std : Écart-type du bruit thermique
"""
# Définition des paramètres
fs = 1000 # Fréquence d'échantillonnage
t = np.arange(0, 1, 1/fs) # Durée de 1 seconde
# Signal d'entrée m(t) (sinusoïdal à fréquence fc/10 pour adaptabilité)
m_t = np.sin(2 * np.pi * fc / 10 * t)
# Porteuse cos(2πf_c t)
carrier = np.cos(2 * np.pi * fc * t)
# Signal modulé x(t)
x_t = m_t * carrier
# Transformée de Fourier de x(t)
X_f = np.fft.fft(x_t)
frequencies = np.fft.fftfreq(len(X_f), 1/fs)
# Filtre passe-bas dans le domaine fréquentiel (canal H(f))
H_f = np.zeros_like(frequencies)
cutoff = 100 # Fréquence de coupure (Hz)
H_f[np.abs(frequencies) <= cutoff] = 1
# Signal après le passage par le canal dans le domaine fréquentiel
Y_f = X_f * H_f
y_t = np.fft.ifft(Y_f).real # Retour dans le domaine temporel
# Ajout de bruit thermique dans le domaine temporel
noise = np.random.normal(0, noise_std, len(y_t))
r_t = y_t + noise
# Transformée de Fourier de r(t)
R_f = np.fft.fft(r_t)
# Visualisation des signaux et spectres
plt.figure(figsize=(8,8))
# Signal modulé x(t)
plt.subplot(5, 1, 1)
plt.plot(t, x_t)
plt.title("Signal modulé x(t)")
plt.xlabel("Temps (s)")
plt.ylabel("Amplitude")
# Spectre de x(t)
plt.subplot(5, 1, 2)
plt.plot(frequencies, np.abs(X_f))
plt.title("Spectre du signal modulé |X(f)|")
plt.xlabel("Fréquence (Hz)")
plt.ylabel("Amplitude")
plt.xlim(-200, 200)
# Réponse fréquentielle du canal H(f)
plt.subplot(5, 1, 3)
plt.plot(frequencies, H_f)
plt.title("Réponse fréquentielle du canal |H(f)|")
plt.xlabel("Fréquence (Hz)")
plt.ylabel("Amplitude")
plt.xlim(-200, 200)
# Spectre du signal reçu avec bruit r(t)
plt.subplot(5, 1, 4)
plt.plot(frequencies, np.abs(R_f))
plt.title("Spectre du signal reçu |R(f)|")
plt.xlabel("Fréquence (Hz)")
plt.ylabel("Amplitude")
plt.xlim(-200, 200)
# Signal reçu avec bruit r(t)
plt.subplot(5, 1, 5)
plt.plot(t, r_t)
plt.title("Signal reçu avec bruit r(t)")
plt.xlabel("Temps (s)")
plt.ylabel("Amplitude")
plt.tight_layout()
plt.show()
# Interactive sliders
interact(
signal_modulation_demo,
fc=IntSlider(value=50, min=20, max=200, step=10, description='Freq Porteuse'),
noise_std=FloatSlider(value=0.1, min=0.0, max=1.0, step=0.05, description='Bruit (σ)')
);Observations Clés¶
Largeur de Bande et Canal :
- Lorsque la fréquence de la porteuse est faible, le spectre du signal modulé est bien contenu dans la bande passante du canal.
- Lorsque la fréquence de la porteuse augmente, une partie du spectre dépasse la coupure du canal, entraînant une perte d’informations.
Effet du Bruit :
- Avec un bruit faible, le signal reçu reste proche de sa version d’origine.
- Avec un bruit élevé, le signal est significativement dégradé, ce qui est visible dans le domaine temporel et fréquentiel.
Réponse du Canal :
- Le canal agit comme un filtre passe-bas, atténuant les composantes spectrales au-delà de la fréquence de coupure.
Distorsion Harmonique : Superposition des Signaux¶
Ce notebook permet d’explorer les effets de la distorsion harmonique sur un signal constitué de plusieurs composantes harmoniques. La comparaison se fait entre les signaux avec distorsion et sans distorsion, qui sont superposés pour une analyse visuelle claire.
Paramètres¶
Gains des Harmoniques (
Gain 1er,Gain 3e,Gain 5e) :- Ajustez les gains pour augmenter ou réduire l’amplitude des différentes harmoniques.
Phases des Harmoniques (
Phase 1er,Phase 3e,Phase 5e) :- Modifiez les décalages de phase pour observer leur effet sur les signaux individuels et sur la somme totale.
Fréquence Fondamentale (
Fréquence) :- Changez la fréquence de la composante fondamentale, ce qui affecte aussi les fréquences des harmoniques (3ᵉ et 5ᵉ).
Source
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider
def harmonic_distortion_superposed(gain1=1.0, phase1=0.0, gain3=1.0, phase3=0.0, gain5=1.0, phase5=0.0, freq=1.0):
t = np.linspace(0, 1, 1000)
# Signal sans distorsion (fixed)
x1_clean = np.sin(2 * np.pi * freq * t) # Gain = 1, Phase = 0
x3_clean = np.sin(2 * np.pi * 3 * freq * t)
x5_clean = np.sin(2 * np.pi * 5 * freq * t)
x_clean = x1_clean + x3_clean + x5_clean
# Signal avec distorsion (adjustable)
x1_distorted = gain1 * np.sin(2 * np.pi * freq * t + phase1)
x3_distorted = gain3 * np.sin(2 * np.pi * 3 * freq * t + phase3)
x5_distorted = gain5 * np.sin(2 * np.pi * 5 * freq * t + phase5)
x_distorted = x1_distorted + x3_distorted + x5_distorted
# Define fixed axis limits for consistency
time_limits = (0, 1)
amplitude_limits = (-5, 5)
# Affichage
plt.figure(figsize=(8, 8))
# Harmoniques individuelles + somme totale avec/sans distorsion
plt.subplot(4, 1, 1)
plt.plot(t, x1_distorted, label="Harmonique 1 (avec dist.)")
plt.plot(t, x1_clean, linestyle='--', color='orange', label="Harmonique 1 (sans dist.)")
plt.title("Harmonique 1")
plt.legend()
plt.grid()
plt.xlim(time_limits)
plt.ylim(amplitude_limits)
plt.subplot(4, 1, 2)
plt.plot(t, x3_distorted, label="Harmonique 3 (avec dist.)", color='green')
plt.plot(t, x3_clean, linestyle='--', color='orange', label="Harmonique 3 (sans dist.)")
plt.title("Harmonique 3")
plt.legend()
plt.grid()
plt.xlim(time_limits)
plt.ylim(amplitude_limits)
plt.subplot(4, 1, 3)
plt.plot(t, x5_distorted, label="Harmonique 5 (avec dist.)", color='red')
plt.plot(t, x5_clean, linestyle='--', color='orange', label="Harmonique 5 (sans dist.)")
plt.title("Harmonique 5")
plt.legend()
plt.grid()
plt.xlim(time_limits)
plt.ylim(amplitude_limits)
plt.subplot(4, 1, 4)
plt.plot(t, x_distorted, label="Somme totale (avec dist.)", color='black')
plt.plot(t, x_clean, linestyle='--', color='orange', label="Somme totale (sans dist.)")
plt.title("Somme totale des harmoniques")
plt.legend()
plt.grid()
plt.xlim(time_limits)
plt.ylim(amplitude_limits)
plt.tight_layout()
plt.show()
# Interactive sliders
interact(
harmonic_distortion_superposed,
gain1=FloatSlider(value=1.0, min=0.5, max=1.5, step=0.1, description='Gain 1er'),
gain3=FloatSlider(value=1.0, min=0.5, max=1.5, step=0.1, description='Gain 3e'),
gain5=FloatSlider(value=1.0, min=0.5, max=1.5, step=0.1, description='Gain 5e'),
phase1=FloatSlider(value=0.0, min=-np.pi/4, max=np.pi/4, step=0.1, description='Phase 1er'),
phase3=FloatSlider(value=0.0, min=-np.pi/4, max=np.pi/4, step=0.1, description='Phase 3e'),
phase5=FloatSlider(value=0.0, min=-np.pi/4, max=np.pi/4, step=0.1, description='Phase 5e'),
freq=FloatSlider(value=1.0, min=1, max=5.0, step=1, description='Fréquence')
);Observations Clés¶
Effet des Harmoniques :
- Le signal est composé de trois harmoniques : la fondamentale ((f)), le 3ᵉ harmonique ((3f)), et le 5ᵉ harmonique ((5f)).
- Chaque harmonique peut être ajustée en amplitude (gain) et en phase.
Comparaison Visuelle :
- Les signaux sans distorsion (gain = 1, phase = 0) sont représentés en orange pointillé.
- Les signaux avec distorsion sont représentés en couleur pleine.
Somme Totale :
- Les trois harmoniques sont additionnées pour former un signal complexe. La superposition entre la somme totale avec et sans distorsion est visible dans le dernier graphique.
Distorsion dans les systèmes Non-Linéaire¶
Ce notebook explore les effets de la distorsion harmonique dans un système non-linéaire, où un signal sinusoïdal d’entrée traverse une fonction non-linéaire définie par les coefficients α, β, et γ.
Paramètres¶
Coefficient α :
- Contrôle l’amplitude linéaire du signal de sortie.
Coefficient β :
- Ajoute une composante quadratique () au signal, générant des harmoniques pairées (, ).
Coefficient γ :
- Ajoute une composante cubique () au signal, générant des harmoniques impaires (, ).
Fréquence du Signal () :
- Permet d’ajuster la fréquence de la sinusoïde d’entrée et d’observer l’impact sur le spectre.
Source
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider
def harmonic_distortion_demo(alpha=1.0, beta=0.0, gamma=0.1, freq=5.0):
t = np.linspace(0, 1, 1000)
x = np.cos(2 * np.pi * freq * t) # Signal d'entrée
# Signal en sortie du système non-linéaire
y = alpha * x + beta * (x ** 2) + gamma * (x ** 3)
# FFT pour observer les harmoniques
freqs = np.fft.fftfreq(len(t), t[1]-t[0])
Xf = np.fft.fft(x)
Yf = np.fft.fft(y)
# Sélection des fréquences positives uniquement
pos_indices = freqs >= 0
freqs_pos = freqs[pos_indices]
Xf_pos = np.abs(Xf[pos_indices])
Yf_pos = np.abs(Yf[pos_indices])
plt.figure(figsize=(8, 6))
# Signal temporel
plt.subplot(2,2,1)
plt.plot(t, x, label='Entrée : x(t)', linewidth=1)
plt.plot(t, y, label='Sortie : y(t)', linestyle='--')
plt.title('Signaux temporels')
plt.xlabel('Temps (s)')
plt.ylabel('Amplitude')
plt.legend()
plt.grid()
# Caractéristique non-linéaire
plt.subplot(2,2,2)
x_vals = np.linspace(-1.2, 1.2, 200)
y_vals = alpha * x_vals + beta * (x_vals ** 2) + gamma * (x_vals ** 3)
plt.plot(x_vals, y_vals, label=f'y = {alpha}x + {beta}x^2 + {gamma}x^3')
plt.title('Caractéristique du système non-linéaire')
plt.xlabel('x(t)')
plt.ylabel('y(t)')
plt.legend()
plt.grid()
# Spectre d'entrée
plt.subplot(2,2,3)
plt.stem(freqs_pos, Xf_pos, basefmt=" ")
plt.title('Spectre |X(f)| (entrée)')
plt.xlabel('Fréquence (Hz)')
plt.ylabel('Amplitude')
plt.xlim(0, 6 * freq)
# Spectre de sortie
plt.subplot(2,2,4)
plt.stem(freqs_pos, Yf_pos, basefmt=" ", linefmt='orange', markerfmt='o')
plt.title('Spectre |Y(f)| (sortie)')
plt.xlabel('Fréquence (Hz)')
plt.ylabel('Amplitude')
plt.xlim(0, 6 * freq)
plt.tight_layout()
plt.show()
interact(
harmonic_distortion_demo,
alpha=FloatSlider(value=1.0, min=0.0, max=2.0, step=0.1, description='alpha'),
beta=FloatSlider(value=0.0, min=0.0, max=1.0, step=0.1, description='beta'),
gamma=FloatSlider(value=0.0, min=0.0, max=1.0, step=0.1, description='gamma'),
freq=FloatSlider(value=5.0, min=1.0, max=20.0, step=1.0, description='Fréquence')
);Observations Clés¶
Caractéristique Non-Linéaire :
- La fonction déforme le signal en fonction des valeurs des coefficients β et γ.
- Lorsque β et γ sont nuls, le système est purement linéaire ().
Effet Temporel :
- Le signal de sortie présente des déformations temporelles lorsqu’on augmente les contributions non-linéaires ( et ).
Spectre Fréquentiel :
- Le spectre d’entrée () montre une composante dominante à la fréquence du signal sinusoïdal ().
- Le spectre de sortie () révèle des harmoniques (, , ) générés par la distorsion non-linéaire.
MODÈLE STATISTIQUE DU CANAL¶
Ce notebook illustre la génération et la visualisation d’une constellation QPSK en présence de bruit gaussien additif (AWGN). Les symboles sont transmis, perturbés par le bruit, puis décodés pour évaluer les erreurs et tracer le diagramme de constellation.
Paramètres¶
Sigma Bruit (σ) :
- Contrôle l’intensité du bruit gaussien ajouté au signal.
- Ajustez ce paramètre pour observer son effet sur la dispersion des symboles et le BER.
Nombre de Symboles () :
- Détermine le nombre de symboles QPSK générés.
- Un nombre plus élevé permet une meilleure estimation statistique du BER.
Source
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider, IntSlider
def qpsk_constellation_demo(sigma_bruit=0.1, N=2000):
"""
Visualisation d'une constellation QPSK avec bruit gaussien.
sigma_bruit : Écart-type du bruit (AWGN)
N : Nombre de symboles QPSK émis
"""
# Génération aléatoire de bits (2 bits par symbole QPSK)
bits = np.random.randint(0, 2, size=2 * N)
# Mapping des bits en symboles QPSK (Gray coding simple)
b0 = bits[0::2] # bits pairs
b1 = bits[1::2] # bits impairs
I = np.where(b0 == 0, +1, -1) # Partie réelle (In-phase)
Q = np.where(b1 == 0, +1, -1) # Partie imaginaire (Quadrature)
symbols = I + 1j * Q # Symboles QPSK complexes
# Ajout d'un bruit gaussien (canal AWGN)
noise = sigma_bruit * (np.random.randn(N) + 1j * np.random.randn(N))
received_symbols = symbols + noise # Symboles reçus après bruit
# Décision (par quadrants) basée sur les seuils de décision
I_hat = np.where(received_symbols.real >= 0, +1, -1) # In-phase decision
Q_hat = np.where(received_symbols.imag >= 0, +1, -1) # Quadrature decision
decided_symbols = I_hat + 1j * Q_hat # Symboles décidés
# Reconstruction des bits à partir des symboles décidés
b0_hat = np.where(I_hat == +1, 0, 1) # Décodage In-phase
b1_hat = np.where(Q_hat == +1, 0, 1) # Décodage Quadrature
bits_decoded = np.zeros(2 * N, dtype=int)
bits_decoded[0::2] = b0_hat
bits_decoded[1::2] = b1_hat
# Calcul du taux d'erreur binaire (BER)
nb_erreurs = np.sum(bits_decoded != bits)
ber = nb_erreurs / (2 * N)
# Visualisation de la constellation dans le plan complexe
plt.figure(figsize=(10, 6))
# Symboles reçus avec bruit
plt.scatter(received_symbols.real, received_symbols.imag, label="Symboles reçus (avec bruit)", alpha=0.5)
# Symboles transmis (sans bruit)
plt.scatter(symbols.real, symbols.imag, label="Symboles transmis (sans bruit)", alpha=0.5, edgecolors='k')
# Seuils de décision (découpage par quadrants)
plt.axhline(0, color='red', linestyle='--', label="Seuil de décision (imaginaire)")
plt.axvline(0, color='blue', linestyle='--', label="Seuil de décision (réel)")
# Customisation
plt.title(f"Diagramme de constellation QPSK\nBruit sigma={sigma_bruit:.2f}, BER={ber:.4f}")
plt.xlabel("Partie réelle (In-phase)")
plt.ylabel("Partie imaginaire (Quadrature)")
plt.grid(alpha=0.3)
plt.axis('equal')
plt.legend()
plt.show()
# Interactive sliders pour tester différents niveaux de bruit et nombre de symboles
interact(
qpsk_constellation_demo,
sigma_bruit=FloatSlider(value=0.2, min=0.0, max=1.0, step=0.01, description='Sigma Bruit'),
N=IntSlider(value=2000, min=100, max=10000, step=500, description='Nb Symboles')
);Observations Clés¶
Constellation QPSK :
- Les symboles QPSK (, , , ) sont représentés dans le plan complexe.
- Les seuils de décision divisent le plan en quatre quadrants correspondant à chaque symbole.
Impact du Bruit :
- Avec un bruit faible (), les symboles reçus restent proches de leur position d’origine.
- Avec un bruit élevé (), les symboles reçus se dispersent davantage, augmentant le taux d’erreur.
Taux d’Erreur Binaire (BER) :
- Le BER est calculé comme la fraction des bits incorrectement décodés.
- Il augmente avec le niveau de bruit, reflétant la dégradation du signal.