# -*- coding: utf-8 -*-
"""
Created on Thu Apr 10 16:00:29 2025

@author: AKourgli
"""

import numpy as np
import matplotlib.pyplot as plt

def gray_code(n):
    """
    Calcule le code Gray d'un entier n.
    """
    return n ^ (n >> 1)

def format_gray(n, n_bits):
    """
    Formate le code Gray en chaîne binaire sur n_bits.
    """
    return format(gray_code(n), f'0{n_bits}b')

def plot_mpsk_constellation(M, ax=None):
    """
    Affiche la constellation M-PSK avec l'annotation du code Gray pour chaque point.
    Parameters:
        M (int): le nombre de points (modulation M-PSK)
        ax (matplotlib.axes): l'axe sur lequel tracer (si None, on crée une nouvelle figure)
    """
    n_bits = int(np.log2(M))
    angles = np.arange(M) * 2 * np.pi / M
    # Constellation sur le cercle unité
    x = np.cos(angles)
    y = np.sin(angles)
    
    if ax is None:
        fig, ax = plt.subplots(figsize=(4,4))
    
    # Tracé des points
    ax.plot(x, y, 'bo', markersize=8)
    
    # Annotation des points avec leur code Gray
    for i in range(M):
        code_gray = format_gray(i, n_bits)
        # Décalage pour que le texte ne recouvre pas exactement le point
        ax.text(x[i]*1.1, y[i]*1.1, code_gray,
                fontsize=12, ha='center', va='center', color='red')
    
    # Tracé du cercle unité pour repère
    theta = np.linspace(0, 2*np.pi, 200)
    ax.plot(np.cos(theta), np.sin(theta), 'k--', linewidth=0.5)
    
    ax.set_title(f"{M}-PSK avec codage Gray")
    ax.set_xlabel("I")
    ax.set_ylabel("Q")
    ax.set_aspect('equal', 'box')
    ax.grid(True)

# Liste des valeurs de M pour lesquelles afficher les constellations
M_values = [2, 4, 8, 16]

# Création d'une figure avec plusieurs sous-graphes
plt.subplots(2, 2, figsize=(8, 8))
axs = axs.flatten()

for i, M in enumerate(M_values):
    plot_mpsk_constellation(M, ax=axs[i])

plt.tight_layout()
plt.show()
