"""
SIMULATION DU FONCTIONNEMENT D'UN ONDULEUR

"""

## Importation des bibliothèques utiles
## ------------------------------------
import numpy as np
import matplotlib.pyplot as plt


## Saisie des données du problème
## ------------------------------------

## Constantes utiles

E = 1                       # amplitude de la tension u (valeur arbitraire, en V)
f = 50                      # fréquence de la tension u (en Hz)
T = 1/f                     # période correspondante (en s)
tau=T/(2*np.pi)

## Implémentation de la méthode d'Euler explicite
## ----------------------------------------------

def euler(F, y0, t0, tf, dt):
  """ 
  RŽésout le problème de Cauchy y'(t)=F(y(t),t) avec y(0)=y0 par la méŽthode 
  d'Euler explicite.
  Arguments d'entrŽée : 
    - F : fonction donnant y' (fonction de 2 variables) ;
    - y0 : condition initiale sur y (flottant) ;
    - t0 et tf : bornes de l'intervalle de rŽésolution (flottants) ;
    - dt : pas de discréŽtisation utiliséŽ pour la rŽésolution (flottant).
  Variables de sortie :
    - t : vecteur contenant l'ensemble des instants tk (array numpy) ;
    - y : vecteur contenant l'ensemble des valeurs approchéŽes yk (array numpy).
  """
  # Initialisation des variables de sortie
  t = np.arange(t0, tf+dt, dt)   # la dernière valeur est dans [tf,tf+dt[
  N = len(t)                     
  y = np.zeros(N)                # initialisation du array y
  y[0] = y0                      # prise en compte de la CI

  # Boucle permettant le calcul des yk par récurrence  
  for k in range(0,N-1):
    y[k+1] = y[k] + F(y[k],t[k])*dt
    
  return t, y # retourne un tableau contenant les temps tk
              # et un tableau contenant les valeurs approchées yk


### Définition du signal u
## ------------------------------------

def uc(t):
  """ 
  Cette fonction permet de calculer la valeur instantanéŽe de la tension u.
  uc(t) est un crŽéneau symŽétrique de rapport cyclique 50%
  EntréŽe : instant t (flottant unique ou array numpy de flottants)
  Sortie : tension u (flottant unique ou array numpy de flottants)
  """
  d = t/T - int(t/T)               # partie décimale de t/T
  if 0 <= d < 1/2:          
    return E
  else:
    return -E

def uo(t):
  """ 
  Cette fonction permet de calculer la valeur instantanéŽe de la tension u.
  uo(t) est un le signal pŽériodique correspondant au chronogramme de l'enoncé
  EntréŽe : instant t (flottant unique ou array numpy de flottants)
  Sortie : tension u (flottant unique ou array numpy de flottants)
  """
  d = t/T - int(t/T)               # partie décimale de t/T
  if d < 5/12:          
    return E
  elif 7/12 < d < 11/12 :
    return -E
  else :
    return 0  

## Résolution de l'équation différentielle pour l'onduleur 
## ------------------------------------
def onduleurc(s,t) : 
    """
    Fonction explicitant ds/dt en fonction de s et t
    pour le circuit modŽélisant l'onduleur. Le signal d'entréŽe est uc(t)
    On a F(s(t),t) = ds/dt = (u-s)/tau
    """
    return (uc(t)-s)/tau

def onduleuro(s,t) : 
    """
    Fonction explicitant ds/dt en fonction de s et t
    pour le circuit modŽélisant l'onduleur. Le signal d'entrŽe est uo(t)
    On a F(s(t),t) = ds/dt = (u-s)/tau
    """
    return (uo(t)-s)/tau

s0=0
t0,tf=0,4*T 
dt=0.01*tau

tc,sc=euler(onduleurc,s0,t0,tf,dt)
to,so=euler(onduleuro,s0,t0,tf,dt)

# Signal sinuso•ïdal modélisant s(t)
smod = np.sqrt(6)*E/np.pi*np.sin(2*np.pi*f*(to-T/8))
    

## Représentation graphique 
## ------------------------------------
# Définition de la taille de la fenêtre
plt.figure(figsize=(14,14))  # Largeur = 14, Hauteur = 14 (unités en pouces)

# Première sous-figure : Signal carré
plt.subplot(2, 1, 1) 

t = np.linspace(0, 4*T, 800)
plt.plot(t, [uc(val) for val in t],label="u(t)")
plt.plot(tc,sc,label = "s(t)")
plt.xlim(0, 4*T), plt.xlabel(r"$t$ (en s)")
plt.ylim(-1.1*E, 1.1*E), plt.ylabel(r"Tension (en V)")
plt.legend(loc = 'upper right')     # affichage de la légende
plt.title("Simulation par la méthode d'Euler explicite pour l'onduleur avec un signal carré en entrée")
plt.grid()
plt.show()

# Deuxième sous-figure : Signal du chronogramme de l'énoncé en entrée
plt.subplot(2, 1, 2) 

t = np.linspace(0, 4*T, 800)
plt.plot(t, [uo(val) for val in t],label="u(t)")
plt.plot(to,so,label = "s(t)")
plt.plot(to,smod,label = "$s_{mod}(t)$")

plt.xlim(0, 4*T), plt.xlabel(r"$t$ (en s)")
plt.ylim(-1.1*E, 1.1*E), plt.ylabel(r"Tension (en V)")
plt.legend(loc = 'upper right')     # affichage de la légende
plt.title("Simulation par la méthode d'Euler explicite pour l'onduleur avec un signal $u(t)$ en entrée")
plt.grid()
plt.show()


## Calcul du rendement
## --------------------------------

uoo=[uc(val) for val in to]
Pu=np.mean(so*so)  # puissance utile moyenne réelle
Pc=np.mean(so*np.array(uoo))  # puissance consommée moyenne réelle

Pumod=np.mean(smod*smod)  # puissance utile moyenne modélisée
Pcmod=np.mean(smod*np.array(uoo))  # puissance consommée moyenne modélisée

# Ajout du texte en bas à gauche
texte = f"$\eta(s)$ = {100*Pu/Pc:.1f} % \n $\eta(s_{{mod}})$ = {100*Pumod/Pcmod:.1f} %"
plt.text(0.02*tf, -0.75*E , texte, fontsize=12, bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=0.5'))


