#!/usr/bin/env python3
# -*- coding: utf-8 -*-


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


### partie 1 ###

def graphe(f,inf,sup) :
    points = 1000
    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)
    plt.show()



### partie 2 ###

def creneaux(t) :
    t = t%T  # T doit avoir été défini avant
    if 0 <= t <= T/2 :
        return 1
    elif T/2 < t <= T :
        return -1


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



### partie 3 ###

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


#plt.loglog()
#graphe(gain(passe_bas(1000)),0,20000)

#plt.semilogx()
#graphe(dephasage(passe_bas(1000)),0,20000)




### partie 5 ###

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])



### partie 6 ###

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




### partie 7 ###

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 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 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,2])



### partie 8 ###

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









