PAM a PSK Gráfica

Referencia: Problema 9.133 Leon-García p.574

Un proceso de modulación por fase se define como:

Y(t) = a \cos \big( 2\pi t + \frac{\pi}{2}X(t) \big)

Sea X(t) un proceso de modulación de amplitud de pulsos con valores de +1 y -1 que representan a los bits 1 y 0 como se muestra en la tabla.

dato en binario (bit) símbolo
1 +1
0 -1

Suponga que T=1, que es la duración de cada símbolo X(t).


 

Algunos datos:

De los experimentos realizados con BPSK y Delta-Sigma para entrontrar la pmf de [+1,-1], se encontró que la media del proceso era igual a 0.


a) Dibuje una muestra de la función Y(t) correspondiente a la secuencia binaria 0010110

# Problema 9.133 Leon-Garcia p.574
# PAM - Pulse Amplitude Modulation
# PSK - Phase Shift Keying
# literal a)
import numpy as np
import matplotlib.pyplot as plt

# INGRESO
# secuencia = input('secuencia binaria: ')
secuencia = '0010110'

# PROCEDIMIENTO
n = len(secuencia)
# texto a símbolos PAM
senalbit = np.zeros(n,dtype=int)
for i in range(0,n,1):
    senalbit[i] = int(secuencia[i])
    if (senalbit[i]==0):
        senalbit[i] = -1
# Señal en PAM
anchobit = 100 # muestras dentro de cada bit
senalpam = np.repeat(senalbit, anchobit)
m = len(senalpam)

# Eje de tiempo:
ti = np.arange(0,m,dtype=float)
ti = ti/anchobit

# Señal PSK
f = 1
senalpsk = np.zeros(m,dtype=float)
for i in range(0,m,1):
    fase = (np.pi/2)*senalpam[i]
    senalpsk[i] = np.cos(2*np.pi*f*ti[i] + fase)

# SALIDA Gráfica
# Señal PAM
plt.subplot(211)
plt.plot(ti,senalpam, color='g')
for k  in range(0,n,1):
    plt.vlines(k,1,-1, color= 'm', linestyles='dotted')
plt.ylabel('Señal PAM')
# Señal PSK
plt.subplot(212)
plt.plot(ti,senalpsk, color='b')
for k  in range(0,n,1):
    plt.vlines(k,1,-1, color= 'm', linestyles='dotted')
plt.ylabel('señal PSK')
plt.suptitle('Secuencia binaria PAM a PSK')
plt.show()

continua…

Correlación entre dos señales de audio

Referencia: Archivos de Audio.wav – Abrir, extraer una porción

Para comparar dos señales de sonido se puede usar la operación de correlación.

Por ejemplo, usando dos archivos.wav, se compara las partes de una canción cantada por diferentes personas. Cada parte se obtiene de los archivos señal01 y señal02 semejantes a las siguientes:

señal01: elaguacate_muestra01.wav
señal02: elaguacate_muestra02.wav

la correlación, destaca las partes en que las señales son semejantes como se muestra en la gráfica.

Tarea: Realice las observaciones y recomendaciones al proceso, realizando el ejercicio con una canción diferente a la mostrada. Use la seleccionada para otras tareas.

Instrucciones en Python

Para el algoritmo, la primera señal de menor duración, la segunda es la señal de mayor duración.

Las señáles se normalizan en el rango [0,1] previo a procesar la correlación.

Para que las gráficas sean proporcionales en el eje de tiempo, a la señal01 se aumenta valores de cero o relleno.

Puede quedar como tarea, convertir el eje x en unidades de tiempo en lugar del número de la muestra.

# analiza correlacion entre dos muestras
# supone que señal01 es más corta que señal02
# propuesta:edelros@espol.edu.ec

import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as waves

# Un canal en caso de estereo
def extraeuncanal(sonido):
    canales=sonido.shape
    cuantos=len(canales)
    canal = 0
    if (cuantos==1): # Monofónico
        uncanal=sonido[:]
    if (cuantos>=2): # Estéreo
        uncanal=sonido[:,canal]
    return(uncanal)

# PROGRAMA
# INGRESO
# archivo01 = input('archivo de sonido 01:' )
# archivo02 = input('archivo de sonido 02:' )
archivo01 = 'elaguacate_muestra01.wav'
archivo02 = 'elaguacate_muestra02.wav'

muestreo, sonido = waves.read(archivo01)
senal01 = extraeuncanal(sonido)

muestreo, sonido = waves.read(archivo02)
senal02 = extraeuncanal(sonido)

# PROCEDIMIENTO
tamano01 = len(senal01)
tamano02 = len(senal02)

# Normaliza las señales
amplitud = np.max(senal01)
senal01 = senal01/amplitud
senal02 = senal02/amplitud

# Correlación para comparar
correlacion = np.correlate(senal01,senal02, mode='same')

# SALIDA
# unifica dimensiones de señal01 y señal02
extra = np.abs(tamano01-tamano02)
relleno = np.zeros(extra,dtype=float)
senal01relleno = np.concatenate((senal01,relleno),axis=0)
plt.suptitle('Correlación(señal01,señal02)')

plt.subplot(311)
plt.plot(senal01relleno,'g', label = 'señal01')
plt.legend()

plt.subplot(312)
plt.plot(senal02,'b', label = 'señal02')
plt.legend()

plt.subplot(313)
plt.plot(correlacion,'m', label = 'correlación')
plt.legend()

plt.show()

