# -*- coding: utf-8 -*-
"""
Created on Sun Oct 26 18:41:29 2025

@author: AKourgli
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert, firwin, lfilter, freqz

# Simulation parameters
fs = 100000        # Sampling frequency (Hz)
T = 0.1            # Duration of signal (seconds)
t = np.linspace(0, T, int(T*fs), endpoint=False) # Time vector

# Message Signal: Sum of two sinusoids (300 Hz and 600 Hz)
f_m1 = 300
f_m2 = 600
m_t = np.sin(2 * np.pi * f_m1 * t) + 0.5 * np.sin(2 * np.pi * f_m2 * t)

# Carrier Signal
f_c = 10000        # Carrier frequency (Hz)
carrier = np.cos(2 * np.pi * f_c * t)
carrier_90 = np.sin(2 * np.pi * f_c * t)  # Quadrature carrier

# Generate Hilbert Transform of the message signal
analytic_signal = hilbert(m_t)
m_h_t = np.imag(analytic_signal)

# =============================================================================
# 1. GENERATION DES SIGNAUX SSB (USB ET LSB) - Méthode de phase
# =============================================================================

# Generate USB and LSB using Phasing Method
ssb_usb_t = m_t * carrier - m_h_t * carrier_90  # USB
ssb_lsb_t = m_t * carrier + m_h_t * carrier_90  # LSB

# =============================================================================
# 2. GENERATION DU SIGNAL VSB - Méthode par filtrage
# =============================================================================

# Create DSB-SC first
dsb_sc_t = m_t * carrier

# Create VSB filter - filtre asymétrique pour VSB
numtaps = 401
# Filtre qui passe la bande supérieure complètement et une partie de la bande inférieure
cutoff_freq = f_c - 200  # Fréquence de coupure basse (vestige de la bande inférieure)
transition_width = 400    # Largeur de transition

# Création d'un filtre passe-bas pour la conception
nyquist = fs / 2
normalized_cutoff = cutoff_freq / nyquist
normalized_transition = transition_width / nyquist

# Design du filtre FIR
vsb_taps = firwin(numtaps, [normalized_cutoff, normalized_cutoff + normalized_transition],  pass_zero=False, window='hamming')
# Application du filtre VSB au signal DSB-SC
vsb_signal = lfilter(vsb_taps, 1.0, dsb_sc_t)

# =============================================================================
# 3. DÉMODULATION COHÉRENTE POUR TOUS LES SIGNALUX
# =============================================================================

def coherent_demod(signal, carrier_freq, time_vector, bandwidth=1000):
    """Démodulation cohérente pour SSB et VSB"""
    # Multiplication avec l'oscillateur local
    demod = signal * np.cos(2 * np.pi * carrier_freq * time_vector)
    
    # Filtrage passe-bas pour récupérer le message
    cutoff_normalized = bandwidth / nyquist
    lp_taps = firwin(101, cutoff_normalized)
    recovered = lfilter(lp_taps, 1.0, demod)
    
    return recovered

# Démodulation des signaux
demod_usb = coherent_demod(ssb_usb_t, f_c, t)
demod_lsb = coherent_demod(ssb_lsb_t, f_c, t)
demod_vsb = coherent_demod(vsb_signal, f_c, t)
demod_dsb = coherent_demod(dsb_sc_t, f_c, t)

# =============================================================================
# 4. VISUALISATION COMPLÈTE
# =============================================================================

plt.figure(figsize=(16, 8))

# Plot 1: Spectre des signaux modulés
plt.subplot(3, 2, 1)
freqs = np.fft.fftfreq(len(t), 1/fs)

# Calcul des spectres
USB_f = np.abs(np.fft.fft(ssb_usb_t))
LSB_f = np.abs(np.fft.fft(ssb_lsb_t))
VSB_f = np.abs(np.fft.fft(vsb_signal))
DSB_f = np.abs(np.fft.fft(dsb_sc_t))

plt.plot(freqs, USB_f, 'b', label='USB', linewidth=2)
plt.plot(freqs, LSB_f, 'r', label='LSB', linewidth=2)
plt.plot(freqs, VSB_f, 'g', label='VSB', linewidth=2)
plt.plot(freqs, DSB_f, 'orange', label='DSB-SC', alpha=0.5, linewidth=1)

plt.title('Spectres Comparatifs: USB, LSB, VSB et DSB-SC')
plt.xlabel('Fréquence [Hz]')
plt.ylabel('Amplitude')
plt.xlim(f_c - 1500, f_c + 1500)
plt.legend()
plt.grid(True, alpha=0.3)

# Plot 2: Zoom sur la région de la porteuse
plt.subplot(3, 2, 2)
plt.plot(freqs, USB_f, 'b', label='USB', linewidth=2)
plt.plot(freqs, LSB_f, 'r', label='LSB', linewidth=2)
plt.plot(freqs, VSB_f, 'g', label='VSB', linewidth=2)
plt.plot(freqs, DSB_f, 'orange', label='DSB-SC', alpha=0.5, linewidth=1)

plt.axvline(x=f_c, color='k', linestyle='--', alpha=0.5, label=f'Porteuse {f_c}Hz')
plt.title('Zoom Spectre Autour de la Porteuse')
plt.xlabel('Fréquence [Hz]')
plt.ylabel('Amplitude')
plt.xlim(f_c - 800, f_c + 800)
plt.legend()
plt.grid(True, alpha=0.3)

# Plot 3: Signaux dans le domaine temporel
plt.subplot(3, 2, 3)
zoom_samples = 1500
plt.plot(t[:zoom_samples], ssb_usb_t[:zoom_samples], 'b', label='USB', alpha=0.8, linewidth=1)
plt.plot(t[:zoom_samples], ssb_lsb_t[:zoom_samples], 'r', label='LSB', alpha=0.8, linewidth=1)
plt.plot(t[:zoom_samples], vsb_signal[:zoom_samples], 'g', label='VSB', alpha=0.8, linewidth=1)
plt.title('Signaux Modulés - Domaine Temporel (Zoom)')
plt.xlabel('Temps [s]')
plt.ylabel('Amplitude')
plt.legend()
plt.grid(True, alpha=0.3)

# Plot 4: Signaux démodulés
plt.subplot(3, 2, 4)
# Normalisation pour comparaison
demod_usb_norm = demod_usb / np.max(np.abs(demod_usb))
demod_lsb_norm = demod_lsb / np.max(np.abs(demod_lsb))
demod_vsb_norm = demod_vsb / np.max(np.abs(demod_vsb))

plt.plot(t[:zoom_samples], m_t[:zoom_samples], 'k', label='Message Original', linewidth=2, alpha=0.7)
plt.plot(t[:zoom_samples], demod_usb_norm[:zoom_samples], 'b--', label='USB Démodulé', alpha=0.8)
plt.plot(t[:zoom_samples], demod_lsb_norm[:zoom_samples], 'r--', label='LSB Démodulé', alpha=0.8)
plt.plot(t[:zoom_samples], demod_vsb_norm[:zoom_samples], 'g--', label='VSB Démodulé', alpha=0.8)
plt.title('Signaux Démodulés vs Message Original')
plt.xlabel('Temps [s]')
plt.ylabel('Amplitude Normalisée')
plt.legend()
plt.grid(True, alpha=0.3)

# Plot 5: Réponse fréquentielle du filtre VSB
plt.subplot(3, 2, 5)
w, h = freqz(vsb_taps, worN=8000, fs=fs)
plt.plot(w, 20 * np.log10(np.abs(h)), 'g', linewidth=2)
plt.axvline(x=f_c, color='k', linestyle='--', alpha=0.5, label='Porteuse')
plt.axvline(x=cutoff_freq, color='r', linestyle=':', alpha=0.7, label=f'Coupure VSB')
plt.title('Réponse du Filtre VSB')
plt.xlabel('Fréquence [Hz]')
plt.ylabel('Amplitude [dB]')
plt.xlim(f_c - 1000, f_c + 1000)
plt.legend()
plt.grid(True, alpha=0.3)

# Plot 6: Efficacité spectrale
plt.subplot(3, 2, 6)
modulation_types = ['DSB-SC', 'SSB (USB/LSB)', 'VSB']
bandwidths = [1200, 600, 800]  # Bandwidth in Hz
efficiencies = [33, 100, 75]   # Relative spectral efficiency in %

bars = plt.bar(modulation_types, bandwidths, color=['orange', 'blue', 'green'], alpha=0.7)
plt.ylabel('Largeur de Bande [Hz]')
plt.title('Efficacité Spectrale Comparée')
plt.grid(True, alpha=0.3)

# Ajout des valeurs sur les barres
for bar, eff in zip(bars, efficiencies):
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2., height + 20,
             f'{eff}% eff.', ha='center', va='bottom')

plt.tight_layout()
plt.show()

# =============================================================================
# 5. ANALYSE COMPARATIVE
# =============================================================================

print("ANALYSE COMPARATIVE DES TECHNIQUES DE MODULATION")
print("=" * 50)
print("SSB (Single Sideband):")
print("  - USB: Transmet uniquement la bande supérieure")
print("  - LSB: Transmet uniquement la bande inférieure") 
print("  - Avantages: Efficacité maximale (bande et puissance)")
print("  - Inconvénients: Complexité, sensibilité aux erreurs de phase")
print()
print("VSB (Vestigial Sideband):")
print("  - Transmet une bande complète + vestige de l'autre")
print("  - Avantages: Filtrage plus facile, bon pour signaux basse fréquence")
print("  - Inconvénients: Légèrement moins efficace que SSB")
print()
print("CARACTÉRISTIQUES DANS LE SPECTRE:")
print(f"  - Fréquences USB: {f_c + f_m1} Hz et {f_c + f_m2} Hz")
print(f"  - Fréquences LSB: {f_c - f_m1} Hz et {f_c - f_m2} Hz") 
print(f"  - Bande vestigiale VSB: {cutoff_freq} Hz à {f_c} Hz")