{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "24613260",
   "metadata": {},
   "source": [
    "# Traitement du Signal - TDM7 : Filtrage Idéal\n",
    "\n",
    "---\n",
    "\n",
    "Vous être des maîtres de la convolution et de la transformée de Fourier depuis maintenant quelques jours. Votre mission du jour : mettre à profit votre expertise pour filtrer les vilaines fréquences des signaux. Je compte sur vous !"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "382a8d4e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Import des librairies\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74445521",
   "metadata": {},
   "source": [
    "## Exercice 1 : Dans un monde parfait, les filtres sont idéaux\n",
    "\n",
    "Comme évoqué dans le titre, on va se concentrer aujourd'hui uniquement sur les filtres *idéaux*. Alors pourquoi on parle de filtres *idéaux* ? Ce sont des filtres qui sont une définition de ce qu'on souhaite avoir idéalement comme filtre. Pour exemple, un filtre passe-bas à une fréquence de coupure $f_c$ est idéal si:\n",
    "- toutes les composantes dont les fréquences sont inférieures ou égales à $f_c$ sont conservées sans modification\n",
    "- toutes les composantes dont les fréquences sont supérieures à $f_c$ sont éliminées sans bruit\n",
    "\n",
    "*\"Bah c'est super comme filtre ça !\"*\n",
    "\n",
    "Eh oui ! Et c'est ce qu'on va principalement faire aujourd'hui: les créer numériquement, les appliquer, mais également comprendre les limites."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e97ff1a",
   "metadata": {},
   "source": [
    "Tout d'abord, avant de filtrer, il nous faut un signal. Pour cela, on va partir sur une somme de sinusoïdes, afin de voir très distinctement les fréquences dans le spectre d'amplitude. Créez maintenant le signal suivant :\n",
    "\n",
    "\\begin{equation*}\n",
    "    x(t) = 3 \\cdot sin(2 \\pi f_0 t - \\frac{\\pi}{2}) + sin(2 \\pi f_1 t + \\frac{\\pi}{3}) + 0.5 \\cdot sin(2 \\pi f_2 t) + 0.1 \\cdot sin(2 \\pi f_3 t + \\frac{\\pi}{6})\n",
    "\\end{equation*}\n",
    "\n",
    "Avec $f_0 = 5 Hz$, $f_1 = 50 Hz$, $f_2 = 100 Hz$ et $f_3 = 200 Hz$. Le signal évoluera entre 0 et 1 secondes avec un pas de 0.001 secondes. Affichez ensuite le signal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6d6bab6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création du signal x et affichage\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f5395d9",
   "metadata": {},
   "source": [
    "Calculez $X(f)$, la transformée de Fourier réelle de $x(t)$ et affichez le spectre d'amplitude"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4d3b09f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# FFT réelle de x(t)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f585188",
   "metadata": {},
   "source": [
    "**Avant de passer à la suite, VERIFIEZ BIEN que vous avez le bon résultat !**\n",
    "\n",
    "*Pour cela, vous avez la plateforme à disposition si vous voulez vérifier...*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84e46dc5",
   "metadata": {},
   "source": [
    "On va pouvoir créer notre premier filtre : un filtre passe-bas. La construction d'un filtre idéal se fait dans le domaine fréquentiel, donc on va design le filtre $H(f)$ pour l'appliquer ensuite directement sur $X(f)$."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fe0c9e9",
   "metadata": {},
   "source": [
    "**_QUESTION :_** A quoi ressemble le spectre d'amplitude d'un filtre passe-bas idéal en fréquentiel ?\n",
    "\n",
    "*Pour rappel, un filtre passe-bas va mettre à zéro toutes les composantes dont la fréquence est supérieure à $f_c$, la fréquence de coupure*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c1f04a3",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1dd2ef9b",
   "metadata": {},
   "source": [
    "Calculez le spectre d'amplitude du filtre passe-bas idéal $H(f)$, avec une fréquence de coupure $f_c = 20 Hz$. Affichez ensuite les spectres d'amplitude de $X(f)$ et $H(f)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa4aaba0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création du filtre passe-bas H(f)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3aedbd2",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Que devrait donne théoriquement l'application du filtre passe-bas $H(f)$ sur le signal $X(f)$ ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da66150b",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fef8c967",
   "metadata": {},
   "source": [
    "Calculez maintenant le signal filtré $Y(f) = X(f) \\cdot H(f)$ et affichez le spectre d'amplitude\n",
    "\n",
    "**_ATTENTION :_** *la multiplication attendue ne se fait pas sur le spectre d'amplitude, mais sur le résultat de la RFFT ! Ne confondez pas $X(f)$ et son spectre d'amplitude !*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fedca0ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Calcul de Y(f) et affichage du spectre d'amplitude\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a66ee499",
   "metadata": {},
   "source": [
    "Effectuez maintenant une FFT réelle inverse de $Y(f)$ pour retrouver votre signal filtré $y(t)$. Comparez le résultat avec ce que vous devriez avoir théoriquement (construisez ce signal théorique en temporel), et affichez sur un même graphique les deux signaux.\n",
    "\n",
    "*Note : assurez vous dans la FFT réelle inverse que le signal temporel en sortie soit de même taille que $x(t)$ (il y a un paramètre à définir pour cela)*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05123114",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# FFT réelle inverse, construction du signal filtré théorique et affichage des deux signaux\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5232dc9",
   "metadata": {},
   "source": [
    "Regroupez le code que vous avez produit précédemment pour créer une fonction de filtre passe-bas, prenant en entrée un signal temporel à filtrer, son temps d'échantillonage et une fréquence de coupure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "844f00fb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction de filtre passe-bas\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "875dc4ed",
   "metadata": {},
   "source": [
    "Super ! Vous avez votre première fonction de filtrage ! Développez dans le même esprit maintenant les fonctions de filtrage suivant:\n",
    "- Filtrage passe-haut\n",
    "- Filtrage passe-bande\n",
    "- Filtrage coupe-bande\n",
    "\n",
    "Après développement, testez vos fonctions sur le signal $x(t)$ et affichez sur le même graphique le résultat du filtrage ainsi que le résultat théorique en fonction de votre filtre et de vos paramètres."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58a9c4a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction des filtres passe-haut, passe-bande et coupe-bande\n",
    "..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d0d8732",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Application du filtre passe-haut sur x(t) à fc = 150 Hz\n",
    "..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a649264f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Application du filtre passe-bande sur x(t) à fc1 = 25 Hz et fc2 = 75 Hz\n",
    "..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3f59eaae",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Application du filtre coupe-bande sur x(t) à fc1 = 80 Hz et fc2 = 150 Hz\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc490f07",
   "metadata": {},
   "source": [
    "Si tout est correct, vous pouvez réécrire vos fonctions précédentes dans cette magnifique Golden Cellule, toujours pour vous aider à garder le code des bases importantes de TDS. Pourquoi garder nos fonctions ? Car NumPy et SciPy ne proposent pas de fonctions de filtrage idéal comme nous le faisons (mais vous comprendrez pourquoi dans la suite du TDM...).\n",
    "\n",
    "*Vous n'êtes pas obligé de remplir la cellule tout de suite en séance, même si honnêtement, c'est du copier-coller*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49ba9ea8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# GOLDEN CELLULE A COMPLETER\n",
    "# Filtrages idéaux\n",
    "\n",
    "# Paramètres des fonctions (MODIFIEZ AVEC VOS NOMS DE VARIABLES)\n",
    "# ... :  un signal temporel à filtrer\n",
    "# ... : le temps d'échantillonnage\n",
    "# ... : les fréquences de coupure du filtre\n",
    "\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "115c6734",
   "metadata": {},
   "source": [
    "Ok, donc on a 4 fonctions de filtrage. On pourrait donc se dire que tout est nickel, pas besoin d'aller plus loin, TDS c'est trop facile comme EC...\n",
    "\n",
    "Cependant, on parle bien ici de filtre idéal, mais la vie est cruelle, et ce filtrage idéal est, dans la majorité des cas, impossible à réaliser. Et on va voir certaines de ces raisons dans l'exercice suivant"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eec706bf",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercice 2 : Mais la vie ne fait pas de cadeau...\n",
    "\n",
    "Comme vu précédemment, on applique un filtre idéal via une transformée de Fourier (classique ou réelle) du signal. Cela nécessite donc en théorie d'avoir tout le signal.\n",
    "\n",
    "*En réalité, on peut effectuer un découpage de signal en blocs successifs et d'appliquer des FFT sur chacun de ces blocs, mais ça engendre d'autres problèmes...*\n",
    "\n",
    "Maintenant, au lieu de l'appliquer en fréquentiel, **est-ce qu'on ne pourrait pas l'appliquer en temporel ?** Et ça va être tout l'objectif de cet exercice :D\n",
    "\n",
    "**_QUESTION :_** Afin d'appliquer le filtre idéal en temporel, quelle théorème vu en cours va-t-on utiliser ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1544728e",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2f824d0",
   "metadata": {},
   "source": [
    "On va pour cet exercice reprendre l'exemple de l'exercice précédent, donc le signal $x(t)$, et on va appliquer un filtre passe-bas avec $f_c = 20 Hz$. Recalculez ci-dessous $t$ et $x(t)$ comme fait précédemment en début de TDM (c'est juste pour être sûr que vous avez le bon signal en début de cet exercice)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ba13911",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Construction de t et x(t) et Te\n",
    "t = ...\n",
    "x = ...\n",
    "Te = ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a38e021e",
   "metadata": {},
   "source": [
    "Comme dit précédemment, on va reprendre un filtre passe-bas idéal. Ici, je vous fournis le code afin de le construire directement, en se rapprochant au mieux de la définition du filtre idéal (nombre d'échantillons élevé $N$, donc avec une résolution spectrale très fine), tout en partant sur la même fréquence d'échantillonnage que le signal $x(t)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd28859b",
   "metadata": {},
   "outputs": [],
   "source": [
    "Fe = 1 / Te\n",
    "fc = 20\n",
    "\n",
    "# Construction du filtre fréquentiel\n",
    "N = 100000\n",
    "\n",
    "freq = np.fft.rfftfreq(N, d=Te)\n",
    "H = (freq <= fc).astype(float)\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(freq,H)\n",
    "plt.title(\"Filtre passe-bas H(f)\")\n",
    "plt.xlabel(\"Fréquence (Hz)\")\n",
    "plt.ylabel(\"Amplitude\")\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bf36c70",
   "metadata": {},
   "source": [
    "La prochaine étape ici va être de profiter d'appliquer une transformée de Fourier réelle inverse au filtre passe-bas, afin ensuite de l'exploiter dans le domaine temporel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f7a4471a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Réponse impulsionnelle centrée\n",
    "# fftshift est utilisée ici pour centrer la réponse impulsionnelle autour de 0\n",
    "h = np.fft.fftshift(np.fft.irfft(H, n=N))\n",
    "\n",
    "# Axe temporel associé\n",
    "t_h = (np.arange(N) - N//2) * Te\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(t_h,h)\n",
    "plt.title(\"Réponse impulsionnelle h(t)\")\n",
    "plt.xlabel(\"Temps (s)\")\n",
    "plt.ylabel(\"Amplitude\")\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0394d576",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que ce filtre temporel est physiquement réalisable ? Pourquoi ?\n",
    "\n",
    "*Note : la réponse est dans votre CM... Mais non, je vous le jure, c'est dingue !*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ede2bafc",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd0c45b3",
   "metadata": {},
   "source": [
    "Bon, pour rendre ce filtre \"physiquement réalisable\", on va du coup le modifier légèrement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "74f6f54c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Décalage de la réponse impulsionnelle pour obtenir la réponse impulsionnelle causale\n",
    "t_h_causal = (np.arange(N)) * Te\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(t_h_causal, h)\n",
    "plt.title(\"Réponse impulsionnelle causale h(t)\")\n",
    "plt.xlabel(\"Temps (s)\")\n",
    "plt.ylabel(\"Amplitude\")\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e21a771c",
   "metadata": {},
   "source": [
    "Nous avons maintenant construit un filtre causal, mais **ce filtre n'est pas parfaitement idéal**.\n",
    "\n",
    "*En réalité, notre filtre était déjà une approximation du filtre idéal : sa réponse fréquentielle a été définie sur un nombre fini de fréquences, puis transformée en une réponse impulsionnelle de durée finie. Or, un filtre passe-bas parfaitement idéal possède une réponse impulsionnelle de durée infinie, qui ne peut pas être rendue causale par un simple décalage temporel.*\n",
    "\n",
    "Bon, on va pouvoir appliquer ce filtre qui, même s'il n'est pas idéal, est une bonne **approximation d'un filtre idéal passe-bas**. Pour cela, on va effectuer une convolution (cf. théorème de convolution), et le comparer avec le résultat théorique qu'on devrait obtenir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e8dc886",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Application du filtre causal sur le signal x(t) et affichage du résultat en comparaison avec le résultat théorique\n",
    "\n",
    "y_theorique = 3*np.sin(2*np.pi*f0*t - np.pi/2)\n",
    "\n",
    "y = np.convolve(x, h, mode='full')  # Convolution avec la réponse impulsionnelle causale\n",
    "t_y = np.arange(0, len(y)*Te, Te)  # Axe temporel pour le signal filtré\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(t_y,y,label='y(t) (x(t) filtré)')\n",
    "plt.plot(t, y_theorique,label='y(t) (théorique)')\n",
    "plt.xlabel('Temps (s)')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.title('Filtrage causal')\n",
    "plt.legend()\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5601d620",
   "metadata": {},
   "source": [
    "Le résultat obtenu est, pour être honnête, pas très satisfaisant. Alors pourquoi ?\n",
    "\n",
    "Cela s'explique par la durée de notre filtre passe-bas : il évolue durant **100 secondes !!!** C'est énorme par rapport au signal $x(t)$ qui dure 1 seconde.\n",
    "\n",
    "Cependant, on peut observer le résultat central de la convolution:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8744a90",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Extraction de la partie centrale du signal filtré correspondant à la durée du signal original\n",
    "N = len(y)\n",
    "center = N // 2\n",
    "\n",
    "y_compense = y[center - len(x) // 2 : center + len(x) // 2]\n",
    "\n",
    "plt.figure()\n",
    "plt.plot(t, y_compense, label='y(t) (compensé)')\n",
    "plt.plot(t, y_theorique, label='y(t) (théorique)')\n",
    "plt.xlabel('Temps (s)')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.title('Filtrage causal (visualisation centrale du résultat)')\n",
    "plt.legend()\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0059b757",
   "metadata": {},
   "source": [
    "**_QUESTION :_** A travers les résultats obtenus (résultat brut et visualisation centrale), que peut-on dire de la convolution avec ce filtre approximé ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a707e151",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5415eda6",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Quel est le retard du signal convolué ? A quoi cela correspond ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f25dafb",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6be9711",
   "metadata": {},
   "source": [
    "Bon, même si le résultat centré est super, ce filtre n'est pas vraiment utilisable dans l'état: on a un retard ultra important. Alors coman kon fé ?\n",
    "\n",
    "Dans la suite de cet exercice, on va redimensionner ce filtre, afin de réduire ce retard. Pour cela, on aura juste à tronquer le filtre temporel original, et répéter les différentes opérations. Je vous ai regroupé pour cela le code réalisé précédemment, ainsi qu'une visualisation du filtre dans le domaine fréquentiel, via la fonction suivante clé en main !"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4729e4b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.signal import freqz\n",
    "\n",
    "# Fonction d'application du filtre non causal sur un signal s\n",
    "def filter_and_compare(s, t_h, h, Te, y_theorique):\n",
    "    \"\"\"\n",
    "    Applique un filtre sur le signal s en utilisant la réponse impulsionnelle h, et compare le résultat avec le signal théorique y_theorique.\n",
    "    s : tableau 1D NumPy, le signal à filtrer\n",
    "    t_h : tableau 1D NumPy, l'axe temporel pour la réponse impulsionnelle\n",
    "    h : tableau 1D NumPy, la réponse impulsionnelle du filtre\n",
    "    Te : float, le temps d'échantillonnage de s et h\n",
    "    y_theorique : tableau 1D NumPy, le signal théorique de référence\n",
    "    \"\"\"\n",
    "    \n",
    "    y = np.convolve(s, h, mode='full')  # Convolution avec la réponse impulsionnelle causale\n",
    "    t_y = np.arange(0, len(y)*Te, Te)  # Axe temporel pour le signal filtré\n",
    "    \n",
    "    # Extraction de la partie centrale du signal filtré correspondant à la durée du signal original\n",
    "    N = len(y)\n",
    "    center = N // 2\n",
    "    y_compense = y[center - len(s) // 2 : center + len(s) // 2]\n",
    "    \n",
    "    # Calcul de la réponse fréquentielle du filtre\n",
    "    f, H = freqz(h, worN=8192, fs=1/Te)\n",
    "    \n",
    "    plt.subplots(2,2, figsize=(15,10))\n",
    "    plt.subplot(2,2,1)\n",
    "    plt.plot(t_h, h)\n",
    "    plt.title(f\"Réponse impulsionnelle h(t) \\n ({-t_h[0]*2} s)\")\n",
    "    plt.xlabel(\"Temps (s)\")\n",
    "    plt.ylabel(\"Amplitude\")\n",
    "    plt.subplot(2,2,2)\n",
    "    plt.plot(t_y, y)\n",
    "    plt.title(f\"Signal filtré y(t) avec h(t) causal \\n ({-t_h[0]*2} s)\")\n",
    "    plt.xlabel(\"Temps (s)\")\n",
    "    plt.ylabel(\"Amplitude\")\n",
    "    plt.subplot(2,2,3)\n",
    "    plt.plot(t, y_compense, label='y(t) (x(t) filtré centré)')\n",
    "    plt.plot(t, y_theorique, label='y_theorique(t)')\n",
    "    plt.title(f\"Signal filtré y(t) (visualisation centrale du résultat) \\n ({-t_h[0]*2} s)\")\n",
    "    plt.xlabel(\"Temps (s)\")\n",
    "    plt.ylabel(\"Amplitude\")\n",
    "    plt.legend()\n",
    "    plt.subplot(2,2,4)\n",
    "    plt.plot(f, np.abs(H))\n",
    "    plt.title(f\"Réponse fréquentielle du filtre \\n ({-t_h[0]*2} s)\")\n",
    "    plt.xlabel(\"Fréquence (Hz)\")\n",
    "    plt.ylabel(\"Amplitude\")\n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    \n",
    "filter_and_compare(x, t_h, h, Te, y_theorique)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b58414f",
   "metadata": {},
   "source": [
    "Bon, ça va être (enfin) à vous de jouer ! Modifiez déjà la réponse impulsionnelle $h(t)$ pour qu'elle évolue entre -10 et 10 secondes. Pour cela, il faut:\n",
    "- Tronquer le signal $h(t)$ pour ne garder que la partie évoluant entre -10 et 10 secondes\n",
    "- Modifier l'axe temporel associé $t\\_h$\n",
    "\n",
    "Effectuez ces opérations, et visualisez le résultat du filtrage via la fonction *filter_and_compare*\n",
    "\n",
    "*Note: je vous conseille d'utiliser np.argwhere pour trouver les indices des tableaux NumPy compris dans votre intervalle de temps*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7569a734",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Modification de h(t) pour qu'il évolue de -10 à 10 secondes, et visualisation du résultat du filtrage sur le signal x(t)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0c60a33",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Que remarquez-vous ? Quelles sont les améliorations mais aussi les défauts avec $h(t)$ variant de -1 à 1 secondes ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "649a6360",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77249ad4",
   "metadata": {},
   "source": [
    "Répétez les mêmes opérations, mais en faisant varier $h(t)$ pour qu'il évolue entre $-T$ et $T$ secondes, avec $T \\in \\{1, 0.1, 0.01\\}$ secondes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d2dd5b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Modification de h(t) pour qu'il évolue de -T à T secondes (T = 1, 0.1, 0.01 ), et visualisation du résultat du filtrage sur le signal x(t)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e6df49d",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Comment évolue le résultat du filtrage à mesure que $T$ décroit ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ac2d0f8",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fcc829c",
   "metadata": {},
   "source": [
    "*\"Bon, bah ça a servi à quoi tout ça ?\"*\n",
    "\n",
    "Cet exercice avait comme volonté de montrer en quoi un filtre idéal est impossible à appliquer exactement dans un système physique fonctionnant en temps réel, pour plusieurs raisons:\n",
    "\n",
    "- Le filtre est non causal\n",
    "- La représentation fréquentielle qu'on construit est discrétisée et bornée entre 2 fréquences min et max\n",
    "- Le filtre est physiquement irréalisable (ex: montage d'un filtre passe-bas avec des composants électroniques)\n",
    "\n",
    "En revanche, ce qu'on a fait ici, sans que vous le sachiez pour l'instant, et un filtrage réel particulier : **un filtrage à réponse impulsionnelle finie (filtre RIF)**. Ce sont des filtres approximant les filtres idéaux appliqués en temporel. Vous entendrez parler de ces filtres en fin de semestre, donc on reviendra en partie dessus ;)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "819f0e3b",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercice 3 : Une séparation difficile, mais nécessaire...\n",
    "\n",
    "Pour ce dernier exercice, vous avez un audio à votre disposition. Pas de bruit, pas de soucis, c'est l'original. Ecoutez-le dans un premier temps."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b112f1fc",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Combien d'instruments/parties identifiez-vous dans l'audio ? Sont-ils tous bien distinguables des autres ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dba13bc9",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f90d81b2",
   "metadata": {},
   "source": [
    "Chargez l'audio et affichez le signal"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39a8bba1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Chargement de l'extrait audio\n",
    "...\n",
    "\n",
    "# Reconstruction de l'axe temporel\n",
    "...\n",
    "\n",
    "# Tracé du signal audio\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b811338",
   "metadata": {},
   "source": [
    "L'objectif du jour va être d'isoler au mieux les instruments que vous entendez, afin de créer des pistes audios séparées. Pour cela, vous avez vos filtres idéaux à votre disposition. A vous de créer un audio avec uniquement la basse, un autre avec les percussions, un autre avec la mélodie, etc."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c52bfacb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Extraction des différentes éléments de l'audio par filtrage et enregistrement dans des sous-fichiers WAV\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d85632b2",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que vos extractions de pistes audios sont satisfaisantes ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13ec69ec",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "deep",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