Para extraer una porción de audio de un archivo.wav, revise las instrucciones en el tema:

Referencia: Archivos de Audio.wav – Abrir, extraer una porción

6. Morse cadena de Markov

Para el texto en código Morse obtenido en el ejercicio «Morse codificador texto», se requiere realizar la correspondiente cadena de Markov.

Se tiene como archivo de entrada: elaguacate_morse.txt

- ..- . .-. . ... -- .. .- -- --- .-. 
-- .. -.. .. -.-. .... .- -.-- -- .. - . ... --- .-. --- 
-- .. ... --- .-.. --- . -. -.-. .- -. - --- 
-.-- -- .. .. .-.. ..- ... .. --- -. .-.-.-
  1. Determine el espacio de estados: S= {…}
  2. Realice el diagrama de transición de estados.
  3. Realice el conteo correspondiente de las transiciones entre estados
  4. Elabore la matriz de transición usando el resultado anterior
  5. Ubique en el diagrama los valores correspondientes a las transiciones
  6. Encuentre la matriz de transición en estado estable, o largo plazo.
  7. Compare los resultados de estado estable con la pmf obtenida en el ejercicio «Morse codificador texto»
  8. Presente las observaciones
  9. Escriba las recomendaciones.

Instrucciones en Python

Un ejemplo de instrucciones para realizar el conteo de las transiciones.

# Matriz de transicion de Código Morse
# Tarea: Realizar la matriz de transición
# para la cadena de Markov
import numpy as np

# INGRESO
narchivo = 'elaguacate_morse.txt'
archivo  = open(narchivo, 'r')

# PROCEDIMIENTO
s = '.- '
n = len(s)
conteo = np.zeros(shape=(n,n), dtype=int)
linea  = archivo.readline()
while not(linea ==''):
    linea = linea.strip('\n')
    m = len(linea)
    for i in range(0,m-1,1):
        simbolo = linea[i]
        simbolosigue = linea[i+1]
        f = s.find(simbolo)
        c = s.find(simbolosigue)
        conteo[f,c] = conteo[f,c] +1
    
    print(linea)
    linea = archivo.readline()

# SALIDA
print('matriz de conteo: ')
print('   .   -  espacio')
print(conteo)

Resultado del algoritmo

matriz de conteo: 
   .   -  espacio
[[123 116 145]
 [100  93 123]
 [156  92 102]]

5. Morse codificador texto

Para la transmisión de texto, por ejemplo la letra de una canción, se puede codificar a Morse usando inicialmente el procedo de los ejemplos anteriores.

Por ejemplo, una parte del archivo origen: elaguacate_Letra.txt

Tu eres mi amor 
mi dicha y mi tesoro 
mi sólo encanto 
y mi ilusión.

se convertiría en: elaguacate_morse.txt

- ..- . .-. . ... -- .. .- -- --- .-. 
-- .. -.. .. -.-. .... .- -.-- -- .. - . ... --- .-. --- 
-- .. ... --- .-.. --- . -. -.-. .- -. - --- 
-.-- -- .. .. .-.. ..- ... .. --- -. .-.-.-

que puede ser guardado en otro archivo  y procesado como un proceso estocástico.

Hay que considerar que en la codificación estandar Morse, no existen las letras con tíldes (‘áéíóú’) que para la transmisión se debe quitar las tildes.


Funciones complementarias

Se usa como función básica como codificador Morse la descrita en el problema básico.

Cuando el tema a tratar es un texto más largo, se abordan más detalles del procesamiento del texto, como el quitar las tildes antes de codificar la letra. En el estándar de la codificación Morse (origen en inglés) no se usaban las tildes en las letras, para ésta operación se usa la funcion quitatildes().

Como complemento se añaden las funciones de codificación por línea, otra función para el conteo de símbolos,

La codificación en python usada para el ejemplo se adjunta:

# Código Morse -  codificador de texto
# propuesta: edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt

def morsecodec(caracter):
    equivale={
        'A':'.-', 'B':'-...', 'C':'-.-.', 
        'CH':'----', 'D':'-..', 'E':'.', 
        'F':'..-.', 'G':'--.', 'H':'....', 
        'I':'..', 'J':'.---', 'K':'-.-',
        'L':'.-..', 'M':'--', 'N':'-.', 
        'Ñ':'--.--', 'O':'---', 'P':'.--.', 
        'Q':'--.-', 'R':'.-.', 'S':'...', 
        'T':'-', 'U':'..-', 'V':'...-',
        'W':'.--', 'X':'-..-', 'Y':'-.--', 
        'Z':'--..',
        '0':'-----', '1':'.----', '2':'..---', 
        '3':'...--', '4':'....-', '5':'.....', 
        '6':'-....', '7':'--...', '8':'---..', 
        '9':'----.', 
        '.':'.-.-.-', ',':'-.-.--', '?':'..--..', 
        '"':'.-..-.', '!':'--..--', ' ':' '}
    # Si caracter no está en equivale
    codigo = caracter
    # codifica a morse
    caracter = caracter.upper()
    if (caracter in equivale):
        codigo = equivale[caracter]    
    return(codigo)

def quitatildes(linea):
    sintilde = {'á':'a', 'é':'e', 'í':'i',
                'ó':'o', 'ú':'u'}
    nueva = ''
    for caracter in linea:
        if (caracter in sintilde):
            caracter = sintilde[caracter]
        nueva = nueva + caracter
    return(nueva)

