import numpy as np
import matplotlib.pyplot as plt

# Paramètres
Tb = 1  # Durée d'un bit
Ts_4 = 2 * Tb  # Durée d'un symbole pour 4-aire (2 bits par symbole)
Ts_8 = 3 * Tb  # Durée d'un symbole pour 8-aire (3 bits par symbole)
f = np.linspace(-3/Tb, 3/Tb, 1000)  # Fréquences normalisées

# DSP théoriques
def dsp_nrz_unipolaire(f, Tb):
    return (Tb/4) * (np.sinc(f * Tb))**2 + (1/4) * (f == 0)  # Dirac à f=0

def dsp_nrz_polaire(f, Tb):
    return Tb * (np.sinc(f * Tb))**2

def dsp_rz_unipolaire(f, Tb):
    return (Tb/16) * (np.sinc(f * Tb / 2))**2 + (1/16) * np.sum([(f == n/Tb) for n in range(-10, 11)])  # Raies spectrales

def dsp_rz_polaire(f, Tb):
    return (Tb/4) * (np.sinc(f * Tb / 2))**2

def dsp_manchester(f, Tb):
    return Tb * (np.sinc(f * Tb / 2))**2 * (np.sin(np.pi * f * Tb / 2))**2

def dsp_4_aire(f, Ts):
    return (Ts / 4) * (np.sinc(f * Ts))**2 * (1 + 9 + 9 + 1)  # Exemple pour 4 niveaux : -3V, -V, +V, +3V

def dsp_8_aire(f, Ts):
    return (Ts / 8) * (np.sinc(f * Ts))**2 * (1 + 9 + 25 + 49 + 49 + 25 + 9 + 1)  # Exemple pour 8 niveaux : -7V, -5V, -3V, -V, +V, +3V, +5V, +7V

# Conversion en dB
def to_db(x):
    return 10 * np.log10(np.maximum(x, 1e-10))  # Éviter log(0) en utilisant un seuil

def dsp_rz_bipolaire(f, Tb):
    return (Tb/4) * (np.sinc(f * Tb / 2))**2 * (np.sin(np.pi * f * Tb))**2

def dsp_ami(f, Tb):
    return Tb * (np.sinc(f * Tb))**2 * (np.sin(np.pi * f * Tb))**2

def dsp_hdb3(f, Tb):
    return Tb * (np.sinc(f * Tb))**2 * (np.sin(np.pi * f * Tb))**2

def dsp_miller(f, Tb):
    return Tb * (np.sinc(f * Tb / 2))**2 * (np.sin(np.pi * f * Tb / 2))**2

def dsp_8b10b(f, Tb):
    return Tb * (np.sinc(f * Tb))**2

def dsp_64b66b(f, Tb):
    return Tb * (np.sinc(f * Tb))**2


# Tracés en dB
plt.figure(figsize=(15, 10))

# NRZ Unipolaire
plt.subplot(4, 4, 1)
plt.plot(f, to_db(dsp_nrz_unipolaire(f, Tb)))
plt.title("NRZ Unipolaire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# NRZ Polaire
plt.subplot(4, 4, 2)
plt.plot(f, to_db(dsp_nrz_polaire(f, Tb)))
plt.title("NRZ Polaire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# RZ Unipolaire
plt.subplot(4, 4, 3)
plt.plot(f, to_db(dsp_rz_unipolaire(f, Tb)))
plt.title("RZ Unipolaire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# RZ Polaire
plt.subplot(4, 4, 4)
plt.plot(f, to_db(dsp_rz_polaire(f, Tb)))
plt.title("RZ Polaire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# Manchester
plt.subplot(4, 4, 5)
plt.plot(f, to_db(dsp_manchester(f, Tb)))
plt.title("Manchester (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# 4-aire
plt.subplot(4, 4, 6)
plt.plot(f, to_db(dsp_4_aire(f, Ts_4)))
plt.title("4-aire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# 8-aire
plt.subplot(4, 4, 7)
plt.plot(f, to_db(dsp_8_aire(f, Ts_8)))
plt.title("8-aire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# RZ Bipolaire
plt.subplot(4, 4, 8)
plt.plot(f, to_db(dsp_rz_bipolaire(f, Tb)))
plt.title("RZ Bipolaire (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# AMI
plt.subplot(4, 4, 9)
plt.plot(f, to_db(dsp_ami(f, Tb)))
plt.title("AMI (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# HDB3
plt.subplot(4, 4, 10)
plt.plot(f, to_db(dsp_hdb3(f, Tb)))
plt.title("HDB3 (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# Miller
plt.subplot(4, 4, 11)
plt.plot(f, to_db(dsp_miller(f, Tb)))
plt.title("Miller (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# 8B/10B
plt.subplot(4, 4, 12)
plt.plot(f, to_db(dsp_8b10b(f, Tb)))
plt.title("8B/10B (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

# 64B/66B
plt.subplot(4, 4, 13)
plt.plot(f, to_db(dsp_64b66b(f, Tb)))
plt.title("64B/66B (dB)")
plt.xlabel("Fréquence (f)")
plt.ylabel("DSP (dB)")
plt.grid()

plt.tight_layout()
plt.show()