rss

Artictles

Hi, thanks for visiting this page. Here I write about technology, in-depth analysis of some problems, sport management, among others. If you like these things, you will be glad to read the articles. Also, you can comment or ask questions whenever you want. I will try to respond as soon as possible...

Compresión de hasta 40% en sistema de tiempo real Bookmark

Una vez desarrollada las clases en C++ para la codificación Huffman Adaptiva en Implementación de la compresión de datos en sistemas de tiempo real, en el cual se comprobaba su funcionamiento con datos fuera de línea, he decidido implementar la codificación en el sistema eMonitor. En éste, se obtienen una serie de resultados muy significativos que se mostrare mas adelante. Ahora bien, antes de ver los resultados en necesario entender como se realizaron las mediciones de los tiempos y tamaño de los datos originales y codificados.

Compresión de la señal electrocardiográfica en tiempo real

eMonitor como plataforma de adquisición y almacenamiento

La plataforma eMonitor posee un hilo de adquisición, en el cual se adquieren las muestras del MAD (modulo de adquisición de datos) bajo previa configuración. Estas muestras son colocadas en un objeto derivado de la clase CDataPacket el cual posee métodos para convertir los datos seriales a paralelos o de paralelos a seriales entre otras cosas, los cuales sirven de datos para toda la aplicación. La estructura de la clase CDataPacket se muestra en la siguiente figura siguiente.

Métodos y variables de la clase CDataPacket

Figura 1. Métodos y variables de la clase CDataPacket

La clase CDataPacket posee varios buffers (uno serial: pBytesBuffer y uno paralelo: pChannelsBuffer) cuyo tamaño depende de ciertos parámetros de adquisición, como el modo y frecuencia de muestreo. Estos parámetros se muestran en la siguiente tabla.

Parámetros de adquisición para determinar el tamaño de los buffers en la clase CDataPacket

Tabla 1. Parámetros de adquisición para determinar el tamaño de los buffers en la clase CDataPacket

Una vez que el hilo de adquisición rellena el paquete de datos (CDataPacket), lo envía a los demás hilos de la aplicación, en donde, se procede a la visualización, procesamiento y lo que nos concierne en este momento: el almacenamiento.

Almacenamiento de los datos de ECG en eMonitor

Cuando llega el momento de almacenar los datos, se posee un objeto derivado de la clase CDataPacket, en donde, se encuentran las muestras de varios canales en un periodo de tiempo especifico, dependiendo de la configuración y de los valores de la tabla anterior.

El código en leguaje C++ de la función que almacena los datos, que se utilizó para calcular todos los resultados que se presentarán mas adelante, tiene la siguiente forma:

   1: BOOL CMainFrame::SaveDataPacketToRecordDebug(CDataPacket *pDataPacket)
   2: {
   3:     ////////////////////////////////////////////////////////////
   4:     // Variables inicializadas en otra parte del código
   5:     m_CFile;            // Objeto que describe al archivo original
   6:     m_CFileCompress;        // Objeto que describe al archivo codificado
   7:     m_CFileCompressStatus;    // Objeto que describe al archivo de estatus
   8:     ////////////////////////////////////////////////////////////
   9:     // Variables temporales para las estadísticas de tiempo
  10:     UINT i64Diff;
  11:     UINT total    = 0;        // Total
  12:     UINT max    = 0;        // Máximo
  13:     UINT min    = 0x10000;    // Minimo
  14:     UINT prom    = 0;        // Promedio
  15:     ////////////////////////////////////////////////////////////////////////////////
  16:     // Almacenamos los datos en el archivo (sin codificar)
  17:     m_CFile.Write(pDataPacket->pBytesBuffer, pDataPacket->m_nBytesBuffer);
  18:     ////////////////////////////////////////////////////////////////////////////////
  19:     // Almacenamos los datos en el archivo codificados
  20:     UINT i, j;
  21:     for(i = 0; i < pDataPacket->m_nChannelsBuffer; i++) {        // Canales
  22:         for(j = 0; j < pDataPacket->m_nChannels; j++) {    // Muestras
  23:             ////////////////////////////////////////////////////////////
  24:             // Comenzamos el timer
  25:             CPreciseTimer preciseTimer;
  26:             preciseTimer.StartTimer();
  27:             ////////////////////////////////////////////////////////////
  28:             // Codificamos y almacenamos
  29:             m_pAdaptiveHuffman->WriteWord(pDataPacket->pChannelsBuffer[j][i]);
  30:             ////////////////////////////////////////////////////////////
  31:             // Detenemos el timer
  32:             preciseTimer.StopTimer();
  33:             ////////////////////////////////////////////////////////////
  34:             // Calculamos los tiempos (total, promedio, máximo y minino)
  35:             i64Diff    = (UINT) preciseTimer.GetTime();
  36:             total        += i64Diff;
  37:             prom        += i64Diff;
  38:             max        = i64Diff > max ? i64Diff : max;
  39:             min        = i64Diff < min ? i64Diff : min;
  40:         }
  41:     }
  42:     ////////////////////////////////////////////////////////////
  43:     // Calculamos el tiempo promedio por muestra
  44:     prom /= (i*j);
  45:     ////////////////////////////////////////////////////////////////////////////////
  46:     // Calculamos la longitud del archivo original y el codificado
  47:     UINT length, lengthCompress; 
  48:     length            = (UINT)m_CFile.GetLength();
  49:     lengthCompress    = (UINT)m_CFileCompress.GetLength();
  50:     
  51:  
  52:     ////////////////////////////////////////////////////////////////////////////////
  53:     // Calculamos el radio de compresión
  54:     double radio;
  55:     radio = (1.0-((double)lengthCompress/length))*100;
  56:     ////////////////////////////////////////////////////////////////////////////////
  57:     // Guardamos la información calculada anteriormente a un archivo de estatus
  58:     CString strStatus;
  59:     strStatus.Format(_T("%12u \t%12u \t%6u \t%4u \t%6u \t%4u \t%6.2f\r\n"), 
  60:         length, 
  61:         lengthCompress, 
  62:         total,
  63:         prom,
  64:         max,
  65:         min, 
  66:         radio);
  67:     m_CFileCompressStatus.Write(strStatus, strStatus.GetLength());
  68:     ////////////////////////////////////////////////////////////
  69:     // Retornamos de la función de almacenamiento
  70:     return 0;
  71: }