def morselinea(linea):
    linea = linea.strip('\n')
    linea = linea.strip(' ')
    linea = quitatildes(linea)
    lineamorse = ''
    for caracter in linea:
        enmorse = morsecodec(caracter)
        lineamorse = lineamorse + enmorse + ' '
    return(lineamorse)

def cuentasimbolo(texto,simbolos):
    k = len(simbolos)
    veces = np.zeros(k,dtype=int)
    n = len(texto)
    for fila in range(0,n,1):
        unalinea = texto[fila]
        unalinea = unalinea.strip('\n')
        m = len(unalinea)
        for caracter in unalinea:
            donde = simbolos.find(caracter)
            if (donde>=0): #Si no encuentra es negativo
                veces[donde] = veces[donde]+1
    total = np.sum(veces)
    return(veces)

# PROGRAMA -----------------------------

# INGRESO
nombrearchivo = 'elaguacate_Letra.txt'

# PROCEDIMIENTO
# procesa el archivo
archivo  = open(nombrearchivo,'r')
unalinea = archivo.readline()
codificado = []
while not(unalinea==''):
    unalinea = unalinea.strip('\n')
    unalinea = unalinea.lower()
    lineamorse = morselinea(unalinea)
    codificado.append(lineamorse)
    unalinea = archivo.readline()
archivo.close()

# cuenta símbolos
simbolos = '.- '
conteo   = cuentasimbolo(codificado,simbolos)
total    = np.sum(conteo)
pmf      = conteo/total

# SALIDA
print('Texto en morse: ')
n = len(codificado)
etiquetas = ['punto','raya','espacio']
for i in range(0,n,1):
    print(codificado[i])

# PMF
print('PMF')
print(etiquetas)
print(pmf)

# GRAFICA
x = np.arange(0,len(conteo),1)
plt.stem(x,pmf)
plt.xticks(x,etiquetas)
plt.title('pmf')
plt.show()

# ARCHIVO
narchivo = 'morsetexto.txt'
archivo  = open(narchivo,'w')
for i in range(0,n,1):
    linea = codificado[i]+'\n'
    archivo.write(linea)
archivo.close()

Al final se presenta la pmf, sus valores y gráficas, junto al archivo morsetexto.txt como resultado.

PMF
['punto', 'raya', 'espacio']
[ 0.3588785   0.2953271   0.34579439]

Tarea: Procese los datos necesarios para generar la función de distribución acumulada (cdf), el valor esperado, varianza y desviación estándar.

Realice las observaciones y recomendaciones necesarias para mejorar el algoritmo que haya encontrado al usar su propio texto.

Alfabeto Matriz Transición

Referencia: Ross 2.2 p25, Telex, TTY o teletipo(Wikipedia)

Funciones de Matriz de transición de alfabeto

Es posible determinar la matriz de transición entre las letras del alfabeto continuando con el ejercicio de Funciones de probabilidad o masa.

Para procesar el texto se usa como entrada un archivo en formato .txt, analizando por línea, por símbolo y contando las veces que hay transición desde una letra del alfabeto.

Nota: Considere solo el total de letras, no el total de símbolos (no incluye «,;.!?» etc.)

El resultado que se obtiene es la matriz en los archivo adjuntos:

transicionesletras.txt

transicionesletrasfreq.txt

pueden ser importados para otro algoritmo, programa u hoja electrónica

matriz de conteo: 
[[   1 318 440 874   14  31  56  59    8  20  0 729 314  631 27   0   78   43  749  745  210  85  64  1  27 67 38]
 [ 134   0   0   0   86   0   0   0  153   8  0 184   0    2  0  56    0    0  167   67    3  40   0  0   0  1  0]
 [ 427   0  69   0  318   1   0 135 1064   0  2  63   0    0  0 877    0    0   82    0  174 394   0  0   0  0  0]
 [ 677   0   0   0 1872   0   8   1  513   1  0   1  20    0  0 689    0    2   36    0    4  71   5  0   0  0  0]
 [ 155  82 416 229   12  53 134   3   21  60 17 655 340 1921 12  34  112   18 1328 1479  138  27  61 24 139 37 40]
 [  45   0   0   0  111   0   0   0  194   0  0  18   0    0  0  48    0    0   25    0    0 160   0  0   0  0  0]
 [  90   0   0   0  104   0   1   0  108   0  1  22   2   30  0 114    0    0  105    2    1 146   0  0   0  0  0]
 [ 261   0   0   0   99   0   0   0   15   0  0   0   3    3  0 183    0    0    1    1    7  42   0  1   0  0  0]
 [ 499 165 439 546  473 123 155   3    0   6  0 143 371  778  4 326   60   12  281  326  285   2 162  0   1  0 37]
 [  29   0   0   0   48   0   0   0    6   0  0   0   0    0  0  46    0    0    0    0    0  29   0  0   0  0  0]
 [  19   0   0   0   12   0   0   0    0   0  0   0   0    0  0   1    0    0    0    0    0   0   0  0   0  0  0]
 [1299   0  19  20  513   3  53   0  281   0  1 172  46    2  0 560    5   28    4   27   97 152  12  0   0  3  0]
 [ 379  80   0   0  531   0   0   0  374   0  0   0   6    2  0 588  312    0   12    1    1  66   0  0   0  1  0]
 [ 501   2 447 379  361  63  86   0  385   6  1   0  33   13  0 541    1   16    2  214 1034 100  38  1   0  0 34]
 [  20   0   0   0    3   0   0   0    0   0  0   0   0    0  0  22    0    0    0    0    0   0   0  0   0  0  0]
 [   0 108 116 197   43  28  54   4   10  12  0 165 404  768  3   0  125    2  628 1356   97   6  18  0   5 11  5]
 [ 334   0  32   0  310   0   0   2  116   0  0 193   0    0  0 560    1    0  412    1   29 222   0  0   0  0  0]
 [   0   0   0   0    0   0   0   0    0   0  0   0   0    0  0   0    0    0    0    0    0 692   0  0   0  0  0]
 [1058  16  74 111  774  22  57   0  486   1  1  40  93   35  0 522   21   13  105  129  191  39  24  0   0  3 51]
 [ 306   2 118  31  576  40   0   2  694   0  2   2  92    0  0 333  150    5    0    4  731 374   2  1   0  0  0]
 [ 840   0   4   0  954   0   1   8  429   0  0   3   0    3  0 771    0    0  475    1    6 150   0  0   0  0  4]
 [ 232  50 100  54  976   9  25   1  134   5  0 166  82  758  0  12   69    0  115  166   83   0   9  0   0 38  9]
 [ 112   0   0   0  272   0   0   0  168   0  0   0   0    0  0  68    0    0    1    0    0  10   0  0   0  0  0]
 [   0   0   0   0    9   0   0   0    1   0  0   0   0    0  0   0    0    0    0    1   21   0   0  0   0  0  0]
 [  14   0  13   0    0   0   0   0   81   0  0   0   0    0  0   0   46    0    0    0   21   0   0  0   0  0  0]
 [  33   0   0   0   22   0   0   0    0   0  0   0   0    2  0  36    0    0    0    0    0   2   0  0   0  0  0]
 [ 117   0   7   0    0   0   3   0    0   0  0   0   0    0  0  22    0    0    0    0    2   3   0  0   0  0  0]]
