#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 25 10:53:56 2021

@author: etienne
"""

import numpy as np
import matplotlib as mpl
mpl.rcParams['lines.linewidth'] = .8
import matplotlib.pyplot as plt
# plt.rcParams.update({
#     "text.usetex": True,
#     "font.family": "serif",
#     "font.size": "10",
#     "font.sans-serif": ["Helvetica"]})

plt.close('all')


def sinus(f0,fe,T_tot):
    t_ana = np.linspace(0,T_tot,10000)         # tps "analogique"
    t_ech = np.arange(0,T_tot,step=1/fe)       # instant des échantillons
    
    S_ana = np.sin(2*np.pi * f0 * t_ana)       # signal d'amplitude 1 V
    S_ech = np.sin(2*np.pi * f0 * t_ech)
    
    return t_ana, S_ana, t_ech, S_ech


def moins_sinus(f0,fe,T_tot):
    t_ana = np.linspace(0,T_tot,10000)         # tps "analogique"
    t_ech = np.arange(0,T_tot,step=1/fe)       # instant des échantillons
    
    S_ana = -np.sin(2*np.pi * f0 * t_ana)       # signal d'amplitude 1 V
    S_ech = -np.sin(2*np.pi * f0 * t_ech)
    
    return t_ana, S_ana, t_ech, S_ech


def creneau(f0,fe,T_tot):
    T0 = 1/f0
    
    t_ana = np.linspace(0,T_tot,10000)         # tps "analogique"
    S_ana = np.ones_like(t_ana) * ((t_ana/T0-np.floor(t_ana/T0)-0.5) > 0)
    
    t_ech = np.arange(0,T_tot,step=1/fe)       # instant des échantillons
    S_ech = np.ones_like(t_ech) * ((t_ech/T0-np.floor(t_ech/T0)-0.5) > 0)
    
    return t_ana, S_ana, t_ech, S_ech

def signal_Nper(f0,fe,Nper,fct):
    """
    Trace et renvoie un signal analogique sinusoïdal de fréquence f0
    et le signal échantillonné à la fréquence fe
    en fixant le nombre de période Nper du signal.
    """
    T_tot = Nper/f0         # durée totale
    t_ana, S_ana, t_ech, S_ech = fct(f0,fe,T_tot)
    
    plt.figure(figsize=(6,2))
    plt.plot(t_ana,S_ana)
    plt.plot(t_ech,S_ech,'or--',ms=3)
    plt.xlim(np.min(t_ana),np.max(t_ana))
    plt.axhline(y=0,color='k')
    plt.xlabel('$t$ (ms)')
    plt.ylabel('signaux')
    
    return t_ana, S_ana, t_ech, S_ech

def signal_Nech(f0,fe,Nech,fct):
    """
    Trace et renvoie un signal analogique sinusoïdal de fréquence f0
    et le signal échantillonné à la fréquence fe
    en fixant le nombre d'échantillons Nech.'
    """
    T_tot = Nech/fe         # durée totale
    t_ana, S_ana, t_ech, S_ech = fct(f0,fe,T_tot)
    
    plt.figure(figsize=(6,2))
    plt.plot(t_ana,S_ana)
    plt.plot(t_ech,S_ech,'or--',ms=3)
    plt.xlim(np.min(t_ana),np.max(t_ana))
    plt.axhline(y=0,color='k')
    plt.xlabel('$t$ (ms)')
    plt.ylabel('signaux')
    
    return t_ana, S_ana, t_ech, S_ech


def spectre_Nrepl(fe,S_ech,Nrepl):
    """
    Calcule le spectre d'un signal S_ech échantillonné à la fréquence fe
    """
    ### Construction du spectre entre 0 et fe
    spectre = np.abs(np.fft.fft(S_ech))
    n = spectre.size
    freq = np.fft.fftfreq(n,d=1/fe)
    if n%2 == 0:
        freq[n//2:] += fe
    else:
        freq[n//2+1:] += fe
    
    # freq = np.linspace(0,fe,spectre.size)
       
    ### Construction des Nrepl répliques et du spectre total
    spectre_tot = spectre
    freq_tot = freq
    
    for n in range(1,Nrepl):
        spectre_tot = np.concatenate((spectre_tot,spectre))
        freq_add = freq + n*fe
        freq_tot = np.concatenate((freq_tot,freq_add))
    
    ### Normalisation
    spectre_tot = spectre_tot/np.max(spectre_tot)

    ### Tracé des figures
    plt.figure(figsize=(6,2))
    plt.minorticks_on()
    plt.bar(freq_tot,spectre_tot,zorder=3)#,width=.2)
    plt.xlim(np.min(freq_tot),Nrepl*fe)
    plt.xlabel('$f$ (kHz)')
    plt.ylabel('spectre normalisé')
    plt.grid(color='.5', which='major', linestyle='-', linewidth=.5)
    plt.grid(color='.75', which='minor', linestyle='-', linewidth=.25)

    return freq_tot, spectre_tot


"""
II.A - Première observations
----------------------------
Simu : Échantillonnage d'un même signal à différentes fréquences

Prendre un signal de fréquence f0 = 10 kHz, tracer sur Nper = 20 périodes,
et modifier la fréquence d'échantillonage pour voir ce que ça donne sur le signal
échantillonné.
"""
f0 = 10     # fréq du signal
Nper = 20   # nbre de périodes utilisées pour la simulation
fe = 54.5    # fréq d'échantillonnage

# signal_Nper(f0,fe,Nper,sinus)


"""
Simu : Plusieurs signaux analogiques différents peuvent donner le même signal 
échantillonné
"""
fe = 10     # fréq du signal
Nech = 10   # nbre d'échantillons (le nbre de périodes s'ajuste en csq)

f0 = 2

# signal_Nech(f0,fe,Nech,sinus)
# signal_Nech(fe-f0,fe,Nech,moins_sinus)
# signal_Nech(fe+f0,fe,Nech,sinus)
# signal_Nech(2*fe-f0,fe,Nech,moins_sinus)



"""
II.B - Spectre d'un signal échantillonné
----------------------------------------
Simu : Réplication du spectre

Prendre un signal échantillonné à fe = 10 kHz et faire varier sa fréquence f0
puis commenter les spectres, calculés sur l'intervalle [0,2fe].
"""
f0 = 2
fe = 10

# t_ana, S_ana, t_ech, S_ech = signal_Nper(f0,fe,50,sinus)
# f, sp = spectre_Nrepl(fe,S_ech,2)



"""
II.D.2 - Fuite spectrale
------------------------
Simu : fuite spectrale

Prendre un signal de fréquence 5 kHz échantillonné à 100 kHz, puis comparer
l'effet de la durée d'acquisition sur le signal en prenant pour commencer
Nper = 1.5 puis Nper = 2 puis Nper = 100.5
"""
f0 = 5
fe = 100

Nper = 1.5
t_ana, S_ana, t_ech, S_ech = signal_Nper(f0,fe,Nper,sinus)
f, sp = spectre_Nrepl(fe,S_ech,1)





plt.show()


