import matplotlib.pyplot as plt
import scipy.integrate as si
import math as m


def graphe(f,*args,**kwargs) :
    inf = 0
    sup = 1
    points = 1000
    if len(args) == 1 :
        sup = args[0]
    elif len(args) == 2 :
        inf,sup = args[0],args[1]
    elif len(args) == 3 :
        inf,sup,points = args[0],args[1],args[2]
    lab = None
    if len(kwargs) != 0 :
        lab = kwargs["legende"]
    liste_x = [ inf+i*(sup-inf)/(points-1)  for i in range(points) ]
    liste_y = [ f(i) for i in liste_x ]
    plt.plot(liste_x,liste_y,label=lab)

def spectre(fonction,f,n) :
    liste_x = [ i  for i in range(n+1) ]
    liste_y = [moyenne(fonction,f)]
    for i in range(1,n+1) :
        liste_y.append(coeff_c(fonction,f,i))
    plt.vlines(liste_x,0,liste_y)
    plt.axis([-1,n+1,0,1.3])



def creneaux(f) :
    T = 1/f
    def fct(t) :
        t = t%T
        if 0 <= t <= T/2 :
            return 1
        elif T/2 < t <= T :
            return -1
    return fct

def triangles(f) :
    T = 1/f
    def fct(t) :
        t = t%T
        if 0 <= t <= T/2 :
            return -1+(4*t/T)
        elif T/2 < t <= T :
            return 1-(4*(t-T/2)/T)
    return fct

def cos_abs(f) :
    T = 1/f
    def fct(t) :
        return abs(m.cos((m.pi/T)*t))
    return f



def moyenne(fonction,f) :
    T = 1/f
    return (1/T)*si.quad(fonction,0,T)[0]
    
def coeff_a(fonction,f,n) :
    T = 1/f
    g = lambda t: (2/T)*(m.cos((2*m.pi/T)*n*t)*fonction(t))
    return (si.quad(g,0,T/2)[0] + si.quad(g,T/2,T)[0])

def coeff_b(fonction,f,n) :
    T = 1/f
    g = lambda t: (2/T)*(m.sin((2*m.pi/T)*n*t)*fonction(t))
    return (si.quad(g,0,T/2)[0] + si.quad(g,T/2,T)[0])

def coeff_c(fonction,f,n) :
    return m.sqrt(coeff_a(fonction,f,n)**2 + coeff_b(fonction,f,n)**2)

def coeff_phi(fonction,f,n) :
    a = coeff_a(fonction,f,n)
    b = coeff_b(fonction,f,n)
    if a == 0 :
        if b < 0 :
            return m.pi/2
        elif b > 0 :
            return -m.pi/2
        else :
            return 0
    elif a > 0 :
        return m.atan(-b/a)
    else :
        return m.atan(-b/a) + m.pi



def fourier(fonction,f,n) :
    T = 1/f
    def somme(t) :
        s = moyenne(fonction,f)
        for i in range(1,n+1) :
            s += coeff_a(fonction,f,i)*m.cos((2*m.pi/T)*i*t) + coeff_b(fonction,f,i)*m.sin((2*m.pi/T)*i*t)
        return s
    return somme

def fourier2(fonction,f,n) :
    T = 1/f
    def somme(t) :
        s = moyenne(fonction,f)
        for i in range(1,n+1) :
            s += coeff_c(fonction,f,i)*m.cos((2*m.pi/T)*i*t+coeff_phi(fonction,f,i))
        return s
    return somme



def passe_bas(fc) :
    def fct(f) :
        return 1/(1+1j*(f/fc))
    return fct

def gain(transfert) :
    def fct(f) :
        return abs(transfert(f))
    return fct

def dephasage(transfert) :
    def fct(f) :
        return cm.phase(transfert(f))
    return fct



def simulation(signal,f,n,transfert) :
    def somme(t) :
        s = moyenne(signal,f)*gain(transfert)(0)
        for i in range(1,n+1) :
            c_sortie = coeff_c(signal,f,i) * gain(transfert)(f*i)
            phi_sortie = coeff_phi(signal,f,i) + dephasage(transfert)(f*i)
            s += c_sortie*m.cos((2*m.pi*f)*i*t + phi_sortie)
        return s
    return somme

def spectre_filtre(fonction,transfert,f,n) :
    liste_x = [ i  for i in range(n+1) ]
    liste_y = [moyenne(fonction,f)*gain(transfert)(0)]
    for i in range(1,n+1) :
        liste_y.append(coeff_c(fonction,f,i)*gain(transfert)(f*i))
    plt.vlines(liste_x,0,liste_y)
    plt.axis([-1,n+1,0,1.3])
    
    
    