{"id":21987,"date":"2017-01-04T10:00:07","date_gmt":"2017-01-04T15:00:07","guid":{"rendered":"http:\/\/blog.espol.edu.ec\/estg1003\/?p=55"},"modified":"2026-04-16T09:26:26","modified_gmt":"2026-04-16T14:26:26","slug":"morse-decodificador-sonido","status":"publish","type":"post","link":"https:\/\/blog.espol.edu.ec\/algoritmos101\/stp-aplica\/morse-decodificador-sonido\/","title":{"rendered":"1.2 Morse - Decodificador de sonido a mensaje con Python"},"content":{"rendered":"\n<p>Para analizar el <strong>sonido<\/strong> de un mensaje Morse, se procede de forma semejante al decodificador de <strong>un tono<\/strong> morse, revisando la duraci\u00f3n de cada s\u00edmbolo: <strong>punto<\/strong> o <strong>espacio<\/strong> tienen duraci\u00f3n de una marca, la <strong>raya<\/strong> tiene una duraci\u00f3n de 3 marcas, los s\u00edmbolos se separan por una pausa con un intervalo de una marca.<\/p>\n\n\n\n<p>Se divide el sonido del <code>archivo.wav<\/code> en partes o <strong>ventanas<\/strong>, usando la funci\u00f3n <code>separaventanas()<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.espol.edu.ec\/algoritmos101\/files\/2017\/04\/morsedecotono01.png\" alt=\"ventanas de sonido\" \/><\/figure>\n\n\n\n<p>Cada ventana se analiza con la transformada de Fourier para encontrar la frecuencia del sonido mas fuerte o <strong>marcas<\/strong> de puntos <code>'.'<\/code>, <code>'-'<\/code>, \u00f3 <code>' '<\/code>. El resultado de an\u00e1lisis de las <strong>ventanas<\/strong> es un vector con la <strong>marca<\/strong> de frecuencia m\u00e1s fuerte para cada una de las ventanas. (funci\u00f3n <code>marcasdeventanas()<\/code>)<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.espol.edu.ec\/algoritmos101\/files\/2017\/04\/morsedecotono04.png\" alt=\"\" \/><\/figure>\n\n\n\n<p>La frecuencia o 'tono frecuente' se usa como una referencia para diferenciar si existe una se\u00f1al para un punto o raya Morse. El tono frecuente se obtiene mediante la \"moda\" en el vector <strong>marcas<\/strong> usando <code>scipy.stats.itemfreq()<\/code> y usando la fila <strong>donde<\/strong> donde est\u00e1 la mayor cuenta usando <code>np.argmax()<\/code>.<\/p>\n\n\n\n<p>Para facilitar el an\u00e1lisis de un <strong>tono<\/strong> en una <strong>marca<\/strong>, se realiza una conversi\u00f3n a una <strong>secuencia<\/strong> binaria, usando <code>'1'<\/code> \u00f3 ,<code>'0'<\/code> si se encuentra el 'tono frecuente' en cada ventana.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Para el ejemplo, las ventanas se convierten al vector:\n&#091;1 1 1 1 1 1 0 0]<\/code><\/pre>\n\n\n\n<p>Al contar la duracion de cada intevalo, se determina si el sonido corresponde a un punto, una raya o una espacio:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ejemplo:\n. ... .--. --- .-..<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Algoritmo en python<\/h2>\n\n\n\n<p>El sonido se obtiene de un <strong>archivo.wav<\/strong> del generador de tonos para un punto <code>'.'<\/code> o raya <code>'-'<\/code>, del cual se leen los datos de <strong>sonido<\/strong>, y frecuencia de <strong>muestreo<\/strong>.<\/p>\n\n\n\n<p>Para el ejemplo, el sonido del mensaje morse:&nbsp;<a href=\"https:\/\/www.dropbox.com\/s\/co3beeya63h69we\/morsetonosESPOL.wav?dl=0\">morsetonoESPOL.wav<\/a><\/p>\n\n\n\n<p>Las funciones para cada uno de los procesos descritos se encuentran a continuaci\u00f3n<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code alignwide\"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# C\u00f3digo Morse -  Determina un mensaje desde sonido.wav\n# propuesta: edelros@espol.edu.ec\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport scipy.io.wavfile as waves\nimport scipy.fftpack as fourier\nimport scipy.stats as stats\n\ndef separaventanas(sonido, muestreo, duracion = 0.04, partes = 8 ):\n    # Divide el sonido en partes o ventanas para estudio\n    # duracion = 0.04   # segundos de un punto\n    # partes = 8        # divisiones de un punto\n    # Extraer ventanas para espectro por partes\n    tventana = duracion\/partes\n    mventana = int(muestreo * tventana) # muestras de una ventana\n\n    # Ajuste de muestras de ventanas para matriz\n    anchosonido  = int(len(sonido)\/mventana)*mventana \n    sonidoajuste = np.resize(sonido,anchosonido)\n    ventanas = np.reshape(sonidoajuste,(-1,mventana))  \n    # -1 indica que calcule las filas\n    return(ventanas)\n\ndef marcasdeventanas(ventanas, muestreo):\n    # Analiza con FFT todas las ventanas del sonido\n    filas, columnas = np.shape(ventanas)\n    marcas = np.zeros(filas,dtype=int)\n\n    # Espectro de Fourier de cada ventana\n    # frecuencias para eje frq = fourier.fftfreq(mventana, 1\/muestreo) \n    frq = fourier.fftfreq(columnas, 1\/muestreo)  \n    for f in range(0,filas,1):\n        xf = fourier.fft(ventanas&#x5B;f])\n        xf = np.abs(xf)        # magnitud de xf\n        tono = np.argmax(xf) # tono, frecuencia mayor \n        marcas&#x5B;f] = frq&#x5B;tono]\n    return(marcas)\n\ndef secuenciabinaria(marcas): \n    # Busca el tono frecuente mayor que cero\n    tonosventana = stats.itemfreq(marcas)\n    donde = np.argmax(tonosventana&#x5B;1:,1])\n    tonopunto = tonosventana&#x5B;donde+1,0]\n\n    # Convierte los tonos a secuencia binaria\n    secuencia = ''\n    for valor in marcas:\n        if (valor==tonopunto):\n            secuencia = secuencia + '1'\n        else:\n            secuencia = secuencia + '0'\n    return(secuencia)\n\ndef duracionmarcas(secuencia):\n    # Duraci\u00f3n de cada marca\n    conteo = &#x5B;]\n    caracter = '1'\n    if (len(secuencia)&gt;0):\n        caracter = secuencia&#x5B;0]\n    i = 0\n    k = 0\n    while (i&lt;len(secuencia)):\n        if (secuencia&#x5B;i]==caracter):\n            k = k + 1\n        else:\n            conteo.append(&#x5B;int(caracter),k])\n            if (caracter=='1'):\n                caracter = '0'\n            else:\n                caracter = '1'\n            k = 1\n        i = i+1\n    conteo = np.array(conteo)\n    return(conteo)\n\ndef marcasmorse(conteo):\n    # Determina la base de un tono\n    veces = stats.itemfreq(conteo&#x5B;:,1])\n    donde = np.argmax(veces&#x5B;:,1])\n    base  = veces&#x5B;donde,0]\n\n    # Genera el c\u00f3digo Morse\n    tolera = 0.2 # Tolerancia en relacion\n    bajo   = 1-tolera\n    alto   = 1+tolera\n    morse  = ''\n    for j in range(0,len(conteo)):\n        relacion = conteo&#x5B;j,1]\/base\n        simbolo  = conteo&#x5B;j,0]\n        if (simbolo==1):\n            if (relacion&gt;(1*bajo) and relacion&lt;(1*alto)):\n                morse = morse + '.'\n            if  (relacion&gt;(3*bajo) and relacion&lt;(3*alto)):\n                morse = morse + '-'\n        if  simbolo==0 :\n            if (relacion&gt;(3*bajo) and relacion&lt;(3*alto)):\n                morse = morse + ' '\n            if (relacion&gt;(7*bajo) and relacion&lt;(7*alto)):\n                morse=morse+'   '\n    return(morse)\n\n# INGRESO \n# archivo = input('nombre del archivo: ')\narchivo = 'morsetonoESPOL.wav'\nmuestreo, sonido = waves.read(archivo)\n\n# PROCEDIMIENTO\n\nventanas  = separaventanas(sonido, muestreo)\nmarcas    = marcasdeventanas(ventanas, muestreo)\nsecuencia = secuenciabinaria(marcas)\nconteo    = duracionmarcas(secuencia)\nmorse     = marcasmorse(conteo)\n\n# SALIDA\nprint('codigo en morse: ')\nprint(morse)\n<\/pre><\/div>\n\n\n<pre class=\"wp-block-code alignwide\"><code>codigo en morse: \n. ... .--. --- .-..   .. -- .--. ..- .-.. ... .- -. -.. ---   .-.. .-   ... --- -.-. .. . -.. .- -..   -.. . .-..   -.-. --- -. --- -.-. .. -- .. . -. - ---<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Revisi\u00f3n de valores en el procedimiento<\/h2>\n\n\n\n<p>Se presentan algunos de los valores intermedios para observar el proceso de detecci\u00f3n de s\u00edmbolos Morse.<\/p>\n\n\n\n<pre class=\"wp-block-code alignwide\"><code># Salida \/Observaci\u00f3n intermedia\nprint('ventanas analizadas: ',len(marcas))\nprint('marcas: ', marcas)<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>ventanas analizadas:  3287\nmarcas:  &#091;400 400 400 ...,   0   0   0]<\/code><\/pre>\n\n\n\n<p>Para facilitar el proceso de detecci\u00f3n morse se convierten las marcas a una secuencia binaria, usando como referencia la frecuencia del tono de un punto determinada en la secci\u00f3n anterior.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Salida \/Observaci\u00f3n intermedia\nif len(secuencia)&lt;100:\n    print(secuencia)\nelse:\n    print(secuencia&#x5B;0:200] + ' ... ')\n<\/pre><\/div>\n\n\n<pre class=\"wp-block-code\"><code>11111111000000000000000000000000111111110000000011111111000000001111111110000000000000000000000011111111000000001111111111111111111111111000000011111111111111111111111110000000111111111000000000000000 ... <\/code><\/pre>\n\n\n\n<p>Cambiar la secuencia a s\u00edmbolos morse, consiste en determinar la relaci\u00f3n entre las veces que aparecen los '1's y '0's, el resultado se puede guardar en un arreglo.<\/p>\n\n\n\n<p>La base de cu\u00e1ntas marcas corresponden a un punto de estima como la \"moda\" de las veces en que se repite un uno o un cero.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code alignwide\"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nprint('simbolo, cuenta:')\nprint(conteo)\n<\/pre><\/div>\n\n\n<pre class=\"wp-block-code\"><code>simbolo, cuenta:\n&#091;&#091; 1  8]\n &#091; 0 24]\n &#091; 1  8]\n &#091; 0  8]\n &#091; 1  8]\n &#091; 0  8]\n &#091; 1  9]\n &#091; 0 23]\n &#091; 1  8]\n &#091; 0  8]\n &#091; 1 25]\n &#091; 0  7]\n &#091; 1 25]\n...<\/code><\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code alignwide\"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Salida\nprint('codigo en morse: ')\nprint(morse)\n<\/pre><\/div>\n\n\n<pre class=\"wp-block-code alignwide\"><code>codigo en morse: \n. ... .--. --- .-..   .. -- .--. ..- .-.. ... .- -. -.. ---   .-.. .-   ... --- -.-. .. . -.. .- -..   -.. . .-..   -.-. --- -. --- -.-. .. -- .. . -. - ---<\/code><\/pre>\n\n\n\n<p>Con el resultado puede usar el decodificador morse de los temas anteriores.<\/p>\n\n\n\n<p><strong><em>Referencia<\/em><\/strong>: <a href=\"https:\/\/es.wikipedia.org\/wiki\/C%C3%B3digo_morse\">C\u00f3digo Morse Wikipedia<\/a>, <a href=\"https:\/\/www.itu.int\/dms_pubrec\/itu-r\/rec\/m\/R-REC-M.1677-1-200910-I!!PDF-E.pdf\"> Recommendation ITU-R M.1677-1 (10\/2009) International Morse code<\/a>, Leon-Couch, 5\u20139 Se\u00f1alizaci\u00f3n Pasabanda Modulada Binaria (OOK)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Para analizar el sonido de un mensaje Morse, se procede de forma semejante al decodificador de un tono morse, revisando la duraci\u00f3n de cada s\u00edmbolo: punto o espacio tienen duraci\u00f3n de una marca, la raya tiene una duraci\u00f3n de 3 marcas, los s\u00edmbolos se separan por una pausa con un intervalo de una marca. Se [&hellip;]<\/p>\n","protected":false},"author":8043,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"wp-custom-template-entrada-stp-ejercicios","format":"standard","meta":{"footnotes":""},"categories":[202],"tags":[],"class_list":["post-21987","post","type-post","status-publish","format-standard","hentry","category-stp-aplica"],"_links":{"self":[{"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/posts\/21987","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/users\/8043"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/comments?post=21987"}],"version-history":[{"count":4,"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/posts\/21987\/revisions"}],"predecessor-version":[{"id":24321,"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/posts\/21987\/revisions\/24321"}],"wp:attachment":[{"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/media?parent=21987"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/categories?post=21987"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.espol.edu.ec\/algoritmos101\/wp-json\/wp\/v2\/tags?post=21987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}