matriz de conteo:
[[  1.77e-04  5.64e-02  7.81e-02  1.55e-01   2.48e-03  5.50e-03  9.94e-03  1.04e-02   1.42e-03  3.55e-03  0.00e+00  1.29e-01   5.57e-02  1.12e-01  4.79e-03  0.00e+00   1.38e-02  7.63e-03  1.33e-01  1.32e-01   3.73e-02  1.51e-02  1.13e-02  1.77e-04   4.79e-03  1.19e-02  6.75e-03]
 [  1.48e-01  0.00e+00  0.00e+00  0.00e+00   9.54e-02  0.00e+00  0.00e+00  0.00e+00   1.69e-01  8.87e-03  0.00e+00  2.04e-01   0.00e+00  2.21e-03  0.00e+00  6.21e-02   0.00e+00  0.00e+00  1.85e-01  7.43e-02   3.32e-03  4.43e-02  0.00e+00  0.00e+00   0.00e+00  1.10e-03  0.00e+00]
 [  1.18e-01  0.00e+00  1.91e-02  0.00e+00   8.81e-02  2.77e-04  0.00e+00  3.74e-02   2.95e-01  0.00e+00  5.54e-04  1.74e-02   0.00e+00  0.00e+00  0.00e+00  2.43e-01   0.00e+00  0.00e+00  2.27e-02  0.00e+00   4.82e-02  1.09e-01  0.00e+00  0.00e+00   0.00e+00  0.00e+00  0.00e+00]
 ...
 [  7.59e-01  0.00e+00  4.54e-02  0.00e+00   0.00e+00  0.00e+00  1.94e-02  0.00e+00   0.00e+00  0.00e+00  0.00e+00  0.00e+00   0.00e+00  0.00e+00  0.00e+00  1.42e-01   0.00e+00  0.00e+00  0.00e+00  0.00e+00   1.29e-02  1.94e-02  0.00e+00  0.00e+00   0.00e+00  0.00e+00  0.00e+00]]

Instrucciones en Python

# procesar un archivo de texto
# Determinar la matriz de transición
# para las letras del alfabeto(incluye ñ)
import numpy as np

# INGRESO
# archivo=input('archivo a leer.txt: ')
nombrearchivo =' eureka_poe_edgar_allan.txt'

# PROCEDIMIENTO
alfabeto = 'abcdefghijklmnñopqrstuvwxyz'
k = len(alfabeto)
matriz     = np.zeros(shape=(k,k),dtype=int)
transicion =
np.zeros(shape=(k,k),dtype=float)
total = 0

# procesa el archivo
archivo  = open(nombrearchivo,'r')
unalinea = archivo.readline()
while not(unalinea == ''):
    unalinea = unalinea.strip('\n')
    unalinea = unalinea.lower()
    m = len(unalinea)
    for j in range(0,m-1,1):
        unsimbolo = unalinea[j]
        donde = alfabeto.find(unsimbolo)
        siguiente = unalinea[j+1]
        dondesig  = alfabeto.find(siguiente)
        if (donde>=0 and dondesig>=0):
            #Si no encuentra es negativo
            matriz[donde][dondesig] = matriz[donde][dondesig]+1
            total = total + 1
    unalinea = archivo.readline()
archivo.close()

# Determina matriz de transicion
for i in range(0,k,1):
    suma = np.sum(matriz[i,:])
    transicion[i]=matriz[i,:]/suma

# Salida
print('matriz de conteo: ')
print(matriz)
print('matriz de transición:')
print(transicion)
np.savetxt('transicionletras.txt',matriz, fmt='%d')
np.savetxt('transicionletrasfreq.txt',transicion)

Convertidor Analógico Digital

Ejemplo: León-García 4.20 p.161
Un cuantizador se usa para convertir una señal analógica (ejemplo: audio) en su forma digital.

Un cuantizador crea un mapa de un voltaje aleatorio X en el punto más próximo q(X) a los valores 2R  representados como se muestra en la figura.

El valor de X se aproxima por q(X), el que se identifica con un número binario de R-bits. De esta forma, un voltage «analógico» X , que toma valores contínuos se convierte a un numero de R-bits.

El cuantizador introduce un error Z = X –  q(X) como se muestra en la figura (b). Note que Z es una función de X y cuyo rango está entre -d/2 y d/2, conocido como el tamaño de paso del cuantizador.

Suponga que X tiene una distribución uniforme en el intervalo [-xmax, xmax], que el cuentizador tiene 2R niveles, y que 2xmax = 2Rd.
Es sencillo mostrar que > está uniformemente distribuido en el intervalo [-d/2, d/2].

Se tiene que para una variable uniforme:
E[X]= \frac{1}{b-a}\int_{a}^{b}t dr = \frac{a+b}{2}
E[z] = \frac{d/2 - d/2}{2} = 0
El error Z tiene media cero.
La varianza es:
VAR[Z] =\frac{(d/2 - (-d/2)^2}{12} =\frac{d^2}{12}
El resultado es aproximadamente correcto para cualquier pdf que sea aproximadamente plana sobre un intervalo del cuantizador. Es el caso cuando 2R es grande.

La aproximación de q(x) puede ser observada como una versión «ruidosa» de X, dado que:
Q(Z) = X-Z
donde Z es el error de cuantización, Una medida de cuán bueno es el cuantizador se da por el factor SNR o de señal ruido, que se define como la fracción entre la varianza de la «señal» X para la varianza de la distorción de «ruido» Z:

\text{SNR} = \frac{VAR[X]}{VAR[Z]} = \frac{VAR[X]}{d^2 /12}
= \frac{VAR[X]}{x_{max}^2 /3} 2^{2R}
donde se ha usado el hecho que d= 2xmax/ 2R.
Cuando X es no uniforme, el valor de xmax se seleccciona de tal forma que P[|X|> xmax] sea pequeña. Un casi tipico es que xmax = 4 STD[X], con lo que SNR será:
\text{SNR} = \frac{3}{16} 2^{2R}
lo que es genera la formula conocida como:
\text{SNR dB} = 10 log_{10} \text{SNR} = 6R-7.3 dB

En otras palabras, el nivel de SNR se incrementa por un factor de 4 (6db) con cada bit adicional que se usa para representar X. Esto tiene sentido dado que cada bit duplica el número de niveles de cuantización, lo cual reduce el tamaño de paso por un factor de 2. La varianza del error podría ser reducida por el cuadrado de ésto, es decir 22=4

cdf – una señal de sonido

Referencia: Leon W Couch apéndice B p675, «El Aguacate», pasillo introducción, Archivos de Audio.wav – Abrir, extraer una porción

De forma semejante al análisis para una señal triangular, se obtiene barriendo una ventana estrecha de Δx voltios de ancho, verticalmente a lo largo de las formas de onda y después midiendo la frecuencia relativa de la ocurrencia de voltajes en la ventana Δx.

El eje de tiempo se divide en n intervalos y la forma de onda aparece nΔx veces dentro de estos intervalos en la ventana Δx.

Se inicia abriendo el archivo 'muestra01_ElAguacateIntro.wav', seleccionando un canal en caso de ser estéreo. Para los cálculos se convierte a números reales ‘float’ de tipo estándar de python y para la gráfica se determina el rango de tiempo 't'.

# pmf de un sonido
# entrada es arcchivo01
# propuesta:edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as waves
import scipy.stats as stats

# INGRESO 
# archivo01 = input('archivo de sonido 01:' )
archivo01 = 'muestra01_ElAguacateIntro.wav'

# PROCEDIMIENTO
muestreo, sonido01 = waves.read(archivo01)

# Extrae un canal en caso de estéreo
canales=np.shape(sonido01)
cuantos=len(canales)
canal = 0   
if (cuantos==1): # Monofónico
    uncanal=sonido01[:]  
if (cuantos>=2): # Estéreo
    uncanal=sonido01[:,canal]
    
senal=uncanal.astype(float)
dt=1/muestreo
n=len(senal)
t=np.arange(0,n*dt,dt)

Se grafica la señal en observación de uncanal:

# SALIDA GRAFICA
plt.plot(t,senal)
plt.title(' Sonido')
plt.xlabel('t')
plt.ylabel('señal')
plt.plot()
plt.show()


Aplicando luego el mismo algoritmo usado para señales triangulares y senoidales, manteniendo la forma discreta.

# Función de Probabilidad de Masa, PMF
m=40  # intervalos eje vertical

#PROCEDIMIENTO
relativa = stats.relfreq(senal, numbins = m )
deltax=relativa.binsize

# Eje de frecuencias, por cada deltax
senalmin=np.min(senal)
senalmax=np.max(senal)
senalrango=np.linspace(senalmin,senalmax,m)

# SALIDA
print('frecuencia relativa:')
print(relativa.frequency)
print('Rango de Señal')
print(senalrango)
frecuencia relativa:
[ 0.00023583  0.00073469  0.00089796  0.00053515  0.00084354  0.00179592  0.00245805  0.00306576  0.0039093   0.00504308  0.0066576   0.0099229  0.01693424  0.02671202  0.03568254  0.05160998  0.06758277  0.07323356  0.08575057  0.09217234  0.11898413  0.08494331  0.07535601  0.06454422  0.05382313  0.03821315  0.02429932  0.01573696  0.01075737  0.00767347  0.00576871  0.00365533  0.00245805  0.00176871  0.00145125  0.00103401  0.0008254   0.00106122  0.00137868  0.0004898 ]
Rango de Señal
[-32768.         -31087.61538462 -29407.23076923 -27726.84615385 -26046.46153846 -24366.07692308 -22685.69230769 -21005.30769231 -19324.92307692 -17644.53846154 -15964.15384615 -14283.76923077 -12603.38461538 -10923.          -9242.61538462  -7562.23076923  -5881.84615385  -4201.46153846  -2521.07692308   -840.69230769    839.69230769   2520.07692308   4200.46153846   5880.84615385   7561.23076923   9241.61538462  10922.          12602.38461538  14282.76923077  15963.15384615  17643.53846154  19323.92307692  21004.30769231  22684.69230769  24365.07692308  26045.46153846  27725.84615385  29406.23076923  31086.61538462  32767.        ]
# SALIDA Grafico de PMF
plt.bar(senalrango,relativa.frequency, width=deltax*0.8)
plt.xlabel('Amplitud de señal')
plt.ylabel('PMF')
plt.show()

# Función distribución acumulada
acumulada=np.cumsum(relativa.frequency)

# SALIDA CDF
plt.step(senalrango,relativa.frequency,label='pmf', where='post')
plt.step(senalrango,acumulada,label='cdf', where='post')
plt.xlabel('Amplitud de señal')
plt.title(' Función de distribuión acumulada , CDF')
plt.legend()
plt.show()

Para grabar los archivos puede usar np.savetxt(‘nombrearchivo.txt’, arreglodata )

PMF – Teclado Qwerty

Referencia: Teclado Qwerty Wikipedia

Uso del teclado QWERTY

El nombre del teclado QWERTY proviene de las primeras seis letras de su fila superior, fue diseñado y patentado por Christopher Sholes en 1868 y vendido a Remington en 1873.

La distribución QWERTY se diseñó con objetivo de separar las letras más usadas de la zona central del teclado, para evitar que se atascaran las máquinas de escribir de primera generación. Actualmente, ésta propiedad no es más requerida, sin embargo se ha heredado la distribución en los teclados de computadora.

A partir de la frecuencia de uso de las letras del alfabeto, se requiere conocer la frecuencia de uso de cada fila del teclado. Los valores de frecuencia para cada letra se encuentran en el archivo: usoletras.txt que por cada línea registra la letra y frecuencia relativa separadas por una coma ‘,’.

archivo: usoletras.txt:
a, 0.11422682511 
b, 0.0118959769969 
c, 0.0464006717728 
d, 0.0543525280541 
...

Algoritmo en Python

# Analiza teclado QWERTY
# Datos desde Archivo 'usoletras.txt'
import numpy as np

# Ingreso
narchivo = input('Nombre del archivo:')
veces    = []
archivo  = open(narchivo,'r')
linea    = archivo.readline()
while not(linea == ''):
    partes = linea.split(',')
    letra  = partes[0]
    frecuencia = float(partes[1])
    veces.append([letra,frecuencia])
    linea = archivo.readline()
archivo.close()

# PROCEDIMIENTO
superior = 'qwertyuiop'
media    = 'asdfghjklñ'
inferior = 'zxcvbnm'
k = len(veces)
usofila = np.zeros(3,dtype=float)
for i in range(0,len(veces),1):
    if (veces[i][0] in superior):
        usofila[0] = usofila[0]+veces[i][1]
    if (veces[i][0] in media):
        usofila[1] = usofila[1]+veces[i][1]
    if (veces[i][0] in inferior):
        usofila[2] = usofila[2]+veces[i][1]

# SALIDA
print(usofila)

resultado:

[ 0.48999975  0.32815084  0.18184941]

La gráfica para pmf se obtiene al añadir las instrucciones:

# GRAFICA
% matplotlib inline
import matplotlib.pyplot as plt
plt.stem([0,1,2],usofila)
plt.title('PMF filas teclado QWERTY')
plt.xlabel('fila superior, media e inferior')
plt.show()

Tarea: En cada caso, realice la gráfica de funciones de probabilidad de masa (pmf) y la función de probabilidades acumulada (cdf)

  • Encuentre la frecuencia de uso de cada mano, presente la división propuesta de el teclado en dos partes: izquierda y derecha.
  • Realice el ejercicio para determinar la frecuencia de uso de cada dedo de cada mano. Presente un modelo gráfico de cada tecla, para mostrar de mejor forma la medida a obtener
  • con los resultados de éste ejercicio, considere llenar la siguiente tabla:
    mano izquierda mano derecha total fila
    superior
    media
    inferior
    total mano

PMF – Alfabeto

Referencia: Ross 2.2 p25, Telex, TTY o teletipo(Wikipedia)

Funciones de probabilidad de masa para alfabeto

Para el «TELEX», «TTY», «teletype» o sistema de tranmisión/recepción de mensajes de texto mecanografiados, al desconocer el contenido del mensaje se podría considerar que cada letra presenta un comportamiento aleatorio. Se puede intuir que hay letras que son poco comunes como ‘x’ y otras muy comunes como ‘e’.

Para el modelo se requiere estimar función de probabilidad de masa (pmf), tomando como base solo el alfabeto incluyendo la letra ‘ñ’, sin discriminar mayúsculas y minúsculas.

Para un ensayo, se usaría un texto con una cantidad considerable de letras, como por ejemplo una obra literaria.

Por ejemplo: ‘elaguacate_Letra.txt

Referencia: https://achiras.net.ec/el-aguacate-un-pasillo-ecuatoriano-sin-tiempo/

Para procesar el texto se usa como entrada un archivo en formato .txt, analizando por línea, por símbolo y contando las veces que aparece cada letra del alfabeto. La frecuencia relativa de cada letra respecto al total de letras, permitirá visualizar la forma de la función probabilidad de masa (pmf) para el alfabeto.

Nota: Considere solo el total de letras, no el total de símbolos (no incluye «,;.!?» etc.)

Algoritmo en Python

# procesar un archivo de texto
# Determinar la función de probabilidad de masa
# para las letras del alfabeto(incluye ñ)
import numpy as np

# INGRESO
# archivo=input('archivo a leer.txt: ')
nombrearchivo='elaguacate_Letra.txt'

# PROCEDIMIENTO
alfabeto='abcdefghijklmnñopqrstuvwxyz'
k=len(alfabeto)
veces=np.zeros(k,dtype=int)
total=0
# procesa el archivo
archivo = open(nombrearchivo,'r')
unalinea = archivo.readline()
while not(unalinea==''):
    n=len(unalinea)
    unalinea = unalinea.strip('\n')
    unalinea = unalinea.lower()
    m=len(unalinea)
    for j in range(0,m,1):
        unsimbolo=unalinea[j]
        donde = alfabeto.find(unsimbolo)
        if (donde>=0): #Si no encuentra es negativo
            veces[donde]=veces[donde]+1
            total=total+1
    unalinea = archivo.readline()
archivo.close()

frelativa=veces/total
alfa=np.arange(0,len(alfabeto))

# SALIDA
print('Letras contadas: ', total)
print('i,letra,veces,frelativa')
for i in range(0,len(alfabeto),1):
    print(i, alfabeto[i],veces[i], frelativa[i])

el resultado obtenido es:

Letras contadas:  253
i,letra,veces,frelativa
0 a 25 0.098814229249
1 b 1 0.00395256916996
2 c 5 0.0197628458498
3 d 7 0.0276679841897
4 e 25 0.098814229249
5 f 4 0.0158102766798
6 g 0 0.0
7 h 2 0.00790513833992
8 i 22 0.0869565217391
9 j 1 0.00395256916996
10 k 0 0.0
11 l 15 0.0592885375494
12 m 15 0.0592885375494
13 n 20 0.0790513833992
14 ñ 0 0.0
15 o 24 0.0948616600791
16 p 4 0.0158102766798
17 q 3 0.0118577075099
18 r 16 0.0632411067194
19 s 21 0.0830039525692
20 t 16 0.0632411067194
21 u 16 0.0632411067194
22 v 3 0.0118577075099
23 w 0 0.0
24 x 0 0.0
25 y 7 0.0276679841897
26 z 1 0.00395256916996

para la gráfica se añade al algoritmo:

# GRAFICA
% matplotlib inline
import matplotlib.pyplot as plt
plt.stem(alfa,frelativa)
plt.title('PMF alfabeto')
plt.xlabel(alfabeto)
plt.show()


otro experimento realizado con:
Poe, Edgar Allan. Eureka. Vol. 13. EDAF, 2006.

tiene el siguiente resultado:

Letras contadas:  78598
i,letra,veces,frelativa
0 a 8978 0.11422682511
1 b 935 0.0118959769969
2 c 3647 0.0464006717728
3 d 4272 0.0543525280541
4 e 10455 0.133018651874
5 f 658 0.00837171429298
6 g 818 0.010407389501
7 h 632 0.00804091707168
8 i 5792 0.0736914425303
9 j 161 0.00204839817807
10 k 36 0.000458026921805
11 l 4203 0.0534746431207
12 m 2541 0.0323290668974
13 n 6126 0.0779409145271
14 ñ 46 0.000585256622306
15 o 6725 0.0855619735871
16 p 2271 0.0288938649838
17 q 692 0.00880429527469
18 r 4899 0.0623298302756
19 s 5988 0.0761851446602
20 t 3792 0.0482455024301
21 u 3362 0.0427746253085
22 v 647 0.00823176162243
23 w 34 0.000432580981704
24 x 177 0.00225196569887
25 y 491 0.00624697829461
26 z 220 0.00279905341103

Será necesario que realizar el experimento muchas veces para tener un comportamiento más general, se propone realizar al estudiante su experimento con otros textos.

Con los resultados, se requiere:

  1. Realizar la pmf para vocales
  2. Realizar la pmf para consonantes
  3. determine las letras con menor probabilidad de cada grupo
  4. escriba alguna recomendación para mejorar el experimento
  5. escriba al menos una conlusión

Considere lo siguiente:

Si en una transmisión de texto, por ruido en el canal se cambian aleatoriamente algunos caracteres,

  • ¿Cuáles cambios serían los que afectan menos al mensaje?
  • ¿Cuáles cambios serían los que afectan más al mensaje?

En caso de presentar el resultado de frecuencias relativas en un archivo:

# Archivo
narchivo='usoletras.txt'
archivo=open(narchivo,'w')
for i in range(0,k,1):
    linea=alfabeto[i]+','+str(frelativa[i])+'\n'
    archivo.write(linea)
archivo.close()

Sigma-Delta Decodificador con Python

Referencia: Leon-Couch, 3–8 Modulación Delta, p.192 ; Delta-sigma_modulation Wikipedia, Sigma-Delta – Modulación

La señal de entrada para el decodificador es la señal codificada en los archivo.txt del ejemplo anterior:

deltasigma_datos.txt, deltasigma_parametros.txt

Los archivos para ser leidos deben copiarse al directorio donde se encuentra el algoritmo.py.

Los parametros obtenidos del archivo.txt son:

  • ΔY = deltaY = datos[1]
  • Δt = datos[0]
  • muestras en el rango de observación: k como tamaño del arreglo yentrada.

DeltaSigma_Decodificador

% matplotlib inline
# Modulacion Sigma-Delta Decodificador
#  entrada y[n], salida: x[n]
# propuesta:edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as waves

# INGRESO - Lectura de datos desde archivos
# archivoparam = intput('archivo.txt de parametros: ')
# archivodatos = input('archivo.txt de datos: ')
# arhivoaudio = input('archivo.wav a grabar: ')

archivoparam = 'deltasigma_parametros.txt'
archivodatos = 'deltasigma_datos.txt'
archivoaudio = 'sigmadeltaaudio.wav'

param = np.loadtxt(archivoparam,dtype=float)
yentrada = np.loadtxt(archivodatos,dtype=int)

Decodificar la señal +1 y -1 en el vector yentrada consiste en acumular los valores de la secuencia en xdigital usando escalones de tamaño deltaY.

Se procede de forma semejante para los tiempos td usados para el eje de las abscisas usando pasos deltaT.

# PROCEDIMIENTO
deltaT = param[0] # Tamaño delta en eje tiempo
deltaY = param[1] # Tamaño delta en eje Y
k = len(yentrada) # número de muestras
xdigital = np.zeros(k, dtype='int16')
punto = np.zeros(k, dtype=int)      # número de muestras
td = np.zeros(k, dtype=float)    # tiempo muestreo

# DECOdifica Sigma-Delta
xdigital[0] = yentrada[0]
punto[0] = 0
td[0] = 0
for i in range(1,k):
    punto[i] = i
    td[i] = deltaT*i
    xdigital[i] = xdigital[i-1]+yentrada[i]*deltaY

El resultado puede ser observado en los vectores, en una gráfica de los vectores y en un archivoaudio.wav.

# SALIDA
print('entrada: ')
print(yentrada)
print('salida: ')
print(xdigital)
entrada: 
[ 0  1 -1  1 -1  1  1 -1  1 -1  1  1 -1  1 -1  1 -1  1  1 -1  1 -1  1 -1  1 -1  1 -1  1 -1  1 -1  1 -1 -1  1 -1  1 -1  1 -1 -1  1 -1  1 -1 -1  1 -1  1 -1 -1  1 -1  1 -1 -1  1 -1  1 -1 -1  1 -1  1 -1  1 -1 -1  1 -1  1 -1  1 -1  1 -1  1 -1  1 -1  1 -1  1  1 -1  1 -1  1]
salida: 
[     0   6801      0   6801      0   6801  13602   6801  13602   6801   13602  20403  13602  20403  13602  20403  13602  20403  27204  20403 27204  20403  27204  20403  27204  20403  27204  20403  27204  20403  27204  20403  27204  20403  13602  20403  13602  20403  13602  20403  13602   6801  13602   6801  13602   6801      0   6801      0   6801  0  -6801   0  -6801      0  -6801 -13602  -6801 -13602  -6801  -13602 -20403 -13602 -20403 -13602 -20403 -13602 -20403 -27204 -20403  -27204 -20403 -27204 -20403 -27204 -20403 -27204 -20403 -27204 -20403  -27204 -20403 -27204 -20403 -13602 -20403 -13602 -20403 -13602]
# Graficar
plt.figure(1)       # define la grafica
plt.suptitle('Decodifica Delta-Sigma')

plt.subplot(211)    # grafica de 2x1 y subgrafica 1
plt.ylabel('entrada: y[n]')
plt.axis((0,k-1,-1.1,1.1)) # Ajusta ejes
plt.step(punto,yentrada, where='post')

plt.subplot(212)    # grafica de 2x1 y subgrafica 2
plt.ylabel('salida: x[t]')
xmax = np.max(xdigital)+0.1*np.max(xdigital)# rango en el eje y
xmin = np.min(xdigital)-0.1*np.max(xdigital)
plt.axis((0,td[k-1],xmin,xmax)) # Ajusta ejes
plt.step(td,xdigital, where='post', color='m')

plt.show()

Archivo de Audio del decodificador

Para crear el archivo de audio que permita escuchar el resultado del decodificador, se utiliza una instrucción de scipy que require:

  • el nombre del archivoaudio.wav: ‘sigmadeltaaudioruido.wav’
  • la frecuencia de muestreo del sonido: muestreo
  • el arreglo con la señal digital reconstruida: xdigital

El archivo.wav creado puede ejecutarse con windows media player:
sigmadeltaaudio440Hz_1s.wav

# Salida
# Archivo de audio.wav
muestreo = int(1/deltaT)
waves.write(archivoaudio, muestreo, xdigital)
print(' ... ' + archivoaudio + ' ...')
... sigmadeltaaudio.wav ...

windowsmediaplayer