{ "cells": [ { "cell_type": "markdown", "id": "turned-vector", "metadata": {}, "source": [ "# TD1 exo 1 sur le TFSD (Sujet Python)\n", "\n", "Exécution interactive en ligne ici [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/balaise31/Signal/master?labpath=discret%2Ftd%2FFREQ_code%2Fexo1_tfsd.ipynb)\n", "\n", "| | Sujet | Corrigé |\n", "|--------|-------|---------|\n", "|Python | [sujet python](./exo1_tfsd.ipynb) | [corrigé python](./exo1_tfsd_corr.ipynb) |\n", "|Octave | [sujet octave](./exo1_tfsd_octave.ipynb) | [corrigé octave](./exo1_tfsd_corr_octave.ipynb) |\n", "\n", "\n", "\n", "Retour au [sujet de TD papier](../FREQ_sujet.ipynb)\n", "\n" ] }, { "cell_type": "markdown", "id": "33268cc1-8917-4167-bcd0-b276843dd560", "metadata": { "tags": [] }, "source": [ "\n", "L'axe des temps est discret donc facilement représentable avec $t=k\\,Te$, il suffit de créer un vecteur du temps discret $k$ de -5 à 5 par exemple et de calculer le vecteur temps $t$ qui y correspond (utile pour l'affichage)\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "interested-costs", "metadata": {}, "outputs": [], "source": [ "import numpy as np # tout pour le numerique, matriciel etc.\n", "Fe=0.1\n", "Te = 1/Fe\n", "\n", "## VOTRE CODE calculant k de -5 à 5: utilisez np.arange(dep,step,fin) pas de boucle\n", "# Attention np.arange(a,b) donne le segment SEMI-OUVERT [a, b[\n", "# pour obtenir de l'aide sur une fonction ajoutez ? à la fin...\n", "\n", "\n", "##VOTRE CODE calculant t : le produit entre scalaire et vecteur existe en math\n", "# donc aussi en python\n", "\n", "\n", "## SHIFT + ENTER pour exécuter la cellule de code.\n", "# pour afficher on fait avec print\n", "print(t)\n", "print(f\"k = {k} échantillons de {Te} secondes\")" ] }, { "cell_type": "markdown", "id": "protected-purse", "metadata": {}, "source": [ "Dans la TFSD les fréquences sont continues entre 0 et $F_e$ et impossible à stocker dans un ordinateur.\n", "On s'en rapproche avec une résolution très fine $\\Delta_f=0.001$ 𝐻𝑧 (par exemple) comparée à la fréquence d'échantillonnage 𝐹𝑒=1 arbitraire. \n", "\n", "On peut choisir d'échantillonner en fréquence avec 1000 points entre 0 et $F_e$ et en déduire la résolution $\\Delta_f=\\frac{F_e}{1000}$. On peut calculer **inutilement** la TFSD pour des fréquences au-delà de $F_e$ pour vérifier la périodicité du spêctre. " ] }, { "cell_type": "code", "execution_count": null, "id": "other-pickup", "metadata": {}, "outputs": [], "source": [ "Df= Fe/1000 #résolution fine\n", "\n", "## VOTRE CODE: f=\n", "# déclarant le vecteur f de -2.Fe à 2.Fe par pas de Df\n", "\n", "## VOTRE CODE: N = \n", "# utilisez la fonction 'len' pour calculer le nombre N\n", "# de points du vecteur f \n", "\n", "# une commande magique de jupyter (ce n'est pas du python) permet de voir les variables\n", "%whos" ] }, { "cell_type": "markdown", "id": "defined-joint", "metadata": {}, "source": [ "On définit la fonction impulsion unité $\\delta_0[k] = 1$ uniquement si $k=0$, elle joue le même rôle que l'impulsion de Dirac. \n", "\n", "Pour cela on aurait pu faire une fonction :\n", "``` python\n", "def delta(k):\n", " if k == 0: \n", " val= 1.\n", " else :\n", " val = 0.\n", " \n", " return val\n", "``` \n", "Attention, ici k ne peut être qu'un scalaire. Si l'on veut \n", "La fonction deviendrait \n", "``` python\n", "def delta(k):\n", " return np.array(k==0, dtype=float)\n", "``` \n", "Ainsi la liste de booléen `k==0` est transformé en tableau numpy `np.array` dont les éléments sont convertis en float grâce à `dtype=float`\n", "\n", "Si la fonction tient en une ligne alors on profite des fonctions anonymes. Par exemple f = x^2 -3 deviendrait\n", "``` python\n", " f = lambda x : x^2 -3\n", "``` \n", "Cette fonction est vectorisée et donc ```f(1:10)``` retourne bien un vecteur de la fonction évaluée en 10 points.\n", "\n", "Déclarez delta et affichez-la :" ] }, { "cell_type": "code", "execution_count": null, "id": "designing-ranking", "metadata": {}, "outputs": [], "source": [ "## VOTRE CODE : delta = \n", "# déclarant la fonction k |---> delta[k]\n", "\n", "## VOTRE CODE : x0 = \n", "# stockez dans un vecteur x0 la valeur de delta \n", "# calculée pour toute les valeur du vecteur k (pas de boucle !)\n", "\n", "l=2;\n", "## VOTRE CODE : xl = \n", "# |__c'est un l minuscule pas un 1 ! \n", "# le vecteur des valeurs de delta[k-l]\n", "\n", "\n", "# On affiche vos signaux \n", "print(f\" k = \\t {k}\")\n", "print(f\"x0 = \\t {x0}\") \n", "print(np.block([[k], #première ligne contient k\n", " [x0] #deuxième x0\n", " ] \n", " )) " ] }, { "cell_type": "markdown", "id": "b2780a60-ac34-42bb-a485-a49dd59d92b8", "metadata": {}, "source": [ "On va utiliser les fonctions d'affichage `stem` et `plot` pour représenter ces signaux.\n", "Pour accéder à de l'aide et tester des commandes : utilisez la console.\n", "\n", "> **Ouvrez une console** :\n", "> File→New→Console (onglet) ou File→New console for notebook (console en bas) \n", "> Choisissez le kernel (octave ici)\n", "\n", "Exécutez la ligne `from matplotlib.pyplot import stem` de la cellule ci-dessoys pour importer la librairie.\n", "Puis **dans la console** obtenez de l'aide en faisant `stem?`" ] }, { "cell_type": "code", "execution_count": null, "id": "6d089325-24c9-4118-8770-960d1fd5545f", "metadata": {}, "outputs": [], "source": [ "from matplotlib.pyplot import stem, show\n", "## OUVREZ une console et exécutez `stem?` APRES avoir exécutez la ligne ci-dessus\n", "# vous pouvez mettre au point vos ligne de commande dans la console \n", "# avant de mettre la bonne version ici.\n", "\n", "## VOTRE CODE : stem(...)\n", "# affichant les deux signaux\n", "\n", "\n", "\n", "# changez le style d'affichage 'lineformat=\"r--\"' rouge avec tirets 'sk' des 'Squares' en blacK..\n", "\n", "show()" ] }, { "cell_type": "markdown", "id": "a3b5e1d6-2846-4861-9872-c90dbe3064a2", "metadata": {}, "source": [ "Par défaut Jupyter fait un affichage avec une image fixe en ligne des figures venant de matplotlib lorsque la commande `show()` est exécutée. \n", "\n", "Le comportement peut être modifié par des *commandes magiques* comme\n", "```\n", "%matplotlib tk #affiche fenêtre interractive (exécution locale) \n", "%matplotlib inline #affiche une image fixe dans le notebook\n", "```\n", "\n", "Exécutez la commande `%matplotlib tk` la console et relancez la cellule précédente pour voir l'effet" ] }, { "cell_type": "markdown", "id": "common-rugby", "metadata": {}, "source": [ "Il suffit ensuite de faire un script TFSD qui fait le calcul pour chaque fréquence contenue dans le vecteur f (supposé être continu de 0 à Fe) avec tous les instants contenu dans k (qui est bien un vecteur d'entiers, mais supposé être infini...)\n", "\n", "C'est déjà fait ! \n", "Faites `help tfsd` dans la console et jetez un œil au script [tfsd](tfsd.m) qui ressemble beaucoup aux scripts de deuxieme année.\n", "\n", "Pour les affichages à gauche temporel, à droite fréquentiel, en haut partie réelle et en bas partie imaginaire, je vous ai fait la fonction [plot_dual](plot_dual.m).\n", "\n", "À vous de mettre les bonnes légendes avec les bonnes sunités." ] }, { "cell_type": "code", "execution_count": null, "id": "accredited-business", "metadata": {}, "outputs": [], "source": [ "from tfsd import tfsd, plot_dual\n", "\n", "## VOTRE CODE tfsd_x0 =\n", "# appelle la fonction tfsd avec le signal x0 \n", "# pour obtenir de spoints de la tfsd de x0 pour toutes valeur de f\n", "\n", "## VOTRE CODE tfsd_xl= \n", "\n", "\n", "# gros affichage à faire en interactif en local\n", "%matplotlib tk \n", "## COMPLETEZ les ? : l'appel de plot dual pour indiquer les unités\n", "plot_dual(xs=[[k,k], [f,f]],\n", " ys=[[x0,xl], [tfsd_x0,tfsd_xl]],\n", " legendes=[\"impulsion 0\",\"impulsion en 2\"],\n", " labelx=[\"Unite temps ?\",\"Unite frequence ?\"],\n", " labely=[\"Unites Ordonnees Primal ?\", \"Unites Ordonnees Dual ?\"],\n", " est_discret=[True, False]\n", " )\n", "show()" ] }, { "cell_type": "markdown", "id": "distributed-senator", "metadata": {}, "source": [ "On a donc bien tfsd$[\\delta_0][n]= 1$ et tfsd$[\\delta_2][n]= e^{-i\\,2\\pi\\,f\\;2T_e}$\n", "\n", "On peut vérifier autrement qu'à l'œil, en calculant l'énergie de l'erreur entre le calcul et la formule :" ] }, { "cell_type": "code", "execution_count": null, "id": "light-shock", "metadata": {}, "outputs": [], "source": [ "from numpy import exp, pi # évite les np.exp et np.pi \n", "\n", "# On calcule exp(-i.2.pi.f.l.Te) pour toutes valeur de f\n", "tfsd_xl_theorique = exp(1j*2*pi*f*l*Te)\n", "\n", "# on calcule le vecteur d'erreur entre calcul numérique \n", "# et formule théorique\n", "erreur = tfsd_xl - tfsd_xl_theorique\n", "\n", "# on calcule la norme au carré de l'erreur \n", "# ||erreur||^2 = <>\n", "norme_carre_erreur = erreur.T * erreur # M.T donne \"la transposée de M\" \n", "norme_carre_erreur.shape\n" ] }, { "cell_type": "markdown", "id": "tough-andrews", "metadata": {}, "source": [ "Et oui ! Les opérateurs avec python et numpy sont des **opérateurs élément par élément**, même pour des tableaux `np.ndarray`. Ici nous avons les 4000 éléments de erreur multipliés à eux-mêmes. On pourrait l'avoir avec `erreur**2` aussi.\n", "\n", "On peut demander un **produit matriciel avec `@`** au lieu de `*` et s'assurer que même **les vecteurs lignes sont 2D avec `.reshape(-1,1)`** \n", "\n", "> `v=v.reshape(1,N)` fait passer v de 1D de taille (N,) à un vecteur 2D ligne de taille (1,N) \n", "> `v=v.reshape(N,1)` fait passer v de 1D de taille (N,) à un vecteur 2D colonne de taille (N,1) \n", "> si l'on ne veut pas s'embêter à trouver N on met -1 pour dire \"débrouilles toi mais cela doit rentrer\" \n", "> **`v = v.reshape(1,-1)` fait passer en 2D ligne** \n", "> **`v = v.reshape(-1,1)` fait passer en 2D colonne** \n" ] }, { "cell_type": "code", "execution_count": null, "id": "71ab5e54-e826-49a5-99bb-b846ab15fd3e", "metadata": {}, "outputs": [], "source": [ "err=np.matrix(erreur)\n", "print(f\" dimension de \\t err \\t\\t de type np.matrix = \\t{err.shape}\")\n", "print(f\" dimension de \\t err.T * err \\t de type matrix = \\t{(err.T*err).shape}\\n\")\n", "# err * err # ce produit donne une erreur car (1,n) x (1,n)\n", "print(f\" dimension de \\t erreur \\t\\t de type np.ndarray = \\t{erreur.shape}\")\n", "print(f\" dimension de \\t erreur.T * erreur \\t de type ndarray = \\t{(erreur.T*erreur).shape}\")\n" ] }, { "cell_type": "markdown", "id": "60084f6e-fa86-4c3e-a0e8-03d618c3811b", "metadata": {}, "source": [ "Remarquez que la taille est :\n", " * (4000,) pour un `ndarray 1D` (tableau 1D) et \n", " * (4000,1) pour une `ndarray 2D` (tableau 2D, mais colonne) obtenu avec `.reshape(-1,1)`\n", " \n", "Utilisez des matrices 2D (et donc le vecteur err) et le produit matriciel `@` pour obtenir le produit scalaire qui comme le dit son nom doit être de dimension scalaire = (1,1) " ] }, { "cell_type": "code", "execution_count": null, "id": "impaired-offense", "metadata": { "scrolled": true }, "outputs": [], "source": [ "## VOTRE CODE : norme_carre_erreur =\n", "# corrigeant l'erreur de dimension des vecteurs\n", "\n", "\n", "\n", "print(f\"{norme_carre_erreur} de taille {norme_carre_erreur.shape}\")" ] }, { "cell_type": "markdown", "id": "3ba6c49e-edb3-49c5-92af-e886496b20f8", "metadata": {}, "source": [ "La norme de l'erreur est réelle certe mais **n'est pas positive** !\n", "\n", "Et oui, avec une fonction complexe on a un presque scalaire dit Hilbertien.\n", "\n", "Pour avoir une norme positive on utilise la transposée de Hilbert ou conjugué de Hilbert :\n", "$M^H = \\overline{{}^T\\!M} = {}^T\\!\\overline{M}$ \n", "\n", "Corrigez encore en utilant soit `.T` et `.conj()`, ou en définissant H(M) = M.T.conj() avec une fonction lambda ! \n", "\n", "On peut aussi déclarer une fonction lambda \"scal(u, v)\" de deux arguments vecteurs ligne avec\n", "`scal = lambda u,v : ` ..." ] }, { "cell_type": "code", "execution_count": 10, "id": "1847237a-0f95-4627-b5cf-db2cfd5e76bf", "metadata": {}, "outputs": [], "source": [ "# VOTRE CODE: norme_carre_erreur =\n", "# la norme doit être positive\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "id": "82b99f14-6588-4406-b8ab-c867d8050b9a", "metadata": {}, "source": [ "La norme est positive, mais vaut 8000 et donc pas nulle !\n", "\n", "> J'ai mis une erreur bêêêêêête dans l'un des deux signaux (la norme doit être bonne maintenant) \n", "> Affichez les deux signaux `tfsd_xl` et `tfsd_xl_theorique` pour voir qui est faux et quelle erreur bête " ] }, { "cell_type": "code", "execution_count": 11, "id": "6a2f2a81-db97-430a-aae5-be7f755af1dd", "metadata": {}, "outputs": [], "source": [ "from matplotlib.pyplot import subplot, plot, title, legend\n", "from numpy import real, imag\n", "\n", "%matplotlib inline\n", "## VOTRE CODE : affichant le signal \n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "id": "c049c394-2d66-45e5-afa4-8ebb6297831f", "metadata": {}, "source": [ "On corrige : on voit que la partie imaginaire est opposée (impaire)....\n", "\n", ">On a donc un résultat qui est le conjugué de l'autre \n", ">ça sent l'erreur de signe dans une exponentielle !" ] }, { "cell_type": "code", "execution_count": null, "id": "0706ed44-0e17-46c7-a962-cd0500971d64", "metadata": {}, "outputs": [], "source": [ "## VOTRE CODE : corrigeant l'erreur et recalculant\n", "\n", "\n", "\n", "\n", "print(norme_carre_erreur)" ] }, { "cell_type": "markdown", "id": "de7f3ae2-69c4-4c57-9af2-9058a582174e", "metadata": {}, "source": [ "Ouf on est bon ! \n", "\n", "On peut **regarder le corrigé** pour voir les différences de style et différents langages\n", " - [exo1 tfsd corrigé python](exo1_tfsd_corr.ipynb)\n", " - [exo1 tfsd corrigé octave](exo1_tfsd_corr_octave.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.6" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false } }, "nbformat": 4, "nbformat_minor": 5 }