"""
TP Électronique 9
EFFET D'UN FILTRE SUR UN SIGNAL

Script à compléter
"""

import numpy as np
import matplotlib.pyplot as plt


### ============================================================================
### DÉFINITION DES FONCTIONS
### ============================================================================

def spectre_creneau(freq, ampl, offset, Nharm):
    """
    Renvoie le spectre d'un signal créneau
    freq : fréquence
    ampl : amplitude crête-à-crête
    offset : composante continue
    Nharm : nombre d'harmoniques à considérer en plus de la composante continue
    """
    f = [0] # composante continue
    A = [offset]
    phi = [0]

    for n in range(Nharm):
        f.append( (2*n+1)*freq )
        A.append( 2*ampl/(np.pi * (2*n+1)) )
        phi.append(-np.pi/2)
    
    return f, A, phi

def spectre_triangle(freq, ampl, offset, Nharm):
    """
    Renvoie le spectre d'un signal triangle
    freq : fréquence
    ampl : amplitude crête-à-crête
    offset : composante continue
    Nharm : nombre d'harmoniques à considérer en plus de la composante continue
    """
    f = [0] # composante continue
    A = [offset]
    phi = [0]

    for n in range(Nharm):
        f.append( (2*n+1)*freq )
        A.append( 8*ampl/(np.pi**2 * (2*n+1)**2) )
        phi.append(0)
    
    return f, A, phi


def spectre_to_signal(sp):
    """
    Renvoie le signal temporel sur trois périodes associé au spectre sp
    sp : liste à trois éléments f (fréquence des harmoniques), 
    A (amplitude des harmoniques) et phi (phase des harmoniques)
    """
    f, A, phi = sp

    # Fréquence du fondamental et période du signal
    if f[0] < 1e-12:
        T = 1/f[1]
    else :
        T = 1/f[0]

    # Construction harmonique par harmonique du signal de sortie
    t = np.linspace(0,3*T,1000)
    s = np.zeros_like(t)

    for n in range(len(f)):
        s += A[n] * np.cos(2*np.pi*f[n]*t + phi[n])
    
    return t,s


def H_PBas1(f, H0, fc, Q=None):
    """
    Fonction de transfert d'un passe-bas d'ordre 1
    f : fréquence du signal d'entrée
    H0 : gain statique
    fc : fréquence de coupure
    Q : aucun rôle
    """
    x = f/fc
    return H0/(1+1j*x)

def H_PHaut1(f, H0, fc, Q=None):
    """
    Fonction de transfert d'un passe-haut d'ordre 1
    f : fréquence du signal d'entrée
    H0 : gain en haute fréquence
    fc : fréquence de coupure
    Q : aucun rôle
    """
    x = f/fc
    return H0*1j*x/(1+1j*x)

def H_PBas2(f, H0, f0, Q):
    """
    Fonction de transfert d'un passe-bande d'ordre 2
    f : fréquence du signal d'entrée
    H0 : gain à la résonance
    f0 : fréquence propre
    Q : facteur de qualité
    """
    x = f/f0
    return H0/(1 - x**2 + 1j*x/Q)

def H_PBande(f, H0, f0, Q):
    """
    Fonction de transfert d'un passe-bande d'ordre 2
    f : fréquence du signal d'entrée
    H0 : gain à la résonance
    f0 : fréquence de résonance
    Q : facteur de qualité
    """
    x = f/f0
    return H0/(1+1j*Q*(x-1/x))

def calc_spectre_sortie(sp, H, H0, fc, Q=None):
    """
    Renvoie le spectre de sortie d'un filtre connaissant le spectre d'entrée
    sp : spectre d'entrée
    H : fonction permettant de calculer la fonction de transfert du filtre
        doit être une des fonctions définies ci-dessus
    H0 : gain du filtre à la résonance
    fc : fréq de coupure ou de résonance du filtre
    Q : facteur de qualité (optionnel)
    """
    f, Ae, phi_e = sp

    As = []
    phi_s = []

    for n in range(len(f)):
        Hf = H(f[n], H0, fc, Q)
        As.append(np.abs(Hf) * Ae[n])
        phi_s.append(np.angle(Hf) + phi_e[n])
    
    return f, As, phi_s


def affiche_spectre(f,sp):
    w = (f[2] - f[1])/8
    plt.bar(f, sp, width=.8*w)


### ================================================================================
### PROGRAMME UTILISANT LES FONCTIONS DÉFNIES CI-DESSUS
### ================================================================================

sp_e = spectre_creneau(300, 2, 1, 1000)
t, se = spectre_to_signal(sp_e)

sp_s = calc_spectre_sortie(sp_e, H_PBas1, 1, 1e3, 1/np.sqrt(2))
t, ss = spectre_to_signal(sp_s)


plt.figure()
affiche_spectre(sp_e[0], sp_e[1])
affiche_spectre(sp_s[0], sp_s[1])
# plt.bar(sp_e[0], sp_e[1], width=100)
# plt.bar(sp_s[0], sp_s[1], width=100)
plt.xlim(0,10e3)

plt.figure()
plt.plot(t,se)
plt.plot(t,ss)
plt.xlabel('t (s)')
plt.ylabel('Signaux (V)')




