{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "daf9966c",
   "metadata": {},
   "source": [
    "# Traitement du Signal - TP4 : Convolution\n",
    "\n",
    "---\n",
    "\n",
    "Aujourd'hui, on va faire des convolutions. Beaucoup de convolutions. On va coder la fonction, puis l'utiliser dans plein de situations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eee92c54",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Import des librairies\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fda4484",
   "metadata": {},
   "source": [
    "## Exercice 1 : Pour faire des convolutions, il faut une fonction..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8c0bf77",
   "metadata": {},
   "source": [
    "Avant de commencer à effectuer des convolutions, on va tout d'abord coder la fonction. Pour rappel, la fonction de convolution entre un signal *f(t)* et *g(t)* :\n",
    "\n",
    "\\begin{equation*}\n",
    "f(t) \\ast g(t) = \\int_{-\\infty}^{\\infty} f(\\tau) g(t - \\tau) \\, d \\tau\n",
    "\\end{equation*}\n",
    "\n",
    "Evidemment, cette formule fonctionne en analogique, mais on fait du numérique ici, ce qui signifie qu'il faut utiliser la fonction de convolution discrète : \n",
    "\n",
    "\\begin{equation*}\n",
    "f[n] \\ast g[n]=\\sum_{m=-\\infty}^{\\infty} f[m] \\cdot g[n-m] \\cdot T_e\n",
    "\\end{equation*}\n",
    "\n",
    "Ici, $T_e$ est le temps d'échantillonage de $f$ et $g$."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09f9d800",
   "metadata": {},
   "source": [
    "*Attends, ça me dit un truc cette formule... Un mauvais souvenir sûrement...*\n",
    "\n",
    "Et non, tu ne rêves pas jeune ITI3. Si ça te rappelle quelque chose, c'est qu'elle est très proche d'une autre fonction que nous avons déjà développé : la fonction de corrélation. On va gagner beaucoup de temps !\n",
    "\n",
    "Récupérez les fonctions utilisées durant le TP2 pour la corrélation, et modifiez-les pour effectuer une convolution à la place."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a2a9103",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Développement de la fonction de convolution\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57643863",
   "metadata": {},
   "source": [
    "On va tester notre fonction de convolution ! Pour cela, créez les deux signaux suivants :\n",
    "- $x(t) = \\Pi_{1}(t-t_0)$, avec $t_0 = 2$ \n",
    "- $h(t) = e^{-t}$ \n",
    "\n",
    "Les deux signaux ont une fréquence d'échantillonnage de $100 Hz$, et évoluent de 0 à 5 secondes.\n",
    "\n",
    "Créez les deux signaux et tracez les sur une même figure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "186d4c27",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création et affichage des deux signaux\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34fda742",
   "metadata": {},
   "source": [
    "Calculez $y(t) = x(t) \\ast h(t)$ et affichez le résultat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30df9ad6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Calcul de y(t) = x(t)*h(t) et affichage du résultat\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd0bd4ea",
   "metadata": {},
   "source": [
    "Bon, et pour finir, effectuez la convolution cette fois avec NumPy. Affichez sur une même figure les deux résultats obtenus."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8fd4e799",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Calcul de la convolution avec NumPy et affichage des résultats de convolution\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4452fe9d",
   "metadata": {},
   "source": [
    "Et si tout est bien codé, vous devriez avoir exactement la même courbe. Well done !"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa5000e0",
   "metadata": {},
   "source": [
    "## Exercice 2 : J'adore mon signal, je voudrais l'avoir tout le temps !\n",
    "\n",
    "Pour ce deuxième exercice, on va transformer un signal bref en un signal périodique.\n",
    "\n",
    "Commencez par créer un signal triangulaire :\n",
    "\n",
    "\\begin{equation*}\n",
    "    x(t) = \\Delta(t) = 1-|t-1|\n",
    "\\end{equation*}\n",
    "\n",
    "Le signal évoluera entre 0 et 2 secondes, avec une fréquence d'échantillonage de $100 Hz$. Créez et affichez le signal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa9b03e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création et affichage du signal triangulaire\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f81cc58",
   "metadata": {},
   "source": [
    "L'objectif maintenant va être de rendre ce signal périodique sur une durée de 0 à 10 secondes. Pour cela, on va créer le signal $h(t)$ approprié, tel que $y(t) = x(t) \\ast h(t)$ est le même signal que $x(t)$ mais périodique (avec $T$ la durée de $x(t)$) et évoluant entre 0 et 10 secondes."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0ace1d6c",
   "metadata": {},
   "source": [
    "**_QUESITON :_** Quel doit être le signal $h(t)$ pour construire le signal $y(t)$ souhaité ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b0dd384",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3867b33c",
   "metadata": {},
   "source": [
    "Construisez le signal $h(t)$ approprié pour notre tâche et affichez le résultat.\n",
    "\n",
    "*Note : Au lieu de faire évoluer de 0 à 10 secondes, je vous conseille de faire évoluer de 0 à 10.01 secondes...*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e823b455",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création de h(t) et affichage\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26606017",
   "metadata": {},
   "source": [
    "Appliquez la convolution sur les signaux $x(t)$ et $h(t)$ et affichez le résultat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a218cda",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Convolution entre x(t) et h(t) et affichage du résultat\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "062e17c4",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que le résultat obtenu est celui attendu ?\n",
    "\n",
    "*Note : Regardez bien les axes et les valeurs*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62e11196",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "737da814",
   "metadata": {},
   "source": [
    "Modifiez $h(t)$ afin de corriger le problème (si vous avez constaté un problème...).\n",
    "\n",
    "*Note : il y'a une différence entre l'analogique et le numérique. Ici, ça concerne l'échantillonage utilisé...*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "685a09f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Modification de h(t) pour corriger y(t)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1459d869",
   "metadata": {},
   "source": [
    "Modifiez maintenant $h(t)$ en augmentant la période ($T = 3 s$), puis en diminuant la période ($T = 1.5 s$). Effecutez les convolutions entre $x(t)$ et les nouvelles versions de $h(t)$ et affichez les résultats."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60a1458e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Modification de h(t) avec T = 3 secondes\n",
    "..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0fd6510",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Modification de h(t) avec T = 1.5 secondes\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "062ce7e4",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que les produits de convolution sont périodiques ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "524139d5",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d478bdb",
   "metadata": {},
   "source": [
    "## Exercice 3 : Plancherel ?! J'ai déjà entendu cette théorie...\n",
    "\n",
    "Pour ce 3ème exercice, construisez les signaux suivants : \n",
    "- $x(t) = sin(2 \\pi f_0 t)$, avec $f_0 = 2 Hz$.\n",
    "- $h(t) = sin(2 \\pi f_1 t)$, avec $f_1 = 5 Hz$.\n",
    "\n",
    "Les signaux évolueront entre 0 et 5 secondes, avec une fréquence d'échantillonage de $100 Hz$.\n",
    "\n",
    "Créez ces deux signaux et affichez les sur 2 figures différentes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71c1a68f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création de x(t) et h(t) et affichage des signaux\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd31ecf8",
   "metadata": {},
   "source": [
    "Effectuez la transformée de Fourier réelle sur les deux signaux et affichez les spectres d'amplitudes des deux signaux (sur 2 figures séparées)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "647ae294",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# FFT réelle de x(t) et h(t) et affichage des spectres d'amplitude\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a8b2705",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Que devrait donner théoriquement la convolution entre $x(t)$ et $h(t)$ ?\n",
    "\n",
    "*Indice : C'est quoi le titre de l'exo ?*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64a509a4",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "61c664c0",
   "metadata": {},
   "source": [
    "Effectuez la convolution entre $x(t)$ et $h(t)$ et vérifiez que votre hypothèse est bien confirmée.\n",
    "\n",
    "**ATTENTION : x(t) et h(t) ! Pas X(f) et H(f) !**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c49362dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Convolution entre x(t) et h(t) et affichage du résultat\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1afe712",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que le résultat obtenu est conforme à ce qui était attendu ?\n",
    "\n",
    "*Note : n'hésitez pas à tracer les signaux $x(t)$ et $y(t)$ sur une même figure pour mieux visualiser si besoin*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "61f67631",
   "metadata": {},
   "source": [
    "**_REPONSE :_** "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14c8af07",
   "metadata": {},
   "source": [
    "Pour vérifier le théorème de Plancherel, reproduisez le même signal y(t) obtenu en passant par le produit des FFT. Pour cela :\n",
    "- Calculez les FFT réelles de $x(t)$ et $h(t)$ (en précisant en paramètre le nombre de bins $n=len(x)+len(h)-1$)\n",
    "- Calculez $Y(f) = X(f).H(f)$\n",
    "- Calculez la FFT inverse réelle de $Y(f)$ et divisez le résultat par la fréquence d'échantillonnage $f_e$.\n",
    "\n",
    "Tracez ensuite les deux signaux sur une même figure pour vérifier que vous obtenez le même résultat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb7f7037",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Vérification du théorème de Plancherel\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bea718ac",
   "metadata": {},
   "source": [
    "Normalement, vous obtenez exactement la même courbe que celle faite par convolution."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a43c249",
   "metadata": {},
   "source": [
    "Répétez les convolutions entre $x(t)$ et $h(t)$ en modifiant $f_1 = 5, 10 , 20 , 50 Hz$ et tracez les signaux $y(t)$ obtenus."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "85c9a3bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Convolution entre x(t) et h(t) avec f1 = [5, 10, 20, 50] Hz\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "097c522d",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Que constatez-vous ? Quelle serait potentiellement l'explication de ces résultats ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "453a3961",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2148f07",
   "metadata": {},
   "source": [
    "## Exercice 4 : HEEEEEEE OOOOHHHHH\n",
    "\n",
    "J'ai trouvé une superbe musique pas très connue, mais je la trouve un peu plate... J'aimerai avoir un peu de reverbe dessus (de l'écho comme dans un grand batîment). Vous pouvez m'aider ?\n",
    "\n",
    "Chargez le fichier *audio.wav* et tracez le spectre audio."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2cd4530e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Chargement et affichage de l'extrait audio\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "afcb92b9",
   "metadata": {},
   "source": [
    "Pour créer de la reverb ici, on va utiliser ce qu'on a fait durant tout le TP : la convolution. Pour cela, on va utiliser une réponse impulsionnelle enregistrée dans un endroit avec de l'écho. Ici, on a le fichier *eglise.wav* qui est une réponse impulsionnelle enregistrée dans une église. Si vous êtes intéressé par d'autres réponses impulsionnelles, je vous conseille ce lien : https://www.openair.hosted.york.ac.uk/?page_id=36\n",
    "\n",
    "Chargez le fichier audio *eglise.wav* et tracez le spectre audio."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e565e6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Chargement et affichage de la réponse impulsionnelle\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17e6c02c",
   "metadata": {},
   "source": [
    "Avant de faire la convolution, on va convertir nos données, ici typées int16 (entiers codés sur 16 bits). \n",
    "\n",
    "Normalisez les données en :\n",
    "- convertissant les audios en float\n",
    "- divisant les audios par 32768"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3bc1e5a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Normalisation de l'extrait audio et de la réponse impulsionnelle\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ba97954",
   "metadata": {},
   "source": [
    "Calculez maintenant la convolution entre vos deux audios normalisés\n",
    "\n",
    "**Attention : utilisez np.convolve et ne multipliez pas par $T_e$. Sinon, ça ne marchera pas**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41d52a81",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Convolution de l'extrait audio normalisé et de la réponse impulsionnelle normalisée\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d14ff7e",
   "metadata": {},
   "source": [
    "Malgré la normalisation des extraits audios, la sortie de convolution peut créer des pics trop forts (ici au-dessus de 1). Corrigez l'audio :\n",
    "- Détectez s'il y a au moins un pic (en calculant le maximum)\n",
    "- S'il y'a un pic au-dessus de 1 (ou en-dessous de -1), normalisez l'audio en le divisant par le maximum et en multipliant par 0.999"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "109d3c79",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Correction de pics trop élevés par normalisation\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35f8f43b",
   "metadata": {},
   "source": [
    "Convertissez l'audio pour coller à celui d'origine. Pour cela :\n",
    "- Multipliez l'audio par 32768\n",
    "- Convertissez l'audio en entier 16 bits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e5a35abc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Conversion de l'audio en entier 16 bits\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2e141d2",
   "metadata": {},
   "source": [
    "Affichez le spectre audio du résultat. \n",
    "\n",
    "**Attention : quel est l'axe temporel ? Comment le retrouver ?**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ed45112a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Affichage du spectre d'audio résultat\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "720d4b2a",
   "metadata": {},
   "source": [
    "Pour finir, enregistrez l'audio et écoutez le résultat. Alors, qu'est-ce que ça donne ?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7748ddfd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Enregistrement du son final avec reverb\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf205ae6",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## La convolution au service de l'art\n",
    "\n",
    "Ici, juste un bonus, pas de code, mais c'est pour ceux qui sont curieux ;)\n",
    "\n",
    "Via l'exercice précédent, on a vu comment faire une reverb. Pour cela, on a enregistré une réponse impulsionnelle dans une église, ce qui a permis de créer notre signal reverb. Cependant, on peut aussi créer des réponses impulsionnelles via des objets du quotidien, comme par exemple un jouet à ressort : https://www.openair.hosted.york.ac.uk/?page_id=652\n",
    "\n",
    "De ce fait, on peut créer des sons très spéciaux, servant d'effet sonore au cinéma par exemple. Ces réponses impulsionnelles peuvent aussi être générées. On peut alors ainsi transformer un son à sa guise, créant ainsi de nouvelles sonorités uniques.\n",
    "\n",
    "Par exemple, la Loopstation RC-505 est un appareil permettant non seulement de créer des \"loops sonores\" (c'est-à-dire qu'on enregistre un son et il se répète indéfiniment), mais également de rajouter des effets sonores sur les audios durant l'enregistrement ou a posteriori. La machine a été designée particulèrement pour les artistes vocaux (chant, beatbox). Et tout ça à partir de convolution pour créer des sons originaux.\n",
    "\n",
    "Un extrait pour finir : 2 artistes beatbox en battle 1v1 qui utilisent la loopstation pour leurs morceaux avec uniquement leurs voix en entrée : https://youtu.be/niZJPoxiv40?si=Uo_hrlOj3iyLechd&t=74"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "TIM",
   "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
