# -*- coding: utf-8 -*-
"""
action d'un filtre passe-bas d'ordre 1 sur un créneau
avec un contrôle externe sur la pulsation de coupure.
"""

import numpy as np
import scipy.integrate as integr
from math import *
import cmath
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider,Button
###################
# ZONE A MODIFIER #
###################

Nb = 73
T = 1
w = 2*pi/T
w0 = 1.0*w
Q = .5
Te = 0.01
D = 4.56 * T
Nb = int(D//Te)

def carre(t):
    if t-t//T < T/2:
        return 1.
    else:
        return 0.

def triangle(t):
    if t%T < T/2:
        return 2*(t%(T/2))
    elif t%T > T/2:
        return 1 - 2*(t%(T/2))
    else: return 1
p=.3
def PWM(t):
    if t%T < T*p:
        return 1.
    else:
        return 0.

sinabs = lambda t : np.abs(np.sin(w*t))
sin = lambda t : np.sin(w*t)
fonc = sinabs
##########################
# FIN DE ZONE A MODIFIER #
##########################   
   
    
# échantillonage signal d'entrée
xn = np.zeros(Nb)
for k in range(0,Nb):
    xn[k] = fonc(k*Te)


###################
# ZONE A MODIFIER #
###################
    
# calcul du signal filtré avec linéarisation d'Euler p=1/Te.(1-z^-1)
def passe_(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(1, len(xn)):
        yn[i] = 0
    return yn

def passe_bas(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(1, len(xn)):
        yn[i] = (yn[i-1]+Te*w0_*xn[i])/(1+Te*w0_)
    return yn

def passe_bas_bil(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(1, len(xn)):
        yn[i] = ((2/(Te*w0_) - 1)*yn[i-1] + xn[i] + xn[i-1])/(1+2/(Te*w0_))
    return yn

def passe_haut(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(1, len(xn)):
        yn[i] = (yn[i-1]+xn[i]-xn[i-1])/(1+Te*w0_)
    return yn

def passe_haut_bil(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(1, len(xn)):
        yn[i] = ((1-Te*w0_/2)*yn[i-1]+xn[i]-xn[i-1])/(1+Te*w0_/2)
    return yn

def passe_bande(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(2, len(xn)):
        yn[i] = ((1+2*Q_/(Te*w0_))*yn[i-1] - (Q_/(Te*w0_))*yn[i-2] + xn[i] - xn[i-1])/(1 + Q_*Te*w0_ + Q_/(Te*w0_))
    return yn

def passe_bande_bil(w0_, Q_):
    yn = np.zeros(len(xn))
    for i in range(2, len(xn)):
        yn[i] = ((4*Q_/(Te*w0_) -Q_*Te*w0_)*yn[i-1] + (1 - 2*Q_/(Te*w0_) - Q_*Te*w0_*.5)*yn[i-2] + xn[i] - xn[i-2])/(1 + Q_*Te*w0_*.5 + 2*Q_/(Te*w0_))
    return yn

def passe_passe_bande_bil(w0_, Q_):
    yn = np.zeros(len(passe_bande_bil(w0_, Q_)))
    for i in range(2, len(xn)):
        yn[i] = ((4*Q_/(Te*w0_) -Q_*Te*w0_)*yn[i-1] + (1 - 2*Q_/(Te*w0_) - Q_*Te*w0_*.5)*yn[i-2] + xn[i] - xn[i-2])/(1 + Q_*Te*w0_*.5 + 2*Q_/(Te*w0_))
    return yn
Fonction_passe=passe_bande_bil
    
##########################
# FIN DE ZONE A MODIFIER #
##########################  


#calcul de la FFT et troncage à la moitié pour ne pas visualiser le spectre miroir
def fast_fourier(z):
    zf = abs(np.fft.fft(z))
    return(zf[0:Nb/2])

#spectre du signal d'entrée
xft = fast_fourier(xn)
    
# échelle des temps
tt = np.linspace(0,D,Nb)

#filtrage passe-bas
yn =Fonction_passe(w0, Q)

#spectre du signal de sortie
yft = fast_fourier(yn)

# échelle des fréquences
f = np.linspace(0,1/(2*Te),Nb//2)

fig,ax=plt.subplots()
#plt.subplots()
plt.subplots_adjust(bottom=0.25,wspace=0.3)


plt.subplot(2,2,1)
plt.title(u'''signal d'entrée échantillonné''')
#dessin du signal échantillonné
plt.plot(tt,xn,'bo')
#plt.ylim(-0.2,1.2)

plt.subplot(2,2,2)
plt.title(u'réponse')
#dessin du la réponse
plt.grid()
lrep,=plt.plot(tt,yn,'k--')


plt.subplot(2,2,3)
plt.title(u'''spectre du signal d'entrée''')
#dessin du spectre du signal échantillonné
plt.plot(f,xft)

plt.subplot(2,2,4)
plt.title(u'''spectre du signal de sortie''')
#dessin du spectre du signal échantillonné
lf,=plt.plot(f,yft,'r')

plt.show()       

#boîte contenant le contrôle dynamique
axcolor='yellow'
axw0=plt.axes([0.15,0.1,0.6,0.03],axisbg=axcolor)

sw0=Slider(axw0,'$\omega_0/\omega$',0.01,20,valinit=w0/w)
#action lorsque le contrôle dynamique est modifié
#attention à changer les appels à la fonction si on change le nom passe_bas

def update(val):
    global w0
    global Q
    w0=w*sw0.val
    lrep.set_ydata(Fonction_passe(w0, Q))
    lf.set_ydata(fast_fourier(Fonction_passe(w0, Q)))
    fig.canvas.draw_idle()

sw0.on_changed(update)

axQ = plt.axes([0.15,0.1-.05,0.6,0.03],axisbg=axcolor)
sQ = Slider(axQ,'$Q$',0.001,5,valinit=.5)

def update_Q(val):
    global w0
    global Q
    Q = val
    lrep.set_ydata(Fonction_passe(w0, Q))
    lf.set_ydata(fast_fourier(Fonction_passe(w0, Q)))
    fig.canvas.draw_idle()

sQ.on_changed(update_Q)