{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Proyecto barcos: recepción de mensajes AIS\n", "Este notebook funciona como guía para el proyecto de barcos del curso Tallerine Comunicaciones Inalámbricas. A lo largo de este contenido se les pedirán algunos ejercicios de búsqueda de información o de escritura de código. Es obligatorio hacer todas las tareas indicadas justificando la información y comentando el código. El seguimiento de este notebook permitirá desarrollar el proyecto con éxito y poder reflejar el trabajo realizado en la documentación final." ], "metadata": { "id": "gd8oNLY6nTzx" } }, { "cell_type": "markdown", "source": [ "## Sistema de Identificación Automática\n", "El Sistema de Identificación Automática (AIS, por sus siglas en inglés) es una tecnología de comunicaciones inalámbricas. Tiene como principal objetivo mejorar y promover la seguridad marítima. En un escenario ideal todas las embarcaciones, tanto en alta mar como ancladas, estarían provistas de una estación AIS. Esto les permitiría transmitir mensajes de forma periódica, considerando ciertos intervalos de reporte. La información transmitida puede ser de carácter dinámico (información de movimiento, como ubicación, velocidad o dirección de la embarcación) o de carácter estático (información sobre el tamaño de la embarcación, su nombre, entre otras cosas). Como se verá al estudiar la tecnología, en la mayoría de los países la legislación sólo obliga contar con una estación AIS a las embarcaciones de alto porte.\n", "\n", "## Objetivo del proyecto\n", "El objetivo de este proyecto es comprender la tecnología AIS y escribir funciones que permitan decodificar mensajes AIS. El proyecto contará con cuatro partes:\n", "\n", "* En primer lugar se estudiará la tecnología, buscando información y explicando su funcionamiento. Esto conformará en gran parte la base teórica sobre la que se desarrollarán las siguientes partes.\n", "* La segunda parte consistirá en el diseño y la implementación de funciones para decodificar mensajes y expresarlos en un formato específico que se describirá más adelante.\n", "* La tercera parte consistirá en la construcción de una antena.\n", "* Finalmente, se realizarán pruebas con equipos de hardware (antena y sdr) para recibir mensajes AIS en tiempo real." ], "metadata": { "id": "cNoxSOExoh2b" } }, { "cell_type": "markdown", "source": [ "## Entrega intermedia y entrega final del proyecto\n", "\n", "\n", "1. Entrega intermedia Domingo 2/6 a las 23:59 hs. Para esta fecha se espera que los grupos hayan completado la parte 1 y avanzado en la parte 2. Se deberá entregar un documento en pdf conteniendo: introducción, fundamento teórico, implementación (pseudocódigos de las funciones pedidas en la parte 2).\n", "2. Entrega final Domingo 23/6 a las 23:59 hs. Se deberá entregar el informe completo en pdf y el notebook con las implementaciones de las funciones realizadas. Para el informe final se deberán tener en cuenta los comentarios recibidos en la entrega intermedia. Se deberá reflejar el trabajo en las cuatro partes del proyecto (se deberá indicar el modelo de antena fabricado, los mensajes recibidos usando el sdr, etc).\n", "Además se deberá completar el documento inicial con las secciones de Análisis de Resultados y Conclusiones.\n", "\n", "\n" ], "metadata": { "id": "zZgaPjBqqZUt" } }, { "cell_type": "markdown", "source": [ "## Parte 1: Estudio de la tecnología AIS\n", "Responder las siguientes preguntas buscando información por fuera de este notebook. Recordar guardar las referencias consultadas.\n", "1. ¿Con qué objetivos se crea la tecnología AIS?\n", "2. Explicar brevemente el funcionamiento de la tecnología. Algunas preguntas disparadoras: ¿Qué ventaja tiene sobre tecnologías previas, como el radar? ¿Cómo se comunican entre sí las embarcaciones? ¿Qué tipos de estaciones hay? ¿Qué son los intervalos de reporte? ¿Qué canales de frecuencia se utilizan y cuándo se va cambiando de canal?\n", "3. ¿Cuántos mensajes existen en la tecnología AIS? Elegir algunos mensajes representativos (por ejemplo, el mensaje 18 y el mensaje 24 para estaciones de clase B CS) y explicar sus campos principales.\n", "NOTA: Se pueden ver las funciones que se encuentran hacia el final de este notebook para generar mensajes 18 y 24, y considerar que los campos principales son aquellos que son entradas de las funciones.\n" ], "metadata": { "id": "yANVE1XsqSQ2" } }, { "cell_type": "markdown", "source": [ "## Parte 2: Decodificación de mensajes AIS\n", "### Inversión de bits\n", "Responder la siguiente pregunta.\n", "1. ¿Qué mecanismo utiliza la tecnología AIS para codificar los bits? Explicar su funcionamiento con un ejemplo.\n", "\n", "Al implementar un receptor AIS va a ser de interés poder decodificar el mecanismo descrito. Esto se puede hacer aplicando una decodificación diferencial (proceso que no será visto en el curso y no es necesario que entiendan qué es) y luego una inversión de bits. La inversión de bits consistirá en una función que para todo bit de entrada que sea 1 tenga una salida 0, y viceversa.\n", "\n", "**Tarea 1.** Escribir el pseudocódigo/diagrama de flujo de una función que invierta los bits que recibe como entrada en una lista y devuelva el resultado en otra lista.\n", "\n", "**Tarea 2.** Pasar el pseudocódigo escrito a una función de Python, considerando el encabezado que se define en la siguiente celda. Algunas estructuras pueden parecer extrañas, pero son necesarias para que en la última parte del proyecto se puedan realizar pruebas con equipos de hardware." ], "metadata": { "id": "VoS16N0Psax4" } }, { "cell_type": "code", "source": [ "import numpy as np\n", "\n", "def invert(input_items):\n", " ### Sea \"invert\" una función que invierte bits que recibe. La entrada input_items es una lista de listas, y solo\n", " ### nos interesa su primer lista elemento. Esto significa que los bits que se deben invertir son los bits de\n", " ### input_items[0].\n", " lista_bits_invertir = input_items[0]\n", "\n", " ### Completar el código, generando una lista llamada \"salida\" con los bits de entrada invertidos.\n", "\n", " return(salida)" ], "metadata": { "id": "6VezGwgAbimo" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "**Tarea 3.** Escribir un programa corto para verificar que la función \"invert\" implementada funciona de forma correcta." ], "metadata": { "id": "eM1UeJXNvLUx" } }, { "cell_type": "code", "source": [ "### Escribir el programa aquí.\n", "import numpy as np" ], "metadata": { "id": "_0gUx1pgd9x1" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "### Interpretacion de mensajes\n", "Una vez los bits fueron decodificados, se tendrá un string de bits que aún no puede ser interpretado. Por este motivo, se pasará el string de bits a un formato llamado NMEA, que luego se podrá interpretar usando sitios web diseñados para ello.\n", "\n", "Responder las siguientes preguntas:\n", "1. ¿Qué es el formato NMEA?\n", "2. ¿Qué es una suma de comprobación o checksum? ¿Cómo se genera el checksum NMEA?\n", "3. ¿Qué es el código ASCII? ¿Qué variante utiliza la tecnología AIS?\n", "\n", "Realizar las siguientes tareas:\n", "\n", "**Tarea 1.** Escribir el pseudocódigo de una función que calcule el checksum NMEA para un string de caracteres.\n", "\n", "**Tarea 2.** Escribir una función \"nmea_checksum\" que reciba un string de caracteres y calcule el checksum NMEA asociado.\n", "\n", "Nota: Se entrega ya implementada una función llamada \"unpack\". Es importante leer su código e intentar entenderla, para poder utilizarla de forma conveniente en las tareas." ], "metadata": { "id": "zTyUsDVbSq-W" } }, { "cell_type": "code", "source": [ "import numpy as np\n", "\n", "def unpack(buffer, start):\n", " # Esta función toma 6 bits de \"buffer\", en particular los seis bits a partir de \"start\", y\n", " # devuelve el entero representado por esos bits. De esta forma, después se puede aplicar\n", " # chr() sobre ese entero.\n", " ret = 0\n", " for i in range(start, start + 6):\n", " ret <<= 1 # se shiftea ret un lugar hacia la izquierda (es como multiplicar por 2 en binario)\n", " ret = ret | (int(buffer[i]) & 0x01) # a ret se le calcula el OR con el bit menos significativo de buffer\n", " return ret" ], "metadata": { "id": "kZTqJEypagLn" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "def nmea_checksum(buffer):\n", " ### Sea \"nmea_checksum\" una función que calcula el checksum de un string de caracteres. Recibe\n", " ### el string de caracteres en \"buffer\" y debe devolver el valor de la suma de comprobación\n", " ### en formato de caracter.\n", " sum = 0x00 # Variable donde se guardará el valor del checksum\n", "\n", " ### Completar el código, guardando en \"sum\" el valor del checksum.\n", "\n", " return(chr(sum))" ], "metadata": { "id": "E37Y6t8Vde5X" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "**Tarea 3.** Considerando las funciones \"unpack\" y \"nmea_checksum\", escribir el pseudocódigo de una función que reciba el campo de datos de una trama AIS en formato de bits, y que devuelva el mensaje AIS como un string de caracteres en formato NMEA.\n", "\n", "**Tarea 4.** Escribir el código para la función descrita en la Tarea 3, llamándola \"AIS_message\"." ], "metadata": { "id": "p0QiDTjceHjJ" } }, { "cell_type": "code", "source": [ "def AIS_message(payload, designator=\"A\"):\n", " ### Función que recibe el payload en bits del mensaje AIS y lo devuelve como\n", " ### un string de caracteres en formato NMEA.\n", " ### Procesar únicamente los mensajes que tengan un solo fragmento, y descartar el resto.\n", "\n", " final_message = \"\"\n", "\n", " ### Completar el código de la función AIS_message.\n", "\n", " return(final_message)\n", "\n" ], "metadata": { "id": "NRPTA26QY7hj" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "**Tarea 5.** Considerar las siguientes funciones que generan mensajes AIS de tipo 18 y 24. Las mismas permiten obtener los mensajes como secuencias de bits. Escribir un programa que genere un mensaje AIS como string de bits y utilizar \"AIS_message\" para decodificar ese mensaje en formato NMEA. Luego verificar con alguna página en Internet (como [este sitio](https://www.aggsoft.com/ais-decoder.htm)) si el mensaje obtenido se corresponde con el mensaje original." ], "metadata": { "id": "NyJ6-VuKfmCY" } }, { "cell_type": "code", "source": [ "### Funciones para generar mensajes 18 y 24 (y algunas funciones auxiliares).\n", "def encode_string(string):\n", "\tvocabolary = \"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^- !\\\"#$%&'()*+,-./0123456789:;<=>?\"\n", "\tencoded_string = \"\"\n", "\tfor c in string.upper():\n", "\t\tindex = vocabolary.find(c)\n", "\t\tencoded_string += '{0:b}'.format(index).rjust(6,'0')\n", "\treturn encoded_string\n", "\n", "def compute_long_lat (__long, __lat):\n", "\t_long = '{0:b}'.format(int(round(__long*600000)) & 0b1111111111111111111111111111).rjust(28,'0')\n", "\t_lat = '{0:b}'.format(int(round(__lat*600000)) & 0b111111111111111111111111111).rjust(27,'0')\n", "\treturn (_long, _lat)\n", "\n", "def encode_18(__mmsi, __speed, __long, __lat, __course, __ts):\n", "\t_type = '{0:b}'.format(18).rjust(6,'0')\t\t\t\t# 18\n", "\t_repeat = \"00\"\t\t\t\t\t\t\t\t\t\t# repeat (directive to an AIS transceiver that this message should be rebroadcast.)\n", "\t_mmsi = '{0:b}'.format(__mmsi).rjust(30,'0')\t\t# 30 bits (247320162)\n", "\t_reserved = '0'*8\n", "\t_speed = '{0:b}'.format(int(round(__speed*10))).rjust(10,'0')\t# Speed over ground is in 0.1-knot resolution from 0 to 102 knots. value 1023 indicates speed is not available, value 1022 indicates 102.2 knots or higher.\n", "\t_accurancy = '0'\t\t\t\t\t\t\t\t\t# > 10m\n", "\n", "\t(_long, _lat) = compute_long_lat(__long, __lat)\n", "\n", "\t_course = '{0:b}'.format(int(round(__course*10))).rjust(12,'0')\t# 0.1 resolution. Course over ground will be 3600 (0xE10) if that data is not available.\n", "\t_true_heading = '1'*9\t# 511 (N/A)\n", "\t_ts = '{0:b}'.format(__ts).rjust(6,'0') # Second of UTC timestamp.\n", "\n", "\t_flags = '001011100'\n", "\t# '00': Regional reserved\n", "\t# '1': CS mode (carrier sense Class B)\n", "\t# '0' Display flag\n", "\t# '1': DSC\n", "\t# '1': Band Flag\n", "\t# '1': M22 Flag\n", "\t# '0': Assigned 0 -> Autonomous mode\n", "\t# '0': Raim flag\n", "\n", "\t_rstatus = '11100000000000000110' # ??\n", "\t# '11100000000000000110' : Radio status\n", "\n", "\treturn _type+_repeat+_mmsi+_reserved+_speed+_accurancy+_long+_lat+_course+_true_heading+_ts+_flags+_rstatus\n", "\n", "\n", "def encode_24(__mmsi, __part, __vname=\"NAN\", __callsign=\"NAN\", __vsize1=\"90\", __vsize2=\"14\", __vtype=50):\n", "\t_type = '{0:b}'.format(24).rjust(6,'0')\t\t\t\t# 24\n", "\t_repeat = \"00\"\t\t\t\t\t\t\t\t\t\t# repeat (directive to an AIS transceiver that this message should be rebroadcast.)\n", "\t_mmsi = '{0:b}'.format(__mmsi).rjust(30,'0')\t\t# 30 bits (247320162)\n", "\tif __part == \"A\":\n", "\t\t_part = \"00\"\n", "\t\t_vname = encode_string(__vname)\n", "\t\t_padding = '0'*(156-6-2-30-2-len(_vname))\t\t# 160 bits per RFC -> 4 bits padding added in Build_Frame_imple.cc\n", "\t\treturn _type+_repeat+_mmsi+_part+_vname+_padding\n", "\n", "\telse:\n", "\t\t_part = \"01\"\n", "\t\t_vtype = '{0:b}'.format(__vtype).rjust(8,'0') # 60 = passengers\n", "\t\t_vendorID = \"0\"*42\t\t\t\t\t\t\t\t# vendor ID\n", "\n", "\t\t_tmp = encode_string(__callsign)\n", "\t\t_callsign = _tmp + \"0\"*(42-len(_tmp))\t\t\t# 7 six-bit characters\n", "\n", "\t\t_hl=int(__vsize1)/2\t\t# AIS antenna in the middle of the boat\n", "\t\t_hw=int(__vsize2)/2\n", "\t\t_half_length='{0:b}'.format(int(_hl)).rjust(9,'0')\n", "\t\t_half_width='{0:b}'.format(int(_hw)).rjust(6,'0')\n", "\n", "\t\treturn _type+_repeat+_mmsi+_part+_vtype+_vendorID+_callsign+_half_length+_half_length+_half_width+_half_width+\"000000\"\n", "\n", "def datafield(type=0, speed=0.1, long=9.72357833333333, lat=45.6910166666667, course=83.4, ts=38): #Use this tool to generate the binary payload of an AIVDM sentence.\n", "\n", " mmsi = 247320162 # este va a ser el default. tiene que tener 9 dígitos\n", " payload = \"\"\n", "\n", " if type == 18: #18 = Standard Class B CS Position Report\n", " payload = encode_18(__mmsi=int(mmsi), __speed=float(speed), __long=float(long), __lat=float(lat), __course=float(course), __ts=int(ts))\n", "\n", " elif type == 240: #24 = Static Data Report\n", " payload = encode_24(__mmsi=int(mmsi), __part=\"A\", __vname=\"ROMA\")\n", " elif type == 241:\n", " payload = encode_24(__mmsi=int(mmsi), __part=\"B\", __vname=\"ROMA\", __callsign=\"@@@@@@@\", __vsize1=\"18\", __vsize2=\"14\", __vtype=int(30))\n", "\n", " return(payload)" ], "metadata": { "id": "AIy3_4UugZz-" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "### Escribir el programa de prueba de \"AIS_message\" aquí.\n", "import numpy as np" ], "metadata": { "id": "zOBlEp5kgCa6" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "source": [ "## Parte 3: Construcción y evaluación de la antena\n", "\n", "En el EVA existirá un sección específica con recomendaciones para la elección y construcción de la antena. Cada grupo será provisto de un cable coaxial y de un conector SMA necesario para conectar la antena al SDR.\n", "\n", "Es importante realizar evaluación de la antena utilizando un VNA (Vector Netwok Analyzer). Esta tarea será realizada en conjunto con las docentes." ], "metadata": { "id": "0WJ9LXjFx578" } }, { "cell_type": "markdown", "source": [ "## Parte 4: Pasaje de las funciones a GNU Radio para pruebas con hardware\n", "La última parte del proyecto consiste en utilizar la herramienta de software \"GNU Radio\" para realizar pruebas con dispositivos de hardware del receptor implementado. Esta parte será realizada por todos los equipos al mismo tiempo, con ayuda de las docentes.\n", "\n", "\n", "En la ceibalita, bajo el directorio /home/ceibal/ deberá bajarse e instalar un repositorio preparado para el proyecto (https://gitlab.fing.edu.uy/rominag/ais-tallerine) utilizando la siguiente secuencia de comandos en una terminal:\n", "\n", "\n", "\n", "```\n", "git clone https://gitlab.fing.edu.uy/rominag/ais-tallerine\n", "cd ais-tallerine\n", "mkdir build\n", "cd build\n", "cmake ../\n", "make\n", "sudo make install\n", "sudo ldconfig\n", "cd\n", "\n", "```\n", "\n", "Los comandos anteriores les generarán una carpeta en la ruta /home/ceibal/ais-tallerine. En ese directorio, bajo /home/ceibal/ais-tallerine/python deberán incluir las funciones implementadas en la parte 2.\n" ], "metadata": { "id": "C-JUiFrHhISD" } } ] }