# -*- coding: utf-8 -*-
"""
Created on Fri Sep  5 16:38:34 2025

@author: AKourgli
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.constants import speed_of_light

# Paramètres de base
freq = 2.4e9  # Fréquence en Hz
c = speed_of_light
wavelength = c / freq

print(f"Fréquence: {freq/1e6} MHz")
print(f"Longueur d'onde: {wavelength:.3f} m")

def dipole_pattern(theta):
    """Calcul du diagramme de rayonnement d'un dipôle demi-onde"""
    beta = 2 * np.pi / wavelength
    L = wavelength / 2  # Dipôle demi-onde
    return (np.cos((beta * L / 2) * np.cos(theta)) - np.cos(beta * L / 2)) / np.sin(theta)

def monopole_pattern(theta):
    """Diagramme de rayonnement d'un monopole quart d'onde"""
    # Pattern similaire au dipôle mais seulement dans l'hémisphère supérieur
    pattern = dipole_pattern(theta)
    pattern = np.where((theta > np.pi/2) & (theta < 3*np.pi/2), 0, pattern)
    return pattern

def isotropic_pattern(theta):
    """Diagramme de rayonnement d'une antenne isotrope (cercle parfait)"""
    return np.ones_like(theta)

def parabolic_pattern(theta, beam_width=20):
    """Diagramme de rayonnement d'une antenne parabolique (faisceau étroit)"""
    # Conversion de beam_width de degrés en radians
    beam_width_rad = np.deg2rad(beam_width)
    
    # Pattern gaussien pour simuler un faisceau étroit
    # Le faisceau est dirigé à 90° (π/2 radians)
    pattern = np.exp(-((theta - np.pi/2)**2) / (2 * (beam_width_rad/4)**2))
    return pattern

def patch_pattern(theta):
    """Diagramme de rayonnement d'une antenne patch (cos²)"""
    return np.cos(theta)**2

# Calcul pour différentes directions
theta = np.linspace(0.001, 2*np.pi, 360)

# Calcul des patterns pour chaque type d'antenne
dipole_pattern_values = dipole_pattern(theta)
monopole_pattern_values = monopole_pattern(theta)
isotropic_pattern_values = isotropic_pattern(theta)
parabolic_pattern_values = parabolic_pattern(theta)
patch_pattern_values = patch_pattern(theta)

# Normalisation de tous les patterns
dipole_pattern_norm = np.abs(dipole_pattern_values) / np.max(np.abs(dipole_pattern_values))
monopole_pattern_norm = np.abs(monopole_pattern_values) / np.max(np.abs(monopole_pattern_values))
isotropic_pattern_norm = np.abs(isotropic_pattern_values) / np.max(np.abs(isotropic_pattern_values))
parabolic_pattern_norm = np.abs(parabolic_pattern_values) / np.max(np.abs(parabolic_pattern_values))
patch_pattern_norm = np.abs(patch_pattern_values) / np.max(np.abs(patch_pattern_values))

# Conversion en dB
dipole_pattern_db = 10 * np.log10(dipole_pattern_norm)
monopole_pattern_db = 10 * np.log10(monopole_pattern_norm)
isotropic_pattern_db = 10 * np.log10(isotropic_pattern_norm)
parabolic_pattern_db = 10 * np.log10(parabolic_pattern_norm)
patch_pattern_db = 10 * np.log10(patch_pattern_norm)

# Tracé de tous les diagrammes sur un même graphique
plt.figure(figsize=(10, 10))
ax = plt.subplot(111, projection='polar')

# Tracé avec les couleurs demandées
ax.plot(theta, dipole_pattern_db, 'blue', linewidth=2, label='Dipôle λ/2 (donut)')
ax.plot(theta, monopole_pattern_db, 'green', linewidth=2, label='Monopôle λ/4 (hémisphérique)')
ax.plot(theta, isotropic_pattern_db, 'black', linewidth=2, label='Isotrope (cercle parfait)')
ax.plot(theta, parabolic_pattern_db, 'red', linewidth=2, label='Parabole (faisceau étroit)')
ax.plot(theta, patch_pattern_db, 'orange', linewidth=2, label='Patch (cos²)')

# Configuration du graphique
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_rmin(-30)
ax.set_rmax(0)
ax.set_title("Comparaison des diagrammes de rayonnement d'antennes", va='bottom', fontsize=14)
ax.legend(loc='lower right', bbox_to_anchor=(1.1, 0.1))

plt.tight_layout()
plt.show()

# Tracé individuel pour chaque antenne pour plus de clarté
fig, axes = plt.subplots(2, 3, subplot_kw={'projection': 'polar'}, figsize=(15, 10))
axes = axes.flatten()

