{ "cells": [ { "cell_type": "markdown", "id": "f5dd1112-4bbb-4209-8a00-6b17c82b9660", "metadata": {}, "source": [ "# G: Control de dispositivos serie (o USB-serie): GPS\n", "\n", "Para ejecutar este `notebook` necesitaremos instalar algunos paquetes (y poseer el hardware del que se habla!):\n", "\n", "```\n", " > conda install -c conda-forge tabulate\n", "\n", " > conda install -c anaconda pyserial\n", " \n", " > conda install -c anaconda pyaudio\n", "```" ] }, { "cell_type": "markdown", "id": "1e1621a8-538b-4961-9006-d9a979a7c8cb", "metadata": {}, "source": [ "Usaremos la biblioteca `pySerial` ([documentación](https://pyserial.readthedocs.io/en/latest/pyserial.html)) para leer de un modulo receptor de GPS USB como el de la imagen. Dichos aparatos, que se pueden comprar muy baratos (menos de 10€).\n", "\n", "![](ficherosAuxiliares/moduloGPS.jpg)\n", "\n", "Un puerto serie se maneja de manera muy similar a como funcionan los archivos normales. Podemos leer de ellos y escribir en ellos.\n", "\n", "En un sistema UNIX este tipo de dispositivos crean en el sistema de archivos un fichero con una ruta similar a `/dev/ttyUSBx` o `/dev/ttyACMx` donde `x` puede variar. Por tanto una vez conectado el dispositivo podemos listar los ficheros de dicho directorio para ver si aparece ese puerto:" ] }, { "cell_type": "code", "execution_count": 1, "id": "842a67dc-82d7-4cde-9826-9a75c9aae686", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[0m\u001b[40;33;01m/dev/tty\u001b[0m \u001b[40;33;01m/dev/tty23\u001b[0m \u001b[40;33;01m/dev/tty39\u001b[0m \u001b[40;33;01m/dev/tty54\u001b[0m \u001b[40;33;01m/dev/ttyS1\u001b[0m \u001b[40;33;01m/dev/ttyS25\u001b[0m\n", "\u001b[40;33;01m/dev/tty0\u001b[0m \u001b[40;33;01m/dev/tty24\u001b[0m \u001b[40;33;01m/dev/tty4\u001b[0m \u001b[40;33;01m/dev/tty55\u001b[0m \u001b[40;33;01m/dev/ttyS10\u001b[0m \u001b[40;33;01m/dev/ttyS26\u001b[0m\n", "\u001b[40;33;01m/dev/tty1\u001b[0m \u001b[40;33;01m/dev/tty25\u001b[0m \u001b[40;33;01m/dev/tty40\u001b[0m \u001b[40;33;01m/dev/tty56\u001b[0m \u001b[40;33;01m/dev/ttyS11\u001b[0m \u001b[40;33;01m/dev/ttyS27\u001b[0m\n", "\u001b[40;33;01m/dev/tty10\u001b[0m \u001b[40;33;01m/dev/tty26\u001b[0m \u001b[40;33;01m/dev/tty41\u001b[0m \u001b[40;33;01m/dev/tty57\u001b[0m \u001b[40;33;01m/dev/ttyS12\u001b[0m \u001b[40;33;01m/dev/ttyS28\u001b[0m\n", "\u001b[40;33;01m/dev/tty11\u001b[0m \u001b[40;33;01m/dev/tty27\u001b[0m \u001b[40;33;01m/dev/tty42\u001b[0m \u001b[40;33;01m/dev/tty58\u001b[0m \u001b[40;33;01m/dev/ttyS13\u001b[0m \u001b[40;33;01m/dev/ttyS29\u001b[0m\n", "\u001b[40;33;01m/dev/tty12\u001b[0m \u001b[40;33;01m/dev/tty28\u001b[0m \u001b[40;33;01m/dev/tty43\u001b[0m \u001b[40;33;01m/dev/tty59\u001b[0m \u001b[40;33;01m/dev/ttyS14\u001b[0m \u001b[40;33;01m/dev/ttyS3\u001b[0m\n", "\u001b[40;33;01m/dev/tty13\u001b[0m \u001b[40;33;01m/dev/tty29\u001b[0m \u001b[40;33;01m/dev/tty44\u001b[0m \u001b[40;33;01m/dev/tty6\u001b[0m \u001b[40;33;01m/dev/ttyS15\u001b[0m \u001b[40;33;01m/dev/ttyS30\u001b[0m\n", "\u001b[40;33;01m/dev/tty14\u001b[0m \u001b[40;33;01m/dev/tty3\u001b[0m \u001b[40;33;01m/dev/tty45\u001b[0m \u001b[40;33;01m/dev/tty60\u001b[0m \u001b[40;33;01m/dev/ttyS16\u001b[0m \u001b[40;33;01m/dev/ttyS31\u001b[0m\n", "\u001b[40;33;01m/dev/tty15\u001b[0m \u001b[40;33;01m/dev/tty30\u001b[0m \u001b[40;33;01m/dev/tty46\u001b[0m \u001b[40;33;01m/dev/tty61\u001b[0m \u001b[40;33;01m/dev/ttyS17\u001b[0m \u001b[40;33;01m/dev/ttyS4\u001b[0m\n", "\u001b[40;33;01m/dev/tty16\u001b[0m \u001b[40;33;01m/dev/tty31\u001b[0m \u001b[40;33;01m/dev/tty47\u001b[0m \u001b[40;33;01m/dev/tty62\u001b[0m \u001b[40;33;01m/dev/ttyS18\u001b[0m \u001b[40;33;01m/dev/ttyS5\u001b[0m\n", "\u001b[40;33;01m/dev/tty17\u001b[0m \u001b[40;33;01m/dev/tty32\u001b[0m \u001b[40;33;01m/dev/tty48\u001b[0m \u001b[40;33;01m/dev/tty63\u001b[0m \u001b[40;33;01m/dev/ttyS19\u001b[0m \u001b[40;33;01m/dev/ttyS6\u001b[0m\n", "\u001b[40;33;01m/dev/tty18\u001b[0m \u001b[40;33;01m/dev/tty33\u001b[0m \u001b[40;33;01m/dev/tty49\u001b[0m \u001b[40;33;01m/dev/tty7\u001b[0m \u001b[40;33;01m/dev/ttyS2\u001b[0m \u001b[40;33;01m/dev/ttyS7\u001b[0m\n", "\u001b[40;33;01m/dev/tty19\u001b[0m \u001b[40;33;01m/dev/tty34\u001b[0m \u001b[40;33;01m/dev/tty5\u001b[0m \u001b[40;33;01m/dev/tty8\u001b[0m \u001b[40;33;01m/dev/ttyS20\u001b[0m \u001b[40;33;01m/dev/ttyS8\u001b[0m\n", "\u001b[40;33;01m/dev/tty2\u001b[0m \u001b[40;33;01m/dev/tty35\u001b[0m \u001b[40;33;01m/dev/tty50\u001b[0m \u001b[40;33;01m/dev/tty9\u001b[0m \u001b[40;33;01m/dev/ttyS21\u001b[0m \u001b[40;33;01m/dev/ttyS9\u001b[0m\n", "\u001b[40;33;01m/dev/tty20\u001b[0m \u001b[40;33;01m/dev/tty36\u001b[0m \u001b[40;33;01m/dev/tty51\u001b[0m \u001b[40;33;01m/dev/ttyACM0\u001b[0m \u001b[40;33;01m/dev/ttyS22\u001b[0m\n", "\u001b[40;33;01m/dev/tty21\u001b[0m \u001b[40;33;01m/dev/tty37\u001b[0m \u001b[40;33;01m/dev/tty52\u001b[0m \u001b[40;33;01m/dev/ttyprintk\u001b[0m \u001b[40;33;01m/dev/ttyS23\u001b[0m\n", "\u001b[40;33;01m/dev/tty22\u001b[0m \u001b[40;33;01m/dev/tty38\u001b[0m \u001b[40;33;01m/dev/tty53\u001b[0m \u001b[40;33;01m/dev/ttyS0\u001b[0m \u001b[40;33;01m/dev/ttyS24\u001b[0m\n" ] } ], "source": [ "ls /dev/tty*" ] }, { "cell_type": "markdown", "id": "59293fe4-b9a2-4b36-b6b1-983e47fe4235", "metadata": {}, "source": [ "Estos dispositivos usualmente usan el protocolo [NMEA](https://es.wikipedia.org/wiki/NMEA_0183). Podemos encontrar una descripción más detallada del mismo en [este PDF](https://www.sparkfun.com/datasheets/GPS/NMEA%20Reference%20Manual-Rev2.1-Dec07.pdf).\n", "\n", "Lo más básico que podemos hacer es abrir el puerto serie e ir leyendo los mensajes que nos envía el receptor:\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "c453df98-4975-448c-b9f7-d02e46104e11", "metadata": {}, "outputs": [], "source": [ "pathSerie = '/dev/ttyACM0'" ] }, { "cell_type": "code", "execution_count": 3, "id": "4e128ec9-cba4-4769-bf72-9be5bfd105fe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'$GPRMC,231249.00,V,,,,,,,,,,N*72\\r\\n'\n", "b'$GPVTG,,,,,,,,,N*30\\r\\n'\n", "b'$GPGGA,231249.00,,,,,0,00,99.99,,,,,,*69\\r\\n'\n", "b'$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30\\r\\n'\n", "b'$GPGSV,2,1,05,02,,,36,03,,,31,06,,,37,11,,,42*7D\\r\\n'\n", "b'$GPGSV,2,2,05,20,,,33*7E\\r\\n'\n", "b'$GPGLL,,,,,231249.00,V,N*45\\r\\n'\n", "b'$GPTXT,01,01,02,u-blox ag - www.u-blox.com*50\\r\\n'\n", "b'$GPTXT,01,01,02,HW UBX-G70xx 00070000 FF7FFFFFo*69\\r\\n'\n", "b'$GPTXT,01,01,02,ROM CORE 1.00 (59842) Jun 27 2012 17:43:52*59\\r\\n'\n", "b'$GPTXT,01,01,02,PROTVER 14.00*1E\\r\\n'\n", "b'$GPTXT,01,01,02,ANTSUPERV=AC SD PDoS SR*20\\r\\n'\n", "b'$GPTXT,01,01,02,ANTSTATUS=OK*3B\\r\\n'\n", "b'$GPTXT,01,01,02,LLC FFFFFFFF-FFFFFFFF-FFFFFFFF-FFFFFFFF-FFFFFFFD*2C\\r\\n'\n", "b'$GPRMC,231250.00,V,,,,,,,,,,N*7A\\r\\n'\n", "b'$GPVTG,,,,,,,,,N*30\\r\\n'\n", "b'$GPGGA,231250.00,,,,,0,00,99.99,,,,,,*61\\r\\n'\n", "b'$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30\\r\\n'\n", "b'$GPGSV,2,1,05,02,,,36,03,,,30,06,,,37,11,,,42*7C\\r\\n'\n", "b'$GPGSV,2,2,05,20,,,34*79\\r\\n'\n", "b'$GPGLL,,,,,231250.00,V,N*4D\\r\\n'\n", "b'$GPRMC,231251.00,V,,,,,,,,,,N*7B\\r\\n'\n", "b'$GPVTG,,,,,,,,,N*30\\r\\n'\n", "b'$GPGGA,231251.00,,,,,0,00,99.99,,,,,,*60\\r\\n'\n", "b'$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30\\r\\n'\n", "b'$GPGSV,2,1,05,02,,,36,03,,,30,06,,,37,11,,,42*7C\\r\\n'\n", "b'$GPGSV,2,2,05,20,,,34*79\\r\\n'\n", "b'$GPGLL,,,,,231251.00,V,N*4C\\r\\n'\n", "Fin ejecución\n" ] } ], "source": [ "import serial\n", "from IPython.display import display, clear_output, HTML\n", "\n", "ser = serial.Serial(pathSerie, 9600) # Abrimos el puerto a una velocidad de 9600 baudios (típico en estos dispositivos)\n", "\n", "try: \n", " while True: # Bucle infinito. Seguramente querrás pararlo en algún momento\n", " data = ser.readline()\n", "\n", " if data:\n", " print(data)\n", "except KeyboardInterrupt:\n", " print(\"Fin ejecución\")" ] }, { "cell_type": "markdown", "id": "4d904c55-03a2-464a-a6c2-c21e00166574", "metadata": {}, "source": [ "Vamos a crear unas pocas clases y funciones para mejorar la salida de información:" ] }, { "cell_type": "code", "execution_count": 4, "id": "1d39f0d3-1b89-4c63-870b-f527ebb90690", "metadata": {}, "outputs": [], "source": [ "import tabulate\n", "import serial\n", "from IPython import display\n", "import time\n", "\n", "lastGPRMC = \"\" # Último mensaje de tipo GPRMC codificado como tabla bonita\n", "lastGPGSV = \"\" # Último mensaje de tipo GPSVC codificado como tabla bonita\n", "lastDate = \"\" # Última fecha recibida del GPS\n", "lastTime = \"\" # Última hora recibida del GPS\n", "\n", "class printer(str): # Clase auxiliar para imprimir las tablas de datos\n", " def __repr__(self):\n", " return self\n", "\n", "def parseNMEA(line): # Analiza una línea de mensaje del protocolo NMEA\n", " if line.startswith(\"$GPRMC\"):\n", " parseNMEA_RMC(line)\n", " \n", " if line.startswith(\"$GPGSV\"):\n", " parseNMEA_GSV(line)\n", "\n", "def parseNMEA_RMC(line): # Analiza una línea NMEA de tipo RMC y almacena su información en una tabla bonita. \n", " # Tb actualiza la última hora y fecha recibidas \n", " global lastGPRMC\n", " global lastDate\n", " global lastTime\n", " \n", " split = line.split(\",\")\n", " \n", " tableD = [[\"RMC\", \"UTC Time\", \"Latitude\", \"Longitude\", \"Date\"],\n", " [\"\", split[1], split[3] + split[4], split[5] + split[6], split[9]]]\n", " \n", " table = tabulate.tabulate(tableD, tablefmt='grid')\n", " \n", " lastTime = split[1]\n", " lastDate = split[9]\n", " \n", " lastGPRMC = table\n", " \n", "def parseNMEA_GSV(line): # Analiza una línea NMEA de tipo GSV y almacena su información en una tabla bonita. \n", " global lastGPGSV\n", " \n", " split = line.split(\",\")\n", " \n", " tableD = [\n", " [\"GSV\", \"Satellites in view\"],\n", " [\"\", split[3]]\n", " ]\n", " \n", " table = tabulate.tabulate(tableD, tablefmt='grid')\n", " \n", " lastGPGSV = table\n", "\n", "def imprimeDatos(): # Borra las últimas tablas de datos mostradas y pinta los datos actualizados\n", " global lastGPRMC\n", " global lastGPGSV\n", " \n", " display.clear_output()\n", " display.display(printer(lastGPRMC))\n", " display.display(printer(lastGPGSV))\n", " \n", " \n", "def leeGPS(): # Lee del puerto serie los datos del GPS y los analiza.\n", " try:\n", " ser = serial.Serial(pathSerie, 9600)\n", "\n", " lastUpdate = time.time() - 1\n", "\n", " while True:\n", " data = ser.readline()\n", "\n", " if data:\n", " data = data.decode('ascii')\n", " parseNMEA(data)\n", "\n", " currentTime = time.time()\n", "\n", " if (currentTime - lastUpdate > 0.9): # Si ha pasado más de un segundo desde la última impresión, imprime de nuevo\n", " imprimeDatos()\n", "\n", " lastUpdate = currentTime\n", " \n", " except KeyboardInterrupt:\n", " print(\"Fin ejecución\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "59c1e55f-6de8-4d4a-86ac-c9bfbbcbca67", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "+-----+-----------+-------------+--------------+--------+\n", "| RMC | UTC Time | Latitude | Longitude | Date |\n", "+-----+-----------+-------------+--------------+--------+\n", "| | 231432.00 | 3709.83273N | 00336.07721W | 290422 |\n", "+-----+-----------+-------------+--------------+--------+" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "+-----+--------------------+\n", "| GSV | Satellites in view |\n", "+-----+--------------------+\n", "| | 07 |\n", "+-----+--------------------+" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Fin ejecución\n" ] } ], "source": [ "leeGPS()" ] }, { "cell_type": "markdown", "id": "1bec812f-7ce5-445f-b0e8-c3fd30ef7c86", "metadata": {}, "source": [ "## Produciendo sonidos para codificar la fecha y hora\n", "\n", "Añadimos unas funciones más para reproducir unos sonidos que codifican la fecha y la hora recibida del GPS estilo \"R2D2\". Solo suena en los minutos \"en punto\" (segundos == 0)." ] }, { "cell_type": "code", "execution_count": 6, "id": "b437846c-f525-4a7b-8078-780caa16bb01", "metadata": {}, "outputs": [], "source": [ "from IPython.display import Audio\n", "import numpy as np\n", "\n", "notes = np.arange(1, 12) * 440.0\n", "\n", "\n", "def getNote(digito, volume = .1, sampling_rate=44100, duration = 0.1): # Fabrica los samples de una nota determinada (0-10)\n", " global notes\n", " \n", " digito = int(digito)\n", " \n", " f = notes[digito]\n", " samples = volume * (np.sin(2*np.pi*np.arange(sampling_rate*duration)*f/sampling_rate)).astype(np.float32)\n", " \n", " return samples\n", "\n", "def getNotes(datetime, volume): # Genera los samples de una fecha y hora, cifra a cifra. Empieza por la nota 10 para marcar el comienzo\n", " samples = getNote(10, volume)\n", "\n", " for i in datetime:\n", " if (type(samples) is np.ndarray):\n", " samples = np.concatenate((samples, getNote(i, volume)))\n", "\n", " samples[-1] = 1.0 # Hack para evitar el que notebook normalice el volumen\n", " \n", " return samples\n", "\n", "def playDateTime(date, time, volume=0.3): # Reproduce los sonidos para codificar la fecha y hora\n", " time = time[:6]\n", " \n", " datetime = date + time\n", "\n", " samples = getNotes(datetime, volume)\n", " \n", " display.display(Audio(samples, rate=44100, autoplay=True))\n", " \n", "lastSound = 0\n", "\n", "def imprimeDatos(): # Sobreescribimos la función que pinta las tablas para que cada minuto en punto suene la codificación de la hora\n", " global lastGPRMC\n", " global lastGPGSV\n", " global lastTime\n", " global lastDate\n", " global lastSound\n", " \n", " currentTime = time.time()\n", " \n", " if currentTime - lastSound > 1.9: # Evitamos que se borre la salida si estan sonando los pitidos\n", " display.clear_output()\n", " display.display(printer(lastGPRMC))\n", " display.display(printer(lastGPGSV))\n", "\n", " if lastTime[4:6] == \"00\": # En los minutos en punto pita\n", " playDateTime(lastDate, lastTime, volume = 1)\n", " lastSound = currentTime\n" ] }, { "cell_type": "code", "execution_count": 7, "id": "34a288bc-81ca-4594-8e3e-27f03090b4e8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "+-----+-----------+-------------+--------------+--------+\n", "| RMC | UTC Time | Latitude | Longitude | Date |\n", "+-----+-----------+-------------+--------------+--------+\n", "| | 231443.00 | 3709.83172N | 00336.07816W | 290422 |\n", "+-----+-----------+-------------+--------------+--------+" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "+-----+--------------------+\n", "| GSV | Satellites in view |\n", "+-----+--------------------+\n", "| | 07 |\n", "+-----+--------------------+" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Fin ejecución\n" ] } ], "source": [ "leeGPS()" ] }, { "cell_type": "markdown", "id": "2ce1b851-01f8-4816-835c-ed396cd367c2", "metadata": {}, "source": [ "Por último vamos a hacer unas rutinas que sean capaces de a partir de un audio en el que haya algunos pitidos decodificarlos y recuperar la fecha y hora en la que fueron emitidos." ] }, { "cell_type": "code", "execution_count": 8, "id": "527a766d-69ad-4048-a56f-321042cb1419", "metadata": {}, "outputs": [], "source": [ "from numpy.fft import fftfreq, fft\n", "import matplotlib.pyplot as plt\n", "\n", "def buscaNota(notaBuscada, samples, tamanioMuestreo, pasos = 1, desde = 0, hasta = -1): \n", " '''\n", " Busca en toda la onda la frecuencia de la nota 10, que es la que estamos usando para señalizar el principio del mensaje\n", " '''\n", " \n", " global notes\n", " \n", " if hasta == -1:\n", " hasta = len(samples)\n", " \n", " frecuenciaBuscada=int(notes[notaBuscada]/(44100 / tamanioMuestreo))\n", "\n", " maxVal = 0\n", " maxPos = 0\n", "\n", " for pos in range(desde, hasta, pasos): # Vamos analizando trocitos\n", " samp = samples[pos:pos+tamanioMuestreo]\n", " \n", " four = abs(fft(samp))[:int(tamanioMuestreo/2)] # FFT\n", " \n", " m = round(four[frecuenciaBuscada], 5) # Redondeamos a 5 cifras decimales la frecuencia que buscamos\n", "\n", " if (m > maxVal): # Si es la mayor actualizamos\n", " maxVal = m\n", " maxPos = pos\n", " #print(pos)\n", " #print(m)\n", " \n", " return maxPos\n", "\n", "\n", "\n", "def queNota(samples): # Analiza un trozo de muestras y devuelve la nota que está más presente de acuerdo a su FFT\n", " global notes\n", " \n", " tamanioMuestreo = len(samples)\n", " \n", " four = abs(fft(samples))[:int(len(samples)/2)] # FFT\n", " \n", " max = 0\n", " selectedNote = 0\n", " \n", " for i, n in enumerate(notes): # Analizamos las frecuencias de las notas\n", " frecuenciaBuscada=int(n/(44100 / tamanioMuestreo))\n", " \n", " intensity = four[frecuenciaBuscada]\n", " \n", " if intensity > max: # Nos quedamos con la más intensa\n", " max = intensity\n", " selectedNote = i\n", "\n", " return selectedNote\n", " \n", "\n", "def decodifica(samples, tamanioMuestreo): # A partir de una muestra que debe contener todos los digitos del\n", " # mensaje los decodificamos\n", " mensaje = \"\"\n", " \n", " for pos in range(0, len(samples), tamanioMuestreo): \n", " ss = samples[pos:pos + tamanioMuestreo]\n", " nota = queNota(ss)\n", " \n", " if (nota < 10):\n", " mensaje += str(nota)\n", " \n", " return mensaje\n", " \n", " \n", " \n", "def localizaDecodifica(samples): # En la muestra completa de sonido buscamos donde empieza el mensaje\n", " # y lo decodificamos\n", " \n", " notaBuscada = 10 # La nota inicial del mensaje es la 10\n", " \n", " tamanioMuestreo = int(44100 * 0.1)\n", " \n", " newPos = buscaNota(notaBuscada, samples, int(tamanioMuestreo / 2), pasos = int(tamanioMuestreo/2)) # Buscamos rapidamente la zona donde está\n", " \n", " #print(newPos)\n", " \n", " newPos2 = buscaNota(notaBuscada, samples, tamanioMuestreo, pasos = 1, desde = newPos - tamanioMuestreo, hasta = newPos + tamanioMuestreo*2) # Hacemos una busqueda fina cerca de la anterior posición\n", "\n", " #print(newPos2)\n", " \n", " samp = samples[newPos2:newPos2 + tamanioMuestreo*13] # Recortamos el trozo que debe tener el mensaje completo\n", " \n", " mensaje = decodifica(samp, tamanioMuestreo) # Decodificamos\n", " \n", " return mensaje" ] }, { "cell_type": "markdown", "id": "4dd60396-657d-42ca-8ac3-07151a2ea439", "metadata": {}, "source": [ "Aquí probamos las rutinas anteriores generando un posible mensaje artificial:" ] }, { "cell_type": "code", "execution_count": 9, "id": "9d39d1bb-5053-4975-9f41-360e070dc496", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Mensaje localizado y decodificado: 012345678901\n" ] } ], "source": [ "ruidoInicial = np.random.rand(67570) * 0.1 # Producimos un ruido blanco inicial\n", "samples = getNote(10) # Producimos la nota de inicio \n", "ruidoFinal = np.random.rand(143233) * 0.1 # Ruido blanco final\n", "\n", "samples = np.concatenate((ruidoInicial, samples))\n", "\n", "for i in range(0, 12): # Producimos doce notas: 012345678901\n", " s = getNote(i%10)\n", " \n", " samples = np.concatenate((samples, s))\n", "\n", "samples = np.concatenate((samples, ruidoFinal))\n", "\n", "\n", "samples[-1] = 1 # Pequeño hack porque el plugin de emitir audio normaliza el volumen\n", "\n", "display.display(Audio(samples, rate=44100, autoplay=True)) # Reproducimos el mensaje\n", "\n", "mensaje = localizaDecodifica(samples)\n", "\n", "print(f\"Mensaje localizado y decodificado: {mensaje}\")" ] }, { "cell_type": "markdown", "id": "5059a0e7-045d-45c6-a80a-777f5107d20a", "metadata": {}, "source": [ "Repetimos lo de antes, pero con un mensaje grabado realmente en un fichero `WAV`. Se oye ruido de fondo real y hasta el tick del reloj de la cocina:" ] }, { "cell_type": "code", "execution_count": 10, "id": "1c72d2c8-4411-4441-b5ef-deeb3b053fc8", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Mensaje localizado y decodificado: 270422234800\n" ] } ], "source": [ "from scipy.io.wavfile import read\n", "import numpy as np\n", "from IPython.display import Audio\n", "from IPython import display\n", "\n", "a = read(\"sonidos/sonido.wav\") # Leemos el fichero wav\n", "data = np.array(a[1],dtype=float) \n", "\n", "\n", "display.display(Audio(data, rate=44100, autoplay=True)) # Lo reproducimos\n", "\n", "mensaje = localizaDecodifica(data) # Obtenemos el mensaje\n", "\n", "print(f\"Mensaje localizado y decodificado: {mensaje}\")" ] } ], "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.8.12" } }, "nbformat": 4, "nbformat_minor": 5 }