Ahora bien, como se observa en el código anterior, se realizaron medidas del tiempo de ejecución del método WriteWord de la clase CAdaptiveHuffman. Para lograr esto, se utilizan los timers de alta resolución de Windows. Existen dos funciones de la API de Windows para realizar esta tarea: QueryPerformanceFrequency y QueryPerformanceCounter. Ahora bien, se utilizaron estas funciones para diseñar la clase CPresiceTimer, que nos brinda las utilidades de dichas funciones, más otras características adicionales. Los tiempos están en unidades de µ segundos. En la siguiente figura se muestran los métodos y variables de la clase CPresiceTimer.

Métodos y variables de la clase CPresiceTimer

Figura 2. Métodos y variables de la clase CPresiceTimer

En eMonitor activamos la opción de compresión (usando el algoritmo FGK) y además indicamos que deseamos crear archivos de estatus de dicha compresión, como se muestra en la siguiente figura.

Opciones de configuración de almacenamiento de ECG en eMonitor

Figura 3. Opciones de configuración de almacenamiento de ECG en eMonitor

Luego de empezar la adquisición y comenzar a guardar los datos de ECG, se crearan tres archivos como muestra en la siguiente figura.

Archivos generados por eMonitor

Figura 4. Archivos generados por eMonitor

El archivo de estatus tiene la forma que se muestra en la siguiente figura.

Archivo de estatus de la compresión, generado por eMonitor

Figura 5. Archivo de estatus de la compresión, generado por eMonitor

Las características de la computadora en la cual se realizaron las pruebas se muestran la siguiente figura.

Características de la computadora donde se obtuvieron los resultados

Figura 6. Características de la computadora donde se obtuvieron los resultados

Resultados en eMonitor

A través de los archivos de estatus, generados por eMonitor se lograron obtener muchas características importantes, incluyendo el performance de las clases implementadas en C++. A continuación se muestran algunas graficas más importantes obtenidas a partir de los archivos de estatus.

Radio de compresión versus muestras codificadas usando el algoritmo FGK

Figura 7. Radio de compresión versus muestras codificadas usando el algoritmo FGK

Radio de compresión versus muestras codificadas usando el algoritmo FGK (ampliación)

Figura 8. Radio de compresión versus muestras codificadas usando el algoritmo FGK (ampliación)

 

Tiempo promedio versus muestras codificadas en modo de adquisición de 3 derivaciones (2 canales) @ 250 Hz usando el algoritmo FGK

Figura 9. Tiempo promedio versus muestras codificadas en modo de adquisición de 3 derivaciones (2 canales) @ 250 Hz usando el algoritmo FGK

Tiempo promedio versus muestras codificadas en modo de adquisición de 3 derivaciones (2 canales) @ 1000 Hz usando el algoritmo FGK

Figura 10. Tiempo promedio versus muestras codificadas en modo de adquisición de 3 derivaciones (2 canales) @ 1000 Hz usando el algoritmo FGK

Comparación entre el algoritmo FGK y el algoritmo Vitter con respecto al radio de compresión versus muestras codificadas

Figura 11. Comparación entre el algoritmo FGK y el algoritmo Vitter con respecto al radio de compresión versus muestras codificadas

Comparación entre el algoritmo FGK y el algoritmo Vitter con respecto al tiempo promedio de codificación versus muestras codificadas (ampliación al algoritmo FGK)

Figura 12. Comparación entre el algoritmo FGK y el algoritmo Vitter con respecto al tiempo promedio de codificación versus muestras codificadas (ampliación al algoritmo FGK)

Comparación entre el algoritmo FGK y el algoritmo Vitter con respecto al tiempo promedio de codificación versus muestras codificadas (ampliación al algoritmo Vitter)

Figura 13. Comparación entre el algoritmo FGK y el algoritmo Vitter con respecto al tiempo promedio de codificación versus muestras codificadas (ampliación al algoritmo Vitter)

Conclusiones

La codificación Huffman adaptiva no requiere el conocimiento de la probabilidad de cada símbolo que aparece en el mensaje de texto o fuente de entrada. De esta manera, dado los datos de entrada sin conocer sus estadísticas, solo un paso a través de este, hace la codificación completa.

El algoritmo FGK trabaja bastante bien, pero inferior al algoritmo Vitter minimizando la altura del árbol para acortar el tiempo tomado para encontrar un camino de la raíz a la hoja. El algoritmo Vitter en la implementación corre a una velocidad menor al algoritmo FGK, ya que tiene un procedimiento largo para actualizar el árbol, examinando cada nodo y encontrando aquéllos de peso similar.

A continuación se muestra una tabla comparativa que reflejan algunas semejanzas y/o diferencias entre la codificación Huffman y Huffman Adaptiva para el caso de almacenamiento o transmisión de datos.

Tabla 2. Algunas semejanzas y/o diferencias entre la codificación Huffman y Huffman Adaptiva

Tabla 2. Algunas semejanzas y/o diferencias entre la codificación Huffman y Huffman Adaptiva

blog comments powered by Disqus