# Dipôle
axes[0].plot(theta, dipole_pattern_db, 'blue', linewidth=2)
axes[0].set_title('Dipôle λ/2')
axes[0].set_theta_zero_location('N')
axes[0].set_theta_direction(-1)
axes[0].set_rmin(-30)
axes[0].set_rmax(0)

# Monopôle
axes[1].plot(theta, monopole_pattern_db, 'green', linewidth=2)
axes[1].set_title('Monopôle λ/4')
axes[1].set_theta_zero_location('N')
axes[1].set_theta_direction(-1)
axes[1].set_rmin(-30)
axes[1].set_rmax(0)

# Isotrope
axes[2].plot(theta, isotropic_pattern_db, 'black', linewidth=2)
axes[2].set_title('Antenne isotrope')
axes[2].set_theta_zero_location('N')
axes[2].set_theta_direction(-1)
axes[2].set_rmin(-30)
axes[2].set_rmax(0)

# Parabole
axes[3].plot(theta, parabolic_pattern_db, 'red', linewidth=2)
axes[3].set_title('Antenne parabolique')
axes[3].set_theta_zero_location('N')
axes[3].set_theta_direction(-1)
axes[3].set_rmin(-30)
axes[3].set_rmax(0)

# Patch
axes[4].plot(theta, patch_pattern_db, 'orange', linewidth=2)
axes[4].set_title('Antenne patch')
axes[4].set_theta_zero_location('N')
axes[4].set_theta_direction(-1)
axes[4].set_rmin(-30)
axes[4].set_rmax(0)

# Cacher le dernier subplot
axes[5].set_visible(False)

plt.tight_layout()
plt.show()

# Calcul des caractéristiques pour chaque antenne
def calculate_swr(Z_ant, Z0=50):
    """Calcul du Taux d'Ondes Stationnaires"""
    gamma = (Z_ant - Z0) / (Z_ant + Z0)
    gamma_magnitude = abs(gamma)
    
    # Éviter la division par zéro
    if gamma_magnitude >= 0.999:
        return float('inf')
    
    swr = (1 + gamma_magnitude) / (1 - gamma_magnitude)
    return swr

def dipole_impedance(freq, length, radius):
    """Calcul approximatif de l'impédance d'un dipôle"""
    k = 2 * np.pi * freq / c
    a = radius
    R = 20 * (k * length)**2
    X = 120 * (np.log(length / (2 * a)) - 1) * np.tan(k * length / 2)
    return R + 1j * X

# Calcul des impédances et TOS
dipole_length = wavelength / 2
monopole_length = wavelength / 4

Z_dipole = dipole_impedance(freq, dipole_length, 0.0001)
Z_monopole = Z_dipole / 2  # Approximation pour monopole
Z_isotropic = 50 + 0j  # Supposée adaptée
Z_parabolic = 75 + 0j  # Valeur typique
Z_patch = 50 + 0j  # Valeur typique

swr_dipole = calculate_swr(Z_dipole)
swr_monopole = calculate_swr(Z_monopole)
swr_isotropic = calculate_swr(Z_isotropic)
swr_parabolic = calculate_swr(Z_parabolic)
swr_patch = calculate_swr(Z_patch)

# Affichage des caractéristiques
print("\nCaractéristiques des antennes:")
print(f"Dipôle λ/2: Impédance = {Z_dipole:.2f} Ω, TOS = {swr_dipole:.2f}")
print(f"Monopôle λ/4: Impédance = {Z_monopole:.2f} Ω, TOS = {swr_monopole:.2f}")
print(f"Isotrope: Impédance = {Z_isotropic:.2f} Ω, TOS = {swr_isotropic:.2f}")
print(f"Parabole: Impédance = {Z_parabolic:.2f} Ω, TOS = {swr_parabolic:.2f}")
print(f"Patch: Impédance = {Z_patch:.2f} Ω, TOS = {swr_patch:.2f}")

# Calcul des gains relatifs (approximatifs)
gain_dipole = 2.15  # dBi
gain_monopole = gain_dipole - 3  # dBi
gain_isotropic = 0  # dBi
gain_parabolic = 24  # dBi (valeur typique pour une petite parabole)
gain_patch = 6  # dBi (valeur typique)

print("\nGains approximatifs:")
print(f"Dipôle λ/2: {gain_dipole} dBi")
print(f"Monopôle λ/4: {gain_monopole} dBi")
print(f"Isotrope: {gain_isotropic} dBi")
print(f"Parabole: {gain_parabolic} dBi")
print(f"Patch: {gain_patch} dBi")