{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "096609fe",
   "metadata": {},
   "source": [
    "# Traitement du Signal - TP7 : Transformée de Fourier Directe\n",
    "\n",
    "La transformée de Fourier, c'est bon, vous connaissez. Mais vous savez également qu'entre l'analogique et le numérique, il y'a de sacrés différences. Ici, on va reprendre le principe de transformée de Fourier, mais celle appliquée au numérique, à savoir la **transformée de Fourier discrète (TFD)**. On va d'abord commencer par la recoder, puis comprendre l'impact du paramétrage des signaux d'entrée sur le résultat en fréquentiel et inversement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e72cde10",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Import des librairies\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1273ded",
   "metadata": {},
   "source": [
    "## Exercice 1 : Codage"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc1e81e9",
   "metadata": {},
   "source": [
    "Avant de faire plein de transformées, on va d'abord coder la fonction. Pour rappel, la formule de la transformée de Fourier directe est :\n",
    "\n",
    "\\begin{equation*}\n",
    "    X[k]= \\sum_{n=0}^{N-1} x[n] e^{-j2π \\frac{k}{L} n}\n",
    "\\end{equation*}\n",
    "\n",
    "Avec :\n",
    "- $N$ : Le nombre de points temporels\n",
    "- $n$ : La variable temporelle $\\in [0, N-1]$\n",
    "- $L$ : Le nombre de points fréquentiels\n",
    "- $k$ : La variable fréquentielle $\\in [0, L-1]$\n",
    "\n",
    "Vous pouvez constater ici que la longueur du signal fréquentiel $L est distincte de la longueur du signal temporel $N$. Cela veut dire qu'on peut définir $L \\neq N$ (vous verrez l'utilité plus tard). On a alors 3 cas de figures:\n",
    "- $L=N$ : le plus simple, aucune modification n'est à apporter sur le signal d'entrée\n",
    "- $L<N$ : on coupe le signal d'entrée en ne gardant que les $L$ premières valeurs\n",
    "- $L>N$ : on agrandit le signal d'entrée en rajoutant des zéros à la fin, afin qu'il soit de taille $L$.\n",
    "\n",
    "Développez la fonction de transformée de Fourier directe, prenant donc en entrée le signal et $L$ la taille  du signal fréquentiel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68a51a0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction de transformée de Fourier directe (TFD)\n",
    "def TFD(...):\n",
    "    ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed7550a2",
   "metadata": {},
   "source": [
    "3 tests unitaires pour valider votre fonction:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "321dbc03",
   "metadata": {},
   "outputs": [],
   "source": [
    "rng = np.random.default_rng(0)\n",
    "x = rng.standard_normal(64) + 1j * rng.standard_normal(64)\n",
    "L = len(x)\n",
    "X_tfd = TFD(x, L)\n",
    "X_np = np.fft.fft(x, n=L)\n",
    "\n",
    "assert np.allclose(X_tfd, X_np), f\"Erreur pour L=N : \\\n",
    "                                    \\n Fonction NumPy (longueur {len(X_np)}) : {X_np}\\n \\\n",
    "                                    Votre fonction (longueur {len(X_tfd)}) : {X_tfd}\"\n",
    "\n",
    "L = 128\n",
    "X_tfd = TFD(x, L)\n",
    "X_np = np.fft.fft(x, n=L)\n",
    "\n",
    "assert np.allclose(X_tfd, X_np), f\"Erreur pour L>N : \\\n",
    "                                    \\n Fonction NumPy (longueur {len(X_np)}) : {X_np}\\n \\\n",
    "                                    Votre fonction (longueur {len(X_tfd)}) : {X_tfd}\"\n",
    "\n",
    "L = 32\n",
    "X_tfd = TFD(x, L)\n",
    "X_np = np.fft.fft(x, n=L)\n",
    "\n",
    "assert np.allclose(X_tfd, X_np), f\"Erreur pour L<N : \\\n",
    "                                    \\n Fonction NumPy (longueur {len(X_np)}) : {X_np}\\n \\\n",
    "                                    Votre fonction (longueur {len(X_tfd)}) : {X_tfd}\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f7f1d22",
   "metadata": {},
   "source": [
    "Avant de tester notre fonction, il nous faut aussi calculer l'axe fréquentiel (*np.fft.fftfreq*). Recodez la fonction fftfreq de NumPy, en vous aidant de la documentation : https://numpy.org/devdocs/reference/generated/numpy.fft.fftfreq.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4dc41fc6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction de calcul de l'axe fréquentiel (TFD_freq)\n",
    "def TFD_freq(...):\n",
    "    ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c53f2319",
   "metadata": {},
   "source": [
    "2 tests unitaires pour valider votre fonction:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4dca9eb9",
   "metadata": {},
   "outputs": [],
   "source": [
    "N = 50\n",
    "fe = 1000\n",
    "own_fftfreq = TFD_freq(N, 1/fe)\n",
    "np_fftfreq = np.fft.fftfreq(N, 1/fe)\n",
    "assert np.allclose(own_fftfreq, np_fftfreq), f\"Erreur pour N pair : \\\n",
    "                                            \\n Fonction NumPy (longueur {len(np_fftfreq)}) : {np_fftfreq}\\n \\\n",
    "                                            Votre fonction (longueur {len(own_fftfreq)}) : {own_fftfreq}\"\n",
    "\n",
    "N = 51\n",
    "fe = 2048\n",
    "own_fftfreq = TFD_freq(N, 1/fe)\n",
    "np_fftfreq = np.fft.fftfreq(N, 1/fe)\n",
    "assert np.allclose(own_fftfreq, np_fftfreq), f\"Erreur pour N impair : \\\n",
    "                                            \\n Fonction NumPy (longueur {len(np_fftfreq)}) : {np_fftfreq}\\n \\\n",
    "                                            Votre fonction (longueur {len(own_fftfreq)}) : {own_fftfreq}\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88e52855",
   "metadata": {},
   "source": [
    "Une dernière étape avant de tester sur un signal : il nous faut coder également *fftshift*, permettant de recentrer la transformée et l'axe fréquentiel pour que la fréquence 0 soit au centre. Développez la fonction en vous aidant de la documentation de la fonction : https://numpy.org/devdocs/reference/generated/numpy.fft.fftshift.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e346ad2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction de recentrage des fréquences (TFD_shift)\n",
    "def TFD_shift(...):\n",
    "    ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab6a350d",
   "metadata": {},
   "source": [
    "2 tests unitaires pour valider votre fonction:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b94c31d",
   "metadata": {},
   "outputs": [],
   "source": [
    "N = 50\n",
    "x = np.random.randint(0,100,size=(N))\n",
    "own_fftshift = TFD_shift(x)\n",
    "np_fftshift = np.fft.fftshift(x)\n",
    "assert (own_fftshift==np_fftshift).all(), f\"Erreur pour N pair : \\\n",
    "                                            \\n Fonction NumPy (longueur {len(np_fftshift)}) : {np_fftshift}\\n \\\n",
    "                                            Votre fonction (longueur {len(own_fftshift)}) : {own_fftshift}\"\n",
    "N = 51\n",
    "x = np.random.randint(0,100,size=(N))\n",
    "own_fftshift = TFD_shift(x)\n",
    "np_fftshift = np.fft.fftshift(x)\n",
    "assert (own_fftshift==np_fftshift).all(), f\"Erreur pour N impair : \\\n",
    "                                            \\n Fonction NumPy (longueur {len(np_fftshift)}) : {np_fftshift}\\n \\\n",
    "                                            Votre fonction (longueur {len(own_fftshift)}) : {own_fftshift}\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1bab856",
   "metadata": {},
   "source": [
    "On peut maintenant créer un signal, calculer sa TFD et afficher le spectre d'amplitude, comme lors du TP3 (exercice 2).\n",
    "\n",
    "Créez et affichez le signal suivant : \n",
    "\\begin{equation*}\n",
    "    s(t) = \\sin(2 \\pi f_{0} t)\n",
    "\\end{equation*}\n",
    "\n",
    "Avec $f_{0} = 50 Hz$. Le signal évoluera durant 0.1 seconde avec une fréquence d'échantillonage $f_e = 1000 Hz$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1be44cbd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création et affichage de s(t)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4998277",
   "metadata": {},
   "source": [
    "Calculez maintenant avec vos superbes fonctions la transformée de Fourier directe de $s(t)$, et affichez le spectre d'amplitude."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6df9acd7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Calcul de la TFD de s(t) et affichage du spectre d'amplitude\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54613115",
   "metadata": {},
   "source": [
    "Vous aimez coder ? *(\"OUI!\" répondent-ils tous en choeur)*, et bien on va coder les fonctions inverses maintenant !\n",
    "\n",
    "Commençons par la transformée de Fourier discrète inverse (ITFD). La formule est la suivante :\n",
    "\n",
    "\\begin{equation*}\n",
    "    x[n]= \\frac{1}{L} \\sum_{k=0}^{L-1} X[k] e^{j2π \\frac{k}{L} n}\n",
    "\\end{equation*}\n",
    "\n",
    "On a toujours nos 4 variables $N,n,L$ et $K$, mais cette fois-ci, c'est bien $N$, la longueur du signal temporel en sortie, qui doit être indiqué en paramètre d'entrée de la fonction. De la même manière que précédemment, on peut avoir $N \\neq L$, avec toujours 3 cas de figures:\n",
    "\n",
    "- $N=L$ : le plus simple, aucune modification n'est à apporter sur le signal d'entrée\n",
    "- $N<L$ : on coupe le signal d'entrée en ne gardant que les $N$ premières valeurs\n",
    "- $N>L$ : on agrandit le signal d'entrée en rajoutant des zéros à la fin, afin qu'il soit de taille $N$.\n",
    "\n",
    "A votre clavier ! Prêts ? Codez !"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9fbc261a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction de transformée de Fourier inverse directe (ITFD)\n",
    "def ITFD(...):\n",
    "    ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3f11f0f",
   "metadata": {},
   "source": [
    "3 tests unitaires pour valider votre fonction:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9b5b0be2",
   "metadata": {},
   "outputs": [],
   "source": [
    "rng = np.random.default_rng(0)\n",
    "X = rng.standard_normal(64) + 1j * rng.standard_normal(64)\n",
    "L = len(X)\n",
    "\n",
    "x_itfd = ITFD(X, L)\n",
    "x_np = np.fft.ifft(X, n=L)\n",
    "\n",
    "assert np.allclose(x_itfd, x_np), f\"Erreur pour N=L : \\\n",
    "                                    \\n Fonction NumPy (longueur {len(x_np)}) : {x_np}\\n \\\n",
    "                                    Votre fonction (longueur {len(x_itfd)}) : {x_itfd}\"\n",
    "\n",
    "L = 128\n",
    "x_itfd = ITFD(X, L)\n",
    "x_np = np.fft.ifft(X, n=L)\n",
    "\n",
    "assert np.allclose(x_itfd, x_np), f\"Erreur pour N<L (zero-pad) : \\\n",
    "                                    \\n Fonction NumPy (longueur {len(x_np)}) : {x_np}\\n \\\n",
    "                                    Votre fonction (longueur {len(x_itfd)}) : {x_itfd}\"\n",
    "\n",
    "X_long = rng.standard_normal(96) + 1j * rng.standard_normal(96)  # N = 96\n",
    "L = 32\n",
    "\n",
    "x_itfd = ITFD(X_long, L)\n",
    "x_np = np.fft.ifft(X_long, n=L)\n",
    "\n",
    "assert np.allclose(x_itfd, x_np), f\"Erreur pour N>L (troncature) : \\\n",
    "                                    \\n Fonction NumPy (longueur {len(x_np)}) : {x_np}\\n \\\n",
    "                                    Votre fonction (longueur {len(x_itfd)}) : {x_itfd}\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "932c9d2e",
   "metadata": {},
   "source": [
    "Et pour finir cette longue session de code, une dernière fonction à implémenter : l'inverse de *fftshift* (*iffshift*). Comme précédemment, je vous invite à aller voir la documentation pour vous aider dans le développement: https://numpy.org/doc/2.1/reference/generated/numpy.fft.ifftshift.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "deb3db5c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Fonction inverse de recentrage des fréquences (ITFD_shift)\n",
    "def ITFD_shift(...):\n",
    "    ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26b5f718",
   "metadata": {},
   "source": [
    "2 tests unitaires pour valider votre fonction:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d38aa9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "N = 50\n",
    "x = np.random.randint(0, 100, size=(N))\n",
    "own_ifftshift = ITFD_shift(x)\n",
    "np_ifftshift = np.fft.ifftshift(x)\n",
    "\n",
    "assert (own_ifftshift == np_ifftshift).all(), f\"Erreur pour N pair : \\\n",
    "                                            \\n Fonction NumPy (longueur {len(np_ifftshift)}) : {np_ifftshift}\\n \\\n",
    "                                            Votre fonction (longueur {len(own_ifftshift)}) : {own_ifftshift}\"\n",
    "\n",
    "N = 51\n",
    "x = np.random.randint(0, 100, size=(N))\n",
    "own_ifftshift = ITFD_shift(x)\n",
    "np_ifftshift = np.fft.ifftshift(x)\n",
    "\n",
    "assert (own_ifftshift == np_ifftshift).all(), f\"Erreur pour N impair : \\\n",
    "                                            \\n Fonction NumPy (longueur {len(np_ifftshift)}) : {np_ifftshift}\\n \\\n",
    "                                            Votre fonction (longueur {len(own_ifftshift)}) : {own_ifftshift}\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8116421c",
   "metadata": {},
   "source": [
    "Calculez maintenant vos fonction inverses pour recrée $s(t)$ à partir de $S(f)$, et affichez sur le même graphique la courbe d'origine et celle en sortie de transformée inverse."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "633ea53b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Transformée inverse de S(f) et affichage\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14c898b8",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Exercice 2 : La science réside dans les détails\n",
    "\n",
    "Si vous avez fini l'exercice 1, félicitations ! Pour la suite du TP, vous pouvez soit reprendre vos fonctions de l'exercice 1, soit utiliser celles de NumPy. \n",
    "\n",
    "Vous avez pu voir précédemment qu'on peut définir une taille différente pour le spectre fréquentiel ($L$ dans $fft$) et pour le signal temporel ($N$ pour *ifft*). On va donc maintenant regarder en détail l'utilité de ces paramètres."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8dae6c3",
   "metadata": {},
   "source": [
    "Créez le signal $x(t)$, toujours une sinusoïde mais de fréquence $12,5$ Hz. Le signal évoluera durant 1 secondes à une fréquence d'échantillonnage $f_e$ = 500 Hz."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3b2875ee",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création et affichage de x(t)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c46726d",
   "metadata": {},
   "source": [
    "Calculez maintenant la transformée de Fourier du signal et affichez le spectre d'amplitude."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "91dce36a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Calcul de la TFD de x(t) et affichage du spectre d'amplitude\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb72ba77",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que le spectre vous paraît correct ? Que constatez-vous ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc12cf8a",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb862983",
   "metadata": {},
   "source": [
    "Construisez maintenant le signal $y(t)$, qui exactement le signal $x(t)$ mais évoluant durant 1,04 secondes, affichez le signal et son spectre d'amplitude après TFD."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a3b1738c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création et affichage de y(t), et affichage du spectre d'amplitude de Y(f)\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cfbb466",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Que constatez-vous concernant le spectre d'amplitude de $Y(f)$ par rapport à celui de $X(f)$ ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3935c57",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e52cfc6e",
   "metadata": {},
   "source": [
    "Vous devriez donc avoir deux spectres différents alors que vous avez le même signal en entrée, à la seul différence que $y(t)$ évolue durant 1.04 secondes contre 1 secondes pour $x(t)$. On a ici un **problème de fuite spectale**. Le pas de votre axe fréquentiel que vous avez défini dépend de la durée de votre signal : \n",
    "\n",
    "\\begin{equation*}\n",
    "    \\Delta f = \\frac{1}{T} = \\frac{f_e}{L}\n",
    "\\end{equation*}\n",
    "\n",
    "Avec $T$ la durée du signal, et $L$ la taille du tableau représentant votre signal en fréquentiel.\n",
    "\n",
    "Dans le premier cas, votre pas fréquentiel est donc égal à 1 Hz, ce qui signifie que les fréquences détectées sont espacées de 1 Hz (0, 1, 2, 3, etc...). 12,5 Hz n'étant pas entier, il est normal qu'il ne soit pas détecté. Dans le deuxième cas, le pas fréquentiel tombe à environ 0.96 Hz. La fréquence de 12.5 Hz tombe pile sur l'un des bins de l'axe fréquentiel.\n",
    "\n",
    "Plus généralement, dans le cas d'un signal périodique (comme ici), on évite une fuite spectrale lorsque le signal évolue durant un nombre entier $P$ de périodes complètes. Dans le premier cas, on peut voir que le signal évolue sur 12 périodes complètes, et une 13ème incomplète. En revanche, le signal $y(t)$ évolue lui durant 13 périodes complètes.\n",
    "\n",
    "Ici, notre signal peut être définit sur autant de temps qu'on le veut puisqu'il est stable. Cependant, pour la majorité des signaux à analyser, on ne peut leurs évolutions. De ce fait, on peut alors **allonger** le signal avec un zero-padding, ce que fait la fonction *fft*.\n",
    "\n",
    "Recalculez *X(f)* en précisant la taille de sortie de l'axe fréquentiel. Pour cela, calculez le nombre de points nécessaires pour garantir un nombre entier de périodes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59f695e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Transformée de Fourier de x(t) en précisant la taille du spectre fréquentiel \n",
    "# afin de garantir un nombre entier de périodes\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64adc0bb",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que la transformée de Fourier obtenue est meilleure ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ff16c4e",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5af50826",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Pourquoi la TF obtenue n'est pas totalement parfaite ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c259a137",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8daf8d48",
   "metadata": {},
   "source": [
    "En effet, agrandir le vecteur temporel avec un zero-padding ne corrige pas une fuite spectrale. \n",
    "\n",
    "Concrètement, l'utilité du zero-padding avant une FFT sert avant tout à augmenter le nombre de points en fréquentiels, et ainsi améliorer la résolution fréquentielle $\\Delta f$. Cela permet de mieux analyser les composantes du signal. De plus, sans rentrer dans les détails de calcul, la FFT est d'autant plus efficace à calculer lorsque $N = 2^{k}$ avec $k \\in \\N$. \n",
    "\n",
    "Pour corriger une fuite spectrale, il est préférable de fenêtrer le signal par multiplication avec une fenêtre de Hann, ou une fenêtre de Hamming par exemple. ces fenêtres servent à adoucir les bords d’un signal fini avant une FFT, afin de réduire les discontinuités périodiques. \n",
    "\n",
    "On va appliquer une fenêtre de Hann dans un premier temps sur $x(t)$ via la fonction *np.hanning*. Calculer $h(t)$, la fenêtre de Hann, et $w(t) = x(t) \\times h(t)$. Affichez ensuite les courbes $x(t)$, $h(t)$ et $w(t)$ dans 3 graphes différents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d5e0ed78",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Création de w(t), le fenêtrage de x(t) par h(t), une fenêtre de Hann, et affichage des 3 courbes\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b0cc160",
   "metadata": {},
   "source": [
    "Si vous avez bien réalisez le fenêtrage, vous pouvez constater que $w(t)$ a une fréquence similaire que $x(t)$, avec les bords adoucis. Cependant, l'énergie globale du signal est inévitablement plus faible que l'original.\n",
    "\n",
    "On va maintenant calculer la transformée de Fourier de $w(t)$. Pour compenser la perte d'énergie causée par le fenêtrage, il faut ensuite diviser $W(f)$ par le gain moyen de $h(t)$ (à savoir la moyenne de $h(t)$).\n",
    "\n",
    "Affichez le spectre d'amplitude de $W(f)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63b6ae6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Calcul de la TFD de w(t) et affichage du spectre d'amplitude\n",
    "..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4d919bf",
   "metadata": {},
   "source": [
    "**_QUESTION :_** Est-ce que le fenêtrage de Hann améliore le spectre d'amplitude ?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf9a4463",
   "metadata": {},
   "source": [
    "**_REPONSE :_**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d25cf7e",
   "metadata": {},
   "source": [
    "Réalisez les opérations précédentes, mais en appliquant un fenêtrage de Hamming (*np.hamming*), et un fenêtrage de Blackman (*np.blackman*)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01b0c378",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Mêmes opérations que précédemment mais avec une fenêtre de Hamming\n",
    "..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f0d5181c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A COMPLETER\n",
    "# Mêmes opérations que précédemment mais avec une fenêtre de Blackman\n",
    "..."
   ]
  }
 ],
 "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
}
