Skip to article frontmatterSkip to article content

Exemples Intréractifs: Canaux de Transmission

Introduction\textbf{Introduction}

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é x(t)x(t) est affecté par :

  1. La réponse impulsionnelle du canal h(t)h(t).
  2. Un bruit thermique b(t)b(t).

L’équation mathématique qui modélise le système est la suivante :

y(t)=x(t)h(t)y(t) = x(t) * h(t)
r(t)=y(t)+b(t)r(t) = y(t) + b(t)

Où :

  • * représente la convolution.
  • b(t)b(t) 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 (σ)')
);
Loading...

Observations Clés

  1. 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.
  2. 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.
  3. 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')
);
Loading...

Observations Clés

  1. 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.
  2. 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.
  3. 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 (x2x^2) au signal, générant des harmoniques pairées (2f02f_0, 4f04f_0).
  • Coefficient γ :

    • Ajoute une composante cubique (x3x^3) au signal, générant des harmoniques impaires (3f03f_0, 5f05f_0).
  • Fréquence du Signal (f0f_0) :

    • 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')
);
Loading...

Observations Clés

  1. Caractéristique Non-Linéaire :

    • La fonction y=αx+βx2+γx3y = \alpha x + \beta x^2 + \gamma x^3 déforme le signal en fonction des valeurs des coefficients β et γ.
    • Lorsque β et γ sont nuls, le système est purement linéaire (y=αxy = \alpha x).
  2. Effet Temporel :

    • Le signal de sortie y(t)y(t) présente des déformations temporelles lorsqu’on augmente les contributions non-linéaires (x2x^2 et x3x^3).
  3. Spectre Fréquentiel :

    • Le spectre d’entrée (X(f)|X(f)|) montre une composante dominante à la fréquence du signal sinusoïdal (f0f_0).
    • Le spectre de sortie (Y(f)|Y(f)|) révèle des harmoniques (2f02f_0, 3f03f_0, \dots) 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 (NN) :

    • 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')
);
Loading...

Observations Clés

  1. Constellation QPSK :

    • Les symboles QPSK (+1+1j+1+1j, 1+1j-1+1j, 11j-1-1j, +11j+1-1j) sont représentés dans le plan complexe.
    • Les seuils de décision divisent le plan en quatre quadrants correspondant à chaque symbole.
  2. Impact du Bruit :

    • Avec un bruit faible (σ0.1\sigma \sim 0.1), les symboles reçus restent proches de leur position d’origine.
    • Avec un bruit élevé (σ>0.5\sigma > 0.5), les symboles reçus se dispersent davantage, augmentant le taux d’erreur.
  3. 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.