# -*- coding: utf-8 -*-
"""
Created on Sun Mar  9 17:56:32 2025

@author: AKourgli
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import lfilter


def rcosdesign(beta, span, sps, norm='sqrt'):
    t = np.linspace(-span/2, span/2, span*sps)
    h = np.zeros_like(t)
    eps = 1e-9  # Petit epsilon pour la stabilité numérique
    
    for i, ti in enumerate(t):
        if abs(ti) < 1e-8:  # Gestion du cas t=0
            h[i] = 1.0
        else:
            numerator = np.sin(np.pi*ti*(1 - beta)) + 4*beta*ti*np.cos(np.pi*ti*(1 + beta))
            denominator = np.pi*ti*(1 - (4*beta*ti)**2)
            
            # Éviter la division par zéro
            if abs(denominator) < eps:
                h[i] = beta * np.sin(np.pi/(2*beta)) / 2
            else:
                h[i] = numerator / denominator
    
    # Suppression des valeurs négatives et normalisation
    h = np.maximum(h, 0)  
    h /= np.linalg.norm(h)
    
    if norm == 'sqrt':
        h = np.sqrt(h)
    
    return h


# Paramètres
num_symbols = 100
sps = 10
beta = 0.25
additional_delay = 2

# Génération des symboles avec marge
symbols = np.random.randint(0, 2, num_symbols + 10)*2 - 1

# Création des trois versions du signal
t = np.arange(len(symbols)*sps)/sps  # Échelle temporelle en périodes symbole

# 1. Symboles bruts répétés
rectangular_waveform = np.repeat(symbols, sps)

# 2. Signal formé RRC
up_samples = np.zeros_like(rectangular_waveform)
up_samples[::sps] = symbols
taps = rcosdesign(beta, 4, sps)
signal_shaped = lfilter(taps, 1.0, up_samples)

# 3. Signal avec ISI et retard
isi_taps = [0.5, 1.0, 0.5]
signal_isi = lfilter(isi_taps, 1.0, signal_shaped)
total_delay = (len(taps)-1)//2 + (len(isi_taps)-1)//2 + additional_delay
signal_isi = signal_isi[total_delay:]

# Configuration de la figure
plt.figure(figsize=(12, 8))

# Tracé des symboles bruts
ax1 = plt.subplot(311)
ax1.plot(t[:len(rectangular_waveform)], rectangular_waveform, 'b', alpha=0.5)
ax1.stem(np.arange(len(symbols)), symbols, 'r', basefmt=' ')
ax1.set_title('Symboles originaux mis bout à bout')
ax1.set_xlim(0, 20)  # Afficher 20 premières périodes
ax1.grid(True)

# Tracé du signal formé
ax2 = plt.subplot(312)
ax2.plot(t[:len(signal_shaped)], signal_shaped, 'g')
ax2.set_title('Signal après mise en forme RRC')
ax2.set_xlim(0, 20)
ax2.grid(True)

# Diagramme de l'œil
ax3 = plt.subplot(313)
eye_length = 2*sps
num_eyes = len(signal_isi)//eye_length
t_eye = np.linspace(-0.5, 1.5, eye_length)

for i in range(num_eyes):
    segment = signal_isi[i*eye_length:(i+1)*eye_length]
    ax3.plot(t_eye, segment, 'navy', alpha=0.5, linewidth=0.5)

ax3.set_title('Diagramme de l\'œil avec retard et ISI')
ax3.grid(True)
ax3.set_xlim(-0.5, 1.5)

plt.tight_layout()
plt.show()
