{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "LF0f-9Cqt-9U" }, "source": [ "# Módulo III: Sincronización y telemetría" ] }, { "cell_type": "markdown", "metadata": { "id": "uWL5-Arot-9a" }, "source": [ "Ahora que hemos podido demodular la señal y decodificar una primera imagen veremos como mejorar varios aspectos. En particular en este módulo veremos como sincronizar y calibrar la imagen a partir de los datos de telemetría." ] }, { "cell_type": "markdown", "metadata": { "id": "bbnvBrD8t-9X" }, "source": [ "`Grupo`:\n", "\n", "`Estudiantes`:" ] }, { "cell_type": "markdown", "metadata": { "id": "mEZ1QGeFpBAn" }, "source": [ "## Funciones auxiliares\n", "Se ponen a disposición las siguientes funciones que pueden ser de utilidad:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "bkK928MDRAVn" }, "outputs": [], "source": [ "from scipy.io.wavfile import read\n", "from PIL import Image\n", "from matplotlib.pyplot import imshow\n", "from matplotlib import pyplot as plt\n", "import numpy as np\n", "def visualizar_imagen(matriz_APT):\n", " img = Image.fromarray(matriz_APT)\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", " plt.figure()\n", " plt.rcParams[\"figure.figsize\"] = (14,14)\n", " plt.axis('off')\n", " plt.imshow(img,interpolation='none')\n", "\n", "def guardar_imagen(matriz_APT, filename):\n", " img = Image.fromarray(matriz_APT)\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", " img.save(filename)\n", "\n", "def visualizar_histograma(x):\n", " plt.figure(figsize=(14,7))\n", " plt.hist(x,range(255))\n", " plt.ylabel('Frecuencia')\n", " plt.xlabel('Nivel de gris ( Blanco = 255, Negro = 0)')\n", " plt.title('Histograma')\n", " plt.show()\n" ] }, { "cell_type": "markdown", "metadata": { "id": "y-nbN74xSN0V" }, "source": [ "Para este módulo Ud. cuenta con una señal APT ya demodulada en 1D que se encuentra en la carpeta grabaciones del curso.\n" ] }, { "cell_type": "code", "source": [ "fs = 4160\n", "apt_1d = np.load(\"apt_demod.npy\")" ], "metadata": { "id": "Z_OkoNrChH2g" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "WtPe9CXuaJki" }, "source": [ "Calcular la cantidad de filas que tiene la señal, y transformar la señal 1D en una 2D. Luego visualizarla utilizando la función proporcionada \"visualizar_imagen\".\n", "\n", "Recomendación: Durante lo largo del notebook, va a encontrar que hay momentos que debe trabajar con la señal en 1D, y en otro en 2D. Recomendamos implementar dos funciones, APT_a_2D que tome la señal en 1D, la cantidad de columnas y la cantidad de filas, y la transforme en 2D. De forma analoga, implementar APT_a_1D que hago lo inverso." ] }, { "cell_type": "markdown", "metadata": { "id": "WRlw_hqsClr5" }, "source": [ "## PARTE 1: Sincronización" ] }, { "cell_type": "markdown", "metadata": { "id": "jMTE9LcgGS3w" }, "source": [ "Lo primero que se puede apreciar es que la imagen no comienza con uno de los cuadros de sincronización como estaba definido en el formato APT. En qué columna comience la imagen depende del momento en que se da inicio a la grabación, por lo cual es necesario corregir este aspecto." ] }, { "cell_type": "markdown", "source": [ "### Ejercicio 1:\n", "Piense en una forma de que la primera linea comience con la sincronización e implementelo. Visualize la imagen resultante\n" ], "metadata": { "id": "4kZFEtzbEjWg" } }, { "cell_type": "code", "source": [], "metadata": { "id": "MMweBrjqOj2V" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "I_jZ9auIqSuN" }, "source": [ "\n", "Aunque haya alineado la imagen con un campo de sincronización, debería observar cierta “curvatura” en la imagen, este efecto lo puede observar mejor descargando la imagen generada y abriéndola con un visor de imágenes en su PC.\n", "\n", "La explicación para este fenómeno es que las líneas de video APT no duran exactamente $0.5~s$ como asumimos hasta ahora, sino que la duración de cada línea de video se ve afectada por el llamado efecto Doppler (ver https://es.wikipedia.org/wiki/Efecto_Doppler).\n", "\n", "Si una fuente electromagnética se mueve en relación con un observador, hay un cambio en la frecuencia observada. Si la fuente se aleja del observador, la frecuencia observada parecerá disminuir. Note que los satélites NOAA se mueven a una velocidad de más de $26000~km.h^{-1}$ por lo que el efecto no es despreciable.\n", "\n", "La velocidad relativa respecto al obervador en la tierra hace que se produzca un pequeño desplazamiento en frecuencia de la subportadora de 2400 Hz que transmite el satélite. Si esto no es detectado y corregido en la demodulación, cada línea de video se adelantará o atrasará en el tiempo respecto a los $0.5~s$ en transmisión.\n", "\n", "Si bien puede ser un error chico en cada línea de video, los errores de sincronización se van acumulando en el tiempo, lo cual produce el efecto que se puede ver en la imagen. Note que al principio entran cada vez más píxeles por línea, hasta que llega un punto en que esto se compensa, y a partir de allí aparecen cada vez más menos píxeles por línea.\n", "\n", "Para corregir tanto el efecto Doppler como la alineación de la imagen nos ayudaremos de los campos de sincronización que se especifican en la siguiente figura:\n", "\n", "\n", "\n", "> ![sync](https://iie.fing.edu.uy/~gbelcredi/tallerineImSat/fig/apt_sync.png)\n", ">\n", ">Referencia: [NOAA KLM User's Guide](http://webapp1.dlib.indiana.edu/virtual_disk_library/index.cgi/2790181/FID1497/klm/html/c4/sec4-2.htm#t422-1)\n", "\n", "\n", "Para lo que sigue se provee la función ```obtener_muestras_comienzo_sync(signal, sync)``` que devuelve, a partir de una señal APT y una señal de sinconización, los indices de la señal APT donde comienza un patrón de sincronización.\n", "\n", "Esta funcion recorre la el vector \"signal\" y busca el patrón \"sync\". Para esto se van tomando de a pedacitos de la señal \"signal\", del mismo largo que el \"sync\", y se mide la similaridad con \"sync\". La similaridad entre dos vectores se realiza matematicamente como la correlación cruzada entre estas. Puede obtener una idea intuitiva de la correlación cruzada entre señales con el ejemplo de este video: https://www.youtube.com/watch?v=cuD-LXic2cE" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mby6Eyw_FZme" }, "outputs": [], "source": [ "def obtener_muestras_comienzo_sync(signal, sync):\n", " \"\"\"!@brief Devuelve los indices de comienzo del cuadro de sincronización de una señal APT.\n", " @param signal Señal APT\n", " @param sync Vector de sincronización (SyncA o SyncB)\n", " @result peaks Indices de sincronización.\n", " \"\"\"\n", " # list of maximum correlations found: (index, value)\n", " peaks_corr = [(0, 0)]\n", "\n", " # minimum distance between peaks\n", " mindistance = 2000\n", "\n", " # need to shift the values down to get meaningful correlation values\n", " signalshifted = [x-128 for x in signal]\n", " sync = [x-128 for x in sync]\n", "\n", "\n", " for i in range(0,len(signalshifted) - len(sync)):\n", "\n", " corr = np.dot(sync, signalshifted[i : i+len(sync)])\n", "\n", " # if previous peak is too far, keep it and add this value to the\n", " # list as a new peak\n", " if i - peaks_corr[-1][0] > mindistance:\n", " peaks_corr.append((i, corr))\n", "\n", " # else if this value is bigger than the previous maximum, set this\n", " # one\n", " elif corr > peaks_corr[-1][1]:\n", " peaks_corr[-1] = (i, corr)\n", "\n", " peaks = [i[0] for i in peaks_corr] # retrieve peak indexes from peaks_corr\n", "\n", " return peaks" ] }, { "cell_type": "markdown", "metadata": { "id": "pQgI-JeHNbvy" }, "source": [ "### **Ejercicio 2**\n", "A partir del diagrama anterior, genere el array syncA que representa el patrón de sincronización del canal A y corra la función `obtener_muestras_comienzo_sync` para obtener los indices." ] }, { "cell_type": "code", "source": [], "metadata": { "id": "uTJqniCsOmlK" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "gTs4Erq6QV6D" }, "source": [ "Compruebe el funcionamiento realizando las siguientes dos pruebas:\n", "\n", "1) Graficar para alguno de los indices obtenidos, la señal APT centrada en ese indice $\\pm$ 100 muestras. ¿Qué observa?\n", "\n", "2) Calcule la diferencia entre un indice y el siguiente encontrado. ¿Cuanto es la diferencia? ¿Tiene sentido?\n", "\n", "Repetir esto para algunos indices más." ] }, { "cell_type": "code", "source": [], "metadata": { "id": "iLmuUNZROoMu" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "gU0hFh2wf-zR" }, "source": [ "### **Ejercicio 3**\n", "\n", "Ahora que Ud. dispone de todos los indices de comienzo de cada linea de video APT, piense como podría utilizar esta información para armar una nueva imagen donde todas las lineas comienzan con el campo de sincronización. Implementelo y observe la imagen" ] }, { "cell_type": "code", "source": [], "metadata": { "id": "aCl_-1m8OqI9" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "sFVr2vaGhuqo" }, "source": [ "## PARTE 2: Telemetría" ] }, { "cell_type": "markdown", "metadata": { "id": "yW1M2fvTYKNe" }, "source": [ "Si bien anteriormente normalizamos la señal para ocupar todo el rango 0-255, lo que puede suceder es que hayamos normalizado en una muestra con ruido. Esto se puede observar a partir del histograma de la señal APT. Grafique el histograma de la señal utilizando la función auxiliar correspondiente (se le debe pasar la señal en 1D).\n", "\n" ] }, { "cell_type": "code", "source": [], "metadata": { "id": "CsfK2SlTOsYJ" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "\n", " Para solucionar esto, y recuperar los niveles del sensor AVHRR, la señal APT en el cuadro de telemetría envía valores conocidos para permitir una calibración. La siguiente tabla muestra como se compone el cuadro de telemetría y los valores de calibración, la cual **se compone de 16 \"wedges\"**. A su vez cada wedge **se repite en 8 filas y 45 columnas** consecutivas.\n" ], "metadata": { "id": "wzvhBm6tOCkr" } }, { "cell_type": "markdown", "metadata": { "id": "GvWKDq7wUxE_" }, "source": [ "![texto alternativo](https://iie.fing.edu.uy/~gbelcredi/tallerineImSat/fig/wedges.png)" ] }, { "cell_type": "markdown", "source": [ "La idea de esta sección es obtener los valores que obtenemos nosotros en la telemetria, (que no van a coincidir con los valores reales de telemetria), y luego encontrar una transformación lineal (aX + b), que mejor transforme nuestros valores de telemetria, a los reales. El primer paso para esto es quedarnos únicamente con los pixeles correspondientes a la telemetría" ], "metadata": { "id": "4fEyVaZIPwrh" } }, { "cell_type": "markdown", "source": [ "### Ejercicio 4: Obtener Telemetria\n", "\n", "De la imagen sincronizada, quedese solo con los pixeles de telemetria. Visualizela utilizando la función visualizar_imagen.\n", "\n", "* ¿De que tamaño queda esta imagen?\n", "* ¿Cuantos cuadros completos de telemetria se observan?\n", "\n", "\n" ], "metadata": { "id": "mroxH8MuRDOv" } }, { "cell_type": "code", "source": [], "metadata": { "id": "3f7wkQuUOti3" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "De todos los cuadros de telemetria, nos vamos a quedar unicamente con el menos ruidoso. Para esto, vamos a hacer un procedimiento parecido a lo que hicimos con el vector de sincronización. Utilizaremos correlación cruzada para encontrar donde comienza cada telemetria, y que tan similar es a la telemetria real. Aquella que presenta mayor similitud será la telemetria menos ruidosa. Sin embargo, para realizar la correlación cruzada, necesitamos una señal de 1D. Piense como podria pasara de tener 45 columnas de telemetría a tener 1 sola. Implementelo." ], "metadata": { "id": "K7u5qSLvRawv" } }, { "cell_type": "code", "source": [], "metadata": { "id": "FyRCNsFqOuU0" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "88XpkPhYuUbY" }, "source": [ "Ahora tenemos una señal 1D con varios cuadros completos de telemetria. La siguiente función devuelve, a partir de esta señal, una lista con los indices donde comienza cada cuadro de telemetria, y otra lista con la similitud de cada cuadro con el cuadro real de telemetria." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "8EAmY9YrINRt" }, "outputs": [], "source": [ "def obtener_indices_comienzo_telemetria_con_similitud(telemetry, sync_telemetry):\n", " # list of maximum correlations found: (index, value)\n", " peaks_corr = [(0, 0)]\n", "\n", " # minimum distance between peaks\n", " mindistance = 8*16 - 3\n", "\n", " # need to shift the values down to get meaningful correlation values\n", " signalshifted = [x-128 for x in telemetry]\n", " sync = [x-128 for x in sync_telemetry]\n", "\n", " for i in range(0,len(signalshifted) - len(sync)):\n", "\n", " corr = np.dot(sync, signalshifted[i : i+len(sync)])\n", "\n", " # if previous peak is too far, keep it and add this value to the\n", " # list as a new peak\n", " if i - peaks_corr[-1][0] > mindistance:\n", " peaks_corr.append((i, corr))\n", "\n", " # else if this value is bigger than the previous maximum, set this\n", " # one\n", " elif corr > peaks_corr[-1][1]:\n", " peaks_corr[-1] = (i, corr)\n", "\n", " peaks = [i[0] for i in peaks_corr] # retrieve peak indexes from peaks_corr\n", " corr = [i[1] for i in peaks_corr] # retrieve peak indexes from peaks_corr\n", "\n", " return peaks,corr" ] }, { "cell_type": "markdown", "metadata": { "id": "4EBb02dyZtcS" }, "source": [ "Defina el vector sync_telemetry y ejecute la función obtener_indices_comienzo_telemetria_con_similitud. Quedese con el cuadro de telemetria que mayor similitud presente." ] }, { "cell_type": "code", "source": [], "metadata": { "id": "7-lWAHmAO3BQ" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "CXBJW4KrzeJ9" }, "source": [ "A partir de la información con la que cuenta arme un vector con los valores de calibración $[tel1,tel2,..,tel8,tel9]$ y compárelo en una misma gráfica con el patrón enviado por el satélite: $[31,63,95,127,159,191,223,255,0]$." ] }, { "cell_type": "code", "source": [], "metadata": { "id": "ob6ukxdJO3p-" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "V8WGQbeg5nFY" }, "source": [ "### **Ejercicio 5: Calibración**\n", "Para calibrar la imagen buscamos ahora una operación lineal de tipo $aX+ b \\to Y$, que transforme el vector de calibración recibido en el vector de calibración original. Una vez obtenidos los valores de $a$ y $b$, aplique la transformación a todos los elementros de la matriz APT, es decir:\n", "\n", "$\\mathcal{I}_{apt~cal} = a\\mathcal{I}_{apt} + b$\n", "\n", "Visualice la imagen calibrada y grafique nuevamente el histograma, obtiene ahora lo que esperaba?\n", "\n", "**Nota**: Para encontrar los coeficientes a y b averigue sobre la función polyfit de numpy: https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html" ] }, { "cell_type": "code", "source": [], "metadata": { "id": "Mua1COIXO4ZT" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "w3Uc24DNt-9y" }, "source": [ "## Entregable\n", "\n", "Deberá subir este notebook con los ejercicios resueltos, recuerde que puede agregar celdas de texto para acompañar el código y facilitar la comprensión." ] } ], "metadata": { "colab": { "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "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.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }