Python

You are currently browsing articles tagged Python.

A veces necesitamos instalar librerías de Python que dependen de librerías externas. En el caso de estar trabajando con Mac, una de las opciones más populares para instalar librerías adicionales es MacPorts. El problema viene cuando las librerías de Python no detectan bien las librerías instaladas por MacPorts.

Una de las opciones más sencillas que puede funcionar, dependiendo del caso, es decirle directamente al compilador la localización de las cabeceras y las librerías. Por ejemplo:

CPPFLAGS="-I/opt/local/include" LDFLAGS="-L/opt/local/lib" python setup.py install --user

(gracias por esta pista)

El último caso en el que me he visto obligado a hacer esto es con la interesante librería Cartopy que requiere GEOS. Como el proyecto es un poco joven aún, parece que no tienen aún pulidos los detalles para la instalación en un Mac. Con el comando anterior la librería compila y se instala sin problema.

Un último detalle. La opción –user de la línea anterior le indica a Python que instale la librería solo para el usuario. Los ejecutables se instalan en ~/Library/Python/2.7/bin/ y las librerías en ~/Library/Python/2.7/lib. Esto es una practica muy aconsejable para evitar posibles problemas. Si algo sale realmente mal solo tendríamos que borrar los directorios anteriores y empezar de nuevo.

Tags: , , , ,

Hace poco en Kriptópolis se publicó una entrada sobre el cifrado XOR. Aparentemente, este cifrado que en teoría es muy bueno, no era tan bueno a la hora de cifrar información que un humano pudiera reconocer. Así un archivo de sonido podía reconocerse después de usarse este cifrado «infalible» o al menos podía intuirse el contenido que se intentaba cifrar. En los comentarios a la entrada aparecían también ejemplos de imágenes que eran fácilmente reconocibles después de aplicarle este cifrado.

Tras mi primer contacto con este cifrado y después de mucho pensar no encontré ningún motivo por el que no debía funcionar. Así que pensé que lo mejor era probarlo yo mismo. Como siempre eché mano de mi amigo Python.

Las librerías que he usado son numpy y scikits.audiolab:

  • Numpy es la librería favorita para trabajar eficientemente con conjuntos ordenados de números como vectores, matrices, etc. No está escrita íntegramente en Python con lo que puede requerir cierta compilación dependiendo de la versión que se instale aunque suele poder instalarse con facilidad.
  • Audiolab es una librería para manipular archivos de sonido usando numpy. El manejo es sencillo viendo los ejemplos. Tampoco está escrita íntegramente en Python. Para la instalación tiene como dependencia la librería «libsndfile». Es posible instalarla manualmente en un Mac usando Macports.

Como entrada utilizamos el mismo archivo (1234) que se usaba como prueba en la entrada de Kriptopolis. Sin embargo el formato del archivo es «wav» en lugar de mp3 para evitar problemas con la lectura/escritura o algún tipo de efecto debido a la codificación.

El código es el siguiente:

import numpy as np
from scikits.audiolab import Format, Sndfile
 
fi = Sndfile("1234.wav",'r')
sr = fi.samplerate
ch = fi.channels
frames = fi.nframes
data = fi.read_frames(frames, dtype=np.int16)
maxint = np.iinfo(np.int16).max
minint = np.iinfo(np.int16).min
ruido = np.random.randint(minint,maxint+1,frames)
 
salida = np.bitwise_xor(data,ruido)
 
f_test = Sndfile("1234_test.wav",'w',Format('wav'),ch,sr)
data_test = data/float(maxint)
f_test.write_frames(data_test)
f_test.close()
 
f_ruido = Sndfile("ruido.wav",'w',Format('wav'),ch,sr)
data_ruido = ruido/float(maxint)
f_ruido.write_frames(data_ruido)
f_ruido.close()
 
f_xor = Sndfile("1234_xor.wav",'w',Format('wav'),ch,sr)
data_xor = salida/float(maxint)
f_xor.write_frames(data_xor)
f_xor.close()

Tras importar las librerías leemos el archivo de entrada. Después generamos el ruido aleatorio (pseudoaleatorio en realidad) que combinaremos con la entrada. Se generan tres archivos de salida:

  1. 1234_test es una prueba similar al archivo de entrada que se usa para comprobar que no hay ningún fallo.
  2. ruido es el archivo de audio correspondiente a la base aleatoria.
  3. 1234_xor es el archivo de salida codificado usando el cifrado XOR.

Como se puede comprobar el fichero de salida no parece presentar ningún patrón de sonido reconocible.

A la hora de escribir un comentario a la entrada de Kriptópolis me encuentro con que lopezvit también tuvo la misma idea hace unos días y comprobó el cifrado usando Matlab obteniendo los mismos resultados.

Lo más probable sería que hubiera habido un fallo a la hora de aplicar el cifrado a los archivos originales de la entrada o a las imágenes de los comentarios. El error podría estar en la generación de los números aleatorios o en la aplicación del XOR. Un simple truncado numérico de los datos del ruido podría producir un efecto parecido.

Para completar también he probado a reconstruir el fichero original usando el ruido y el archivo cifrado. Como el formato wav no tiene perdidas debido a la codificación esto se puede hacer fácilmente. El código es este:

import numpy as np
from scikits.audiolab import Format, Sndfile
 
f_clave = Sndfile("ruido.wav",'r')
sr = f_clave.samplerate
ch = f_clave.channels
frames = f_clave.nframes
ruido = f_clave.read_frames(f_clave.nframes, dtype=np.int16)
maxint = np.iinfo(np.int16).max
 
fi = Sndfile("1234_xor.wav",'r')
data = fi.read_frames(fi.nframes, dtype=np.int16)
 
salida = np.bitwise_xor(data,ruido)
 
f_xor = Sndfile("1234_rec.wav",'w',Format('wav'),ch,sr)
data_xor = salida/float(maxint)
f_xor.write_frames(data_xor)
f_xor.close()

El archivo 1234_rec.wav es exactamente igual que el original.

En definitiva, ya conozco un método de cifrado nuevo y he comprobado que, aparentemente, funciona.

Tags: ,

Quería saber cual iba a ser el número de horas de sol que tendría en Edimburgo a lo largo del año, vamos, lo que viene a ser la duración del día. Gracias al software libre, a las pilas incluidas con Python y a las que se pueden obtener fácilmente, he realizado un programa sencillito y rápido que indica y muestra gráficamente las horas de sol y las de puesta y salida del sol según el día del año. Aquí viene la descripción del programilla. Por cierto, me imagino el tiempo que me hubiera costado encontrar o calcular yo mismo esta información en la era pre-Internet y pre-Software libre y se me ponen los pelos de punta.

Lo primero es importar los módulos que usaremos: “ephem” (PyEphem) para los cálculos de las efemérides, “math” para usar operaciones matemáticas y “pylab” (Matplotlib) para pintar los resultados:

import ephem
import math
import pylab

En el ejemplo que vamos a ver se podría omitir el uso de math pero se mantiene por claridad.

Luego definimos el lugar de observación con las coordenadas de Edimburgo:

EDI = ephem.Observer()
EDI.lat = str(55+55.378/60)
EDI.long = str(-3-11.672/60)

Después definimos el sol:

sun = ephem.Sun()

Creamos una serie de tuplas vacías que vamos a ir rellenando con los datos que nos interesen para cada día del año:

date = []
salida = []
puesta = []
df = []
sf = []
pf = []
dia = []

En la variable “d” ponemos el primer día del año, al mediodía que es cuando cabe esperar (al menos en el caso de Edimburgo) que el sol esté por encima del horizonte:

d = ephem.Date('2010/01/01 12:00')

En la variable auxiliar “d0” metemos el valor del día eliminando la hora. Esto lo hacemos truncando el valor float de d y quedándonos solo con su parte entera. “dhoy” es el día del año de hoy, le restamos al valor de hoy el valor del primer día del año, ambos en días julianos, para obtener así el día del año:

d0 = math.trunc(d)
dhoy = EDI.date - d0

Cambiamos la fecha de Edimburgo a la del primer día del año:

EDI.date = d

Ahora es cuando ejecutamos un bucle para los 365 días del año en el que vamos rellenando el valor de las tuplas que definimos con anterioridad. Ponemos la fecha completa en “d”; cambiamos la fecha en Edimburgo a la del día “d”; ponemos la hora de salida del sol anterior a ese momento en “salida” y la de puesta posterior en “puesta”; en “df” ponemos la diferencia entre el día actual y el primer día del año, el día del año; en “sf” ponemos la hora de salida y en “pf” la de puesta, ambas en tiempo universal; en “dia” ponemos la duración del día y por último añadimos un día más:

for i in range(0,365):
  date.append(d)
  EDI.date = d
  salida.append(EDI.previous_rising(sun))
  puesta.append(EDI.next_setting(sun))
  df.append(math.trunc(d)-d0)
  sf.append(math.fmod(salida[-1].triple()[2],1)*24)
  pf.append(math.fmod(puesta[-1].triple()[2],1)*24)
  dia.append((puesta[-1]-salida[-1])*24)
  d = d + 1

La última parte es pintar los resultados. Creamos una figura compuesta de dos partes: la de arriba muestra las horas de salida y puesta del sol y, la segunda, muestra las horas del día:

pylab.figure()
pylab.subplot(211)
pylab.plot(df,sf,'b-')
pylab.plot(df,pf,'r-')
pylab.grid()
pylab.vlines([dhoy],0,24,color="g",linestyles='dashed')
pylab.ylim([0,24])
pylab.xlim([0,365])
pylab.ylabel("Hour")
pylab.xlabel("Day of the year")
pylab.subplot(212)
pylab.plot(df,dia,'k-')
pylab.vlines([dhoy],0,24,color="g",linestyles='dashed')
pylab.grid()
pylab.xlim([0,365])
pylab.ylim([6,18])
pylab.ylabel("Hours of Sun")
pylab.xlabel("Day of the year")
pylab.show()

El resultado es el siguiente:

Tiempo de sol Edimburgo

Como se puede ver el día dura de un poco menos de 7 horas en diciembre hasta las más de 17 horas y media a finales de junio.

Las figuras se pueden mejorar para mostrar los meses directamente en lugar del día del año. También se podría hacer un poco más interactivo dejando que usuario pudiera elegir el día del año. Quizás se podría integrar fácilmente en un programa gráfico con PyQt por ejemplo pero todo esto se deja para otra ocasión.

Tags: , ,