domingo, 14 de diciembre de 2014

Siente la fuerza (Parte IV)

Qué encontrarás en esta entrada?
  • Mi script para el análisis de los datos de AndroSensor.

Durante estas dos últimos semanas, los que hayáis estado siguiendo la página sabréis que he estado embarcado en un proyecto personal sobre el análisis de datos de sensores de un dispositivo Android, obtenidos a través de AndroSensor.


Tras este tiempo, creo que ha llegado el momento de compartir mi código con vosotros. Aclarar que no se trata de un programa cerrado, sino sólo una serie de ideas puestas en forma de script, en continua revisión.

Actualmente, el código que os suministro lee los datos de los sensores en el formato que exporta AndroSensor (aclarar que este formato puede variar según la configuración, el dispositivo, y la versión de la aplicación). Se centra principalmente en la aceleración y en el campo magnético, y con ellos pretende reconstruir la trayectoria y pintar el campo sobre ella.

El script tiene un diseño modular, y según las opciones con las que lo llamemos carga un módulo u otro (ver documentación más abajo). En general, lo primero que se aborda (tras la carga de datos) son las correcciones a la aceleración.

En estos momentos hay definidas tres correcciones a la aceleración que pasamos a detallar a continuación.

Corrección de picos:


Esta corrección se basa en que picos (máximos y mínimos) que aparezca en un intervalo de tiempo muy pequeño o de muy poca intensidad, no tienen sentido físico, e intenta suavizarlos.

El script ha detectado un pico extraño entre los 6 y los 8 segundos e intenta suavizarlo

Corrección de ceros:


 Esta corrección se hace bajo la hipótesis de que las medidas que hemos tomado se realizan de tal manera que partamos y lleguemos a una situación de reposo (velocidad nula). Imponemos estas condiciones, que en último término implican la suma de un pequeño valor constante a la aceleración, o lo que es lo mismo: un "error de cero".

Se le suma (o resta) un valor constante a la aceleración para conseguir velocidad cero en los extremos

Corrección por cuantización:


Esta corrección intenta "simplificar" la señal de la aceleración bajo la hipótesis de que pequeñas fluctuaciones no son físicamente reales, sino que se tratan de perturbaciones en los sensores. Para ello, definimos un valor de mínima partición y consideramos que la aceleración se forma con múltiplos enteros a partir de éste.

En este caso sólo le permitimos a la aceleración que tome valores múltiplos enteros de 1m/s²


Después de este análisis para ajustar la aceleración, utiliza éste dato ya corregido para reconstruir mediante "diferencias finitas" la velocidad y, posteriormente, la posición. De esta manera recuperamos la trayectoria en tres dimensiones.

Representación de la trayectoria seguida por el móvil

Por último, se cruzan los datos con los del campo magnético para hacer una representación del campo sobre la trayectoria seguida.

Representación del campo magnético sobre la trayectoria seguida por la sonda


Adjunto a continuación la documentación del script (se puede consultar desde MATLAB/OCTAVE escribiendo "help sensor"):

 Programa para analizar los datos de AndroSensor (aplicación para android desde la cual se pueden consultar los datos de todos los sensores de un dispositivo ANDROID).

 Sintaxis:

 [dist,vmax,amax,Bmax,freq,longint]=sensor(F,cord,err0,Qfa,peak,eje,modo,guardargraf)

 Donde (consultar más abajo la descripción ampliada para cada parámetro de entrada):
  • "F": Archivo de datos de entrada. 
  • "cord": Tipo de coordenadas con las que se han grabado los datos.
  • "err0": Activar o no la corrección por error de cero.
  • "Qfa": Factor de cuantización.
  • "peak": Activar o no la corrección de picos aleatorios.
  • "eje": Eje principal.
  • "modo": Modo de ejecución.
  • "guardargraf": Opción para visualizar las gráficas o sólo guardarlas.

 El archivo de datos de entrada, "F", debe ser un archivo ".csv", salida de la aplicación AndroSensor, con separación por comas y columnas dispuestas exactamente de la siguiente manera:

MAGNITUD------------------------------Letra COL--# COL
----------------------------------------------------------------

 - Acelerometro (m/s²) x 3 ejes.
--------A,B,C----1,2,3
 - Gravedad (m/s²) x 3 ejes.------------D,E,F----4,5,6
 - Aceleracion lineal (m/s²) x 3 ejes.--G,H,I----7,8,9
 - Giroscopo (rad/s) x 3 ejes.----------J,K,L----10,11,12
 - Luz (Lux).---------------------------M--------13
 - Campo Magnetico (microT) x 3 ejes.---N,O,P----14,15,16
 - Orientacion (º) x 3 ejes.------------Q,R,S----17,18,19
 - Proximidad (m).----------------------T--------20
 - Presion atmosferica (atm).-----------U--------21
 - Nivel sonido (dB).-------------------V--------22
 - Latitud (º).-------------------------W--------23
 - Longitud (º).------------------------X--------24
 - Altitud (m).-------------------------Y--------25
 - Altitud Google (m)-------------------Z--------26
 - Altitud Presión (m)------------------AA-------27
 - Velocidad (Km/h).--------------------AB-------28
 - Precision (m).-----------------------AC-------29
 - Orientación GPS (º).-----------------AD-------30
 - Numero de Satelites.-----------------AE-------31
 - Tiempo (s).--------------------------AF-------32
 - Fecha.-------------------------------AG-------33

 La variable "cord" es el tipo de coordenada con la que está codificada la información en AndroSensor (por defecto, cord=0):
  • cord=0: Se utiliza como sistema de referencia uno externo fijo al mundo.
  • cord=1: Se utiliza como sistema de referencia uno fijado al dispositivo:
    • Eje x: Eje del ancho de la pantalla.
    • Eje y: Eje del alto de la pantalla.
    • Eje z: Eje de la profundidad del dispositivo.
Este método requiere una transformación de coordenadas basada en la orientación, lo que puede ocasionar errores si el refresco de esta variable es lento como acostumbra.

 La variable "err0" puede tomar dos valores:
  • err0=0 => Sin corrección de error de cero.
  • err0=1 => Se presupone que el objeto está en reposo total tanto al inicio como al final de su trayectoria, y se corrige la aceleración para que así sea.

 La variable "Qfa" es el valor con el que se corrige la sensibilidad de la aceleración. Un valor de "1" indicaría que la aceleración se mediría en pasos enteros de "1 m/s²". Un valor de "0" indica que no se realiza dicha corrección.

 La variable "peak" puede tomar tres valores:
  • peak=0 => Sin corrección de picos.
  • peak=1 => Corrige fluctuaciones demasiado cortas como para tener significado físico.
  • peak=2 => Corrige fluctuaciones demasiado cortas, y poco intensas, como para tener significado físico.

 El "eje" es el eje principal (por ejemplo, el eje en el que se desplaza el objeto), en el que queremos realizar un estudio especial, por ejemplo, de cara a la representación gráfica de la cinemática. Para elegirlo automáticamente, escribir "0".
  • Eje x = 1
  • Eje y = 2
  • Eje z = 3

 Por defecto se toma el eje de máximo desplazamiento.

 El modo de ejecución puede ser uno de los siguientes:
  • modo=-1 => No genera gráficas.
  • modo=0 => Genera todas las gráficas.
  • modo=1 => Genera las gráfica de correción.
  • modo=2 => Genera sólo las gráficas cinemáticas.
  • modo=3 => Genera sólo la gráficas magnéticas.

 El tratamiento de las gráficas viene dado por el parámetro "guardargraf". Puede tomar los siguientes valores:
  • guardargraf=0 => Se muestran los resultados por pantalla.
  • guardargraf=1 => Las gráficas no se muestran, sino que se guardan formato ".png".
  • guardargraf=2 => Las gráficas no se muestran. Se guardan fotogramas para poder crear una animación posteriormente.

 Nota: Se pueden juntar luego los fotogramas para formar un GIF desde Shell de Linux con "convert":

convert -delay 10 *.png -loop 0 Grafico_animado.gif

 Ejemplos de sintaxis:

 sensor(F,cord,err0,Qfa,peak,eje,modo,guardargraf)
 >>sensor('data.csv',1,0,2.32,1,3,2,1);

 Analiza los datos en "data.csv":
 1: Grabados con un sistema de referencia fijo al dispositivo.
 0: Sin corrección de cero.
 2.32: Cuantizando los valores de la aceleración con un paso de "2.32m/s²".
 1: Aplicando corrección de picos.
 3: Los datos cinemáticos serán representados según el "eje z".
 2: Se genera sólo la gráfica magnética.
 1: Las gráficas se guardarán como imágenes para su posterior visualización o procesado.


 Variables de salida: [dist,vmax,amax,Bmax,freq,longint]
  • dist: Distania (m) recorrida por la trayectoria.
  • vmax: Máxima velocidad en el intervalo grabado.
  • amax: Máxima aceleración en el intervalo grabado.
  • Bmax: Campo magnético máximo en el intervalo grabado.
  • freq: Frecuencia de fluctuaciones magnéticas (calculada respecto al valor medio del campo).
  • longint: Número de mediciones para cada variable.


 CRÉDITOS:

 Realizado por Astaroth (O.R.G.) - Diciembre 2014.

Por último, os adjunto el enlace al script (descargar sensor.m). Para ejecutarlo deberéis copiar el script a la carpeta en la que estéis trabajando con MATLAB/OCTAVE y escribir "sensor('data.csv')", donde el archivo "data.csv" son los datos grabados previamente con AndroSensor.

Espero que os haya resultado útil.

lunes, 8 de diciembre de 2014

Siente la fuerza (Parte III)

Qué encontrarás en esta entrada?
  • Análisis de los datos de los sensores de un dispositivo Android.
  • Campo magnético y trayectorias.

¡Bueno bueno! Esta serie de entradas ya se ha convertido en trilogía, y no sé si seguirá más allá. En la primera parte os hablé de cómo AndroSensor permitía grabar y exportar los datos detectados por los sensores de un dispositivo Androird, y os enseñaba cómo, a partir de la aceleración y con un procedimiento basado en diferencias finitas, podíamos reconstruir la velocidad y la trayectoria, llegando a representar algunas de estas en MATLAB/OCTAVE.

En la segunda parte de esta serie, profundizábamos en la representación de las trayectorias y os mostraba cómo podíamos afinar los resultados aplicando distintas correcciones a la aceleración. Allí vimos que éramos capaz de dibujar figuras sencillas moviendo el móvil en el espacio vacío, y luego las podíamos reconstruir en MATLAB/OCTAVE.

Al final de aquella última entrada mencionábamos el análisis del campo magnético como el siguiente paso en el caprichoso camino hacia la satisfacción de nuestra curiosidad.

Una vez teniendo la trayectoria calculada, y los valores para el campo magnético, me pareció curioso cruzar ambos datos y representarlos de una forma visual. Lo que he implementado es la representación del campo magnético (sus tres componentes y su módulo) sobre la trayectoria, por lo que podemos ver de manera gráfica cuál es el campo al que está sometido el móvil en cada punto del espacio por el que ha pasado. Es decir, dibujamos el campo vectorial asociado al campo magnético medido para cada punto de la trayectoria:

(x,y,z) --> B(x,y,z)=(Bx(x,y,z), By(x,y,z), Bz(x,y,z))

Limitado los valores de (x,y,z) a los que formen parte de la curva recorrida por el dispositivo.

¿Cómo representamos un vector por cada punto del espacio? Yo he optado por dibujar una familia de curvas que se extienda en el sentido en el que crezca cada componente. Es decir, el campo Bx se representa como una familia de curvas que nacen en la trayectoria y que se extienden desde ésta, en la dirección del "eje x", proporcionalmente al valor de su magnitud.

Una imagen vale más que mil palabras, pero un ".gif" vale tanto como la cantidad de imágenes que contenga. Siguiendo con la temática de la última vez: os presento una gráfica en la que he puesto todo mi corazón.


En ella vemos una trayectoria con forma de corazón. Se ha dibujado un corazón en el aire con el móvil, se ha estudiado la variación de la aceleración con las correcciones oportunas y hemos reconstruido la trayectoria que siguió nuestro trazo en tres dimensiones. Al mismo tiempo, hemos representado el campo al que está sometido el móvil durante su trayectoria. En este caso no parece haber grandes fluctuaciones en el mismo.

La siguiente prueba que he querido hacer es dar una vuelta al móvil por los bordes de mi habitación, pasando a propósito por una zona por la que sabía de antemano que se eleva considerablemente el valor del campo.


Se puede ver que hay un punto en el que, efectivamente, sube significativamente el campo.


Lo interesante es que podemos verlo de una manera muy gráfica: vemos la trayectoria en forma de "U" que se ha realizado siguiendo las paredes de la habitación, y vemos en qué zona de ésta se dispara el campo. Es cierto que las escalas no están muy afinadas aún, pero las formas básicas las vamos captando.

Por último, un ejemplo que me ha parecido interesante desde el principio, tanto desde el punto de vista cinemático como del electromagnético: el ascensor. Como os comenté previamente, mi ascensor presenta un irregular perfil magnético que decae entre piso y piso, muy probablemente debido a los materiales empleados para la construcción del edificio (hormigón).


Comprobamos lo llamativo de su "huella magnética". El campo en el "eje x" (azul) y, sobre todo en el "eje y" (en rojo - dirección que apunta hacia la puerta del ascensor) se dispara, llegando en total hasta los 62 microteslas.


Como ya comenté en su día, es fácil "adivinar" el número de pisos con tan solo contar estas tremendas variaciones en el campo magnético.

Notar que, según la última gráfica, el ascensor no "sube recto", sino en diagonal. Eso significa que aún queda mucho trabajo por hacer de cara a afinar los resultados obtenidos de nuestro análisis de sensores, pero ya hemos visto en esta serie de entradas que - utilizándolo con cautela - podemos sacar algunas conclusiones interesantes... o, al menos, algún dibujito curioso.

sábado, 6 de diciembre de 2014

Siente la fuerza (Parte II)

Qué encontrarás en esta entrada?
  • Cinemática basada en los sensores Android.
  • Frecuencias electromagnéticas. 

En la última entrada os hablamos de AndroSensor y de cómo manipular los datos que este software nos permite guardar. Hoy vamos a comentar algunos de los resultados que he obtenido utilizando varios métodos para intentar ajustar estos sensores a la realidad física.


El Círculo:

Lo primero que vamos a hacer es dibujar un círculo a mano alzada con el móvil, y nos vamos a centrar, como la última vez, en la parte de la cinemática (análisis de la aceleración para intentar reconstruir la trayectoria). El algoritmo de diferencias finitas que utilizo ya fue esbozado en la entrada anterior, por lo que hoy nos vamos a dedicar a ver dibujitos.

Vemos la trayectoria tal cual sale de las lecturas del sensor:

Datos sin correcciones

Bien en verdad que a mi los círculos a mano alzada no se me dan muy bien... pero quizás éste haya salido especialmente mal.

El siguiente paso sería suponer que los acelerómetros estuviesen afectados por un error constante, un "error de cero", así que los intentamos ajustar para que el error sea compensado, obteniendo lo siguiente:


Datos con correcciones de cero para la aceleración

Supongo que habrá controversia al respecto... pero yo diría que lo de arriba se parece ya bastante a un círculo (al menos, a uno de los que dibujo yo a mano alzada).

Una cosa que se me ha ocurrido recientemente, es descartar las pequeñas vibraciones: ¿Qué pasaría si, en lugar de corregir la aceleración forzándola para que la velocidad sea nula al principio y al final, simplemente la "simplifico"?, y con "simplificar" me refiero a "cuantizarla". Defino un "paso mínimo", y obligo a la aceleración a que tome sólo valores que sean múltiplos enteros de esa "unidad" que acabo de definir. Con todo esto, obtenemos:

Datos con la aceleración cuantizada en pasos de 1m/s²

Bueno, también tiene pinta de círculo. Sin embargo, tiene un fallo importante:

Avance de la hélice en la dirección perpendicular al círculo

En el eje perpendicular al círculo, donde debería estar inmóvil, se mueve nada más ni nada menos que ¡¡4 metros!! No es un círculo, sino una especie de hélice que va avanzando.

El mismo problema lo presentaba la primera gráfica, asociada a datos en bruto, sin ningún tipo de corrección. Sin embargo, no era así cuando obligábamos a la velocidad a ser cero al inicio y al final.

Avance en la dirección perpendicular con la corrección de cero en la aceleración: aunque no sea nulo, éste es "sólo" de metro y medio

Avance en la dirección perpendicular sin correcciones: se dispara hasta los cuatro metros

La última idea es mezclarlo todo: ¿qué pasaría si cuantizamos la aceleración, y al mismo tiempo intentamos corregir el posible error de cero?

Aceleracioes con corrección de cero y cuantización en bloques de 1m/s²

La hélice avanza, pero menos que en cualquiera de los casos anteriores

En este último caso obtenemos un círculo (si bien es verdad, que algo "chuchurrío"), y el avance en la dirección perpendicular es "sólo" de metro y medio. En realidad este "avance" debería ser casi nulo (20cm a lo sumo), pero es el mejor resultado que he obtenido hasta el momento.

A continuación, vamos a ver las gráficas de la cinemática en los dos casos más favorables. La posición está en azul, la velocidad en rojo, y la aceleración en verde. Al terminar el trazado del círculo en el mismo punto en el que lo empezamos, ambas deberían acabar en cero, pero vemos que en ambos casos acaban en metro y medio.

Posición, velocidad y aceleración en la dirección del trazado sin cuantizar la aceleración

Posición, velocidad y aceleración en la dirección del trazado cuantizando la aceleración

En la segunda gráfica se puede apreciar la cuantización de la aceleración. Ésta sólo puede valer múltiplos enteros de 1m/s² (1m/s², 2m/s², 3m/s², ...).

A continuación, dibujamos las gráficas de los casos más desfavorables: aquellos en los que no hemos corregido el error de cero de la aceleración, desviándose notablemente en la dirección perpendicular:

Sin corrección de cero ni cuantizado

Sin corrección de cero, pero con la aceleración cuantizada

Paradójicamente, si nos fijamos sólo en la dirección del trazado, estos círculos empezaron en el mismo punto donde acabaron, lo cual es correcto. El problema es que los valores para el eje perpendicular al trazado son completamente irreales.

En cualquier caso, y aunque aún hay mucho en lo que mejorar, de momento me quedo satisfecho en lo que al dibujo de círculos se refiere... ¿y si lo intentamos con algo más complicado?


El Corazón:

Partiendo de lo anterior, dibujo los cuatro corazones:

Sin corrección de cero ni cuantizado

Con corrección de cero, pero sin cuantizado

Sin corrección de cero, pero con aceleraciones cuantizadas

Con corrección de cero y aceleraciones cuantizadas

Como si de una constante se tratara, en los casos en los que no hemos corregido el error de cero en la aceleración se desvían unos cuatro metros en la dirección perpendicular, mientras que en los que sí lo hemos corregido, el desvío es de metro y medio. En este caso, si tuviera que elegir el que más se parece a la realidad, creo que me quedaría con el segundo. Sin embargo, el segundo no tiene las aceleraciones cuantizadas, y eso puede dar problemas, como veremos en el siguiente caso.


El caso estático:

Vamos a dejar el móvil quieto encima de la mesa, y a ver qué pasa...

"Trayectoria" de un móvil parado con datos en bruto

La conclusión es indiscutible: el móvil se teletransporta a través de dimensiones ocultas del espacio y, aunque parezca que no se mueva de encima de la mesa, recorre unos 80 metros en su apasionante viaje lleno de misterios a través de la parafísica... Bueno, puede ser eso, o que los sensores se hayan visto afectados por un importante error que se potencie con el tiempo.

Vamos a ver cómo se comporta nuestro móvil parado con las distintas correcciones en la aceleración:

"Trayectoria" de un móvil parado con aceleraciones corregidas (error de cero)

"Trayectoria" de un móvil parado con aceleraciones cuantizadas

En el primer caso, la compensación del error de cero no es suficiente para "parar" al objeto, aunque sí acorta su viaje: en este caso pasa de los 80 a los 4 metros recorridos.

En la segunda gráfica (aceleraciones cuantizadas), no es que tengáis mala vista, sino que sólo se representa un punto y, al no estar en compañía de otros, es invisible. La posición del objeto está siempre en el origen. El objeto, por fin, se ha quedado parado.

En mi script he dejado todas las opciones programadas y accesibles, y seguiré trabajando en ello, pero parece que las mejores soluciones las aportan los métodos en los que corregimos el error de cero de la aceleración, siendo en algunos casos especialmente interesante añadir además el proceso de la cuantización.


Magnetismo:

Hasta ahora nos habíamos centrado en las variables cinemáticas, básicamente, en el estudio de la aceleración para reconstruir la velocidad y trayectoria del objeto en cuestión. Sin embargo, AndroSensor ofrece otras variables interesantes, como es el caso del campo magnético.

Bajando el otro día en mi ascensor me di cuenta de la variación tan pintoresca que tenía el campo a medida que bajaba.


He leído un poco por encima sobre el tema y, por lo visto, el hormigón del que están hechas las paredes de mi casa no es demasiado saludable de cara a las posibles interferencias electromagnéticas. De hecho, según Radiansa, la normativa española establece como límite 100 microteslas para campos magnéticos de 50Hz.

En este caso medimos campos que pasan de los 60 microtestas, aparentemente estacionarios (aunque no sé si realmente se está midiendo el promedio temporal de un campo oscilante de más alta frecuencia). La modulación que se observa proviene del movimiento del sensor (que está bajando en un ascensor), de tal manera que lo que estamos viendo es una variación en el espacio, y no en el tiempo.

Es interesante ver que entre piso y piso la amplitud del campo decae incluso casi media centena de microteslas. Se puede utilizar esto para ver claramente que en el recorrido del ascensor hemos cruzado ocho suelos, y así contar los pisos.

Afinamos un poco más este tipo de medidas, e incorporamos a nuestro script de análisis de datos de los sensores la funcionalidad de contar oscilaciones: por separado las bajadas y las subidas.


En este segundo experimento estamos viendo la señal con el sensor fijo. Se trata de uno de los casos estáticos de los cuales hemos estudiado la cinemática unas líneas más arriba. En esas circunstancias, estamos viendo la variación del módulo del campo magnético con el tiempo.


Viendo cuánto oscila a lo largo del tiempo medido, contamos que decae 379 veces, y que vuelve a subir otras 379 en unos 108 segundos. Eso da una frecuencia de unos 3'5 Hz. En general, en esa zona de mi habitación estoy midiendo frecuencias que van desde los 3 a los 4 Hz (bajas frecuencias). Insisto que no sé si se trataría de una frecuencia normal o, en el caso de estar midiendo promedios temporales del campo magnético, una frecuencia secundaria de modulación de la onda.


Informe Remoto:

Para finalizar, os comentaré la integración de este script en Astaroth's Bot System (ABSys), el sistema que me permite la comunicación con mi ordenador vía Hangouts.

Actualmente, puedo depositar los datos adquiridos con mi móvil en una carpeta en la nube que se sincroniza con una carpeta local de mi equipo de sobremesa. Una vez estén los datos en casa, dando una orden vía Hangouts, recibo el resumen del análisis por mensajería instantánea y al correo, incluyendo las gráficas en este último caso.


Un ejemplo curioso de integración entre Android, mensajería instantánea, shell de Linux y MATLAB/OCTAVE.