Log en tarjeta Micro-SD de entradas analógicas (VIN), muestreo a alta velocidad

  • 2 Respuestas
  • 405 Vistas

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2296
  • Soporte Técnico
Si está buscando muestrear uno o más canales analógicos VIN a una velocidad mayor de 5 muestras por segundo y a su vez guardar los datos en archivos dentro de la tarjera Micro-SD para luego analizarlos con Excel (por ejemplo), aquí podrá encontrar ejemplos que le serán útiles.



Los ejemplos utilizan los "SAMPLERS" del PLC, que permiten muestrear un canal VIN a una velocidad fija, por ejemplo a 200 o 2000 muestras por segundo. Si requiere velocidades menores o iguales a 5 muestras por segundo, puede evitar el uso de los SAMPLERS y utilizar solo temporizadores con eventos @OnTimer[X](), que son más fáciles de configurar y utilizar.

Si bien los SAMPLERS pueden muestrear una señal a alta velocidad, el cuello de botella, es decir, el lugar en donde el PLC tarda más tiempo de procesamiento, es en escribir las muestras dentro de un archivo de la tarjeta Micro-SD. Por lo tanto la escritura en tarjeta Micro-SD nos limita a una tasa de muestreo de 2000 a 3000 muestras por segundo para el modelo STX8180, y este valor puede variar según el tipo de proyecto, cantidad de canales analógicos a muestrear y el uso del procesador del PLC en otras lógicas.

Hay muchos caminos para hacer un log de datos, aquí damos algunos ejemplos con diferentes técnicas que puede utilizar como referencia inicial.

LENGUAJE PAWN

EJEMPLO #1: DiskSamplerLog1

www.slicetex.com/docs/an/an036/files/examples/DiskSamplerLog1.zip

Este ejemplo permite muestrear cinco canales analógicos VIN a 10 muestras por segundo (configurable) y almacenar las lecturas en un archivo de texto CSV que puede importar a Excel para análisis y gráficos. El acceso a las muestras es a través de la página web del PLC. Se recomienda leer el archivo "info.txt" del proyecto para una explicación detallada del ejemplo.

EJEMPLO #1 (B): DiskSamplerLog1B

www.slicetex.com/docs/an/an036/files/examples/DiskSamplerLog1B.zip
 
Ejemplo derivado del ejemplo "DiskSamperLog1", pero con diferencia que permite configurar los parámetros SAMPLERS_TS, SAMPLERS_LOG_TIME y SAMPLERS_BUF_SIZE desde la página web sin recompilar el código, ideal para pruebas rápidas.

EJEMPLO #2: DiskSamplerLog2

www.slicetex.com/docs/an/an036/examples/files/DiskSamplerLog2.zip

Este ejemplo permite muestrear cinco canales analógicos VIN a 200 muestras por segundo (configurable, por ejemplo 2000 muestras por segundo) y almacenar las lecturas en un archivo binario que luego puede convertir a CSV con la aplicación "SampleBinToText" y por lo tanto importar a Excel para análisis y gráficos. El acceso a las muestras es a través de la página web del PLC. Se recomienda leer el archivo "info.txt" del proyecto para una explicación detallada del ejemplo.

Este ejemplo, a diferencia del ejemplo DiskSamplerLog3, no utiliza las funciones DiskLogXXX() que simplifican el log de datos en archivos, pero muestran como utilizar las funciones genéricas DiskXXX() para manipular archivos.

EJEMPLO #3: DiskSamplerLog3

www.slicetex.com/docs/an/an036/files/examples/DiskSamplerLog3.zip

Este ejemplo permite muestrear cinco canales analógicos VIN a 200 muestras por segundo (configurable, por ejemplo 2000 muestras por segundo) y almacenar las lecturas en un archivo binario que luego puede convertir a CSV con la aplicación "SampleBinToText" y por lo tanto importar a Excel para análisis y gráficos. A diferencia del ejemplo DiskSamplerLog2, este ejemplo utiliza las funciones DiskLogXXX() para simplificar el log de datos en archivos.

El acceso a las muestras es a través de la página web del PLC. Se recomienda leer el archivo "info.txt" del proyecto para una explicación detallada del ejemplo.

EJEMPLO #3 (B): DiskSamplerLog3B

www.slicetex.com/docs/an/an036/files/examples/DiskSamplerLog3B.zip
 
Ejemplo derivado del ejemplo "DiskSamperLog3", teniendo como principal diferencia el nombre de los archivos de logs, que en este caso incluyen la fecha en el nombre. Además se va listando cada archivo de log como enlace en una página web a medida que nuevos archivos son creados. Información adicional en este mensaje.

EJEMPLO #4: DiskSamplerLog4

www.slicetex.com/docs/an/an036/files/examples/DiskSamplerLog4.zip

Este ejemplo es idéntico al ejemplo DiskSamplerLog3, con la diferencia que permite configurar todos los parámetros del Log desde la página web, por ejemplo velocidad de muestreo, tiempo de muestreo, etc. Puede ser muy útil para hacer pruebas de desempeño de forma fácil, sin necesidad de modificar código y transferir el programa al PLC una y otra vez.

El acceso a las muestras es a través de la página web del PLC. Se recomienda leer el archivo "info.txt" del proyecto para una explicación detallada del ejemplo.

LENGUAJE C#

EJEMPLO: SampleBinToText

www.slicetex.com/docs/an/an036/files/examples/SampleBinToText.zip

La aplicación toma un archivo binario con muestras de canales analógicos VIN (ver ejemplos arriba) y los convierte a un archivo de texto en formato CSV (Comma Separated Values), que luego puede utilizar para importar desde Microsoft Excel.

Esta aplicación se suministra con el código fuente en Microsoft Visual C# para que pueda utilizarla como referencia y modificarla de acuerdo a sus necesidades.



Consejo: Puede copiar esta aplicación a la tarjeta Micro-SD y hacerla disponible para descarga en la página web del PLC. De esta manera sus clientes tienen siempre a mano la aplicación de conversión.

Nota[1]: Otra versión de este programa, pero con conversión a unidades de ingeniería lo puede encontrar aquí.

ANEXO

ARCHIVO CON FORMATO CSV TÍPICO

En la siguiente imagen puede apreciar un archivo de texto CSV con las muestras de cinco canales VIN muestreados mediante las técnicas descriptas arriba. Cada campo está separado por un punto y coma (";"). Notar como la fecha/hora es añadida en cada entrada (línea), junto con los voltajes de los canales analógicos. Este archivo luego se puede importar fácilmente a Excel (ver imagen al comienzo de este post) y realizar gráficos u otros cálculos.






« Última Modificación: julio 04, 2022, 10:57:57 am por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

Atención: Desde el 26 de enero al 21 de febrero de 2023, cerramos por vacaciones. Tenga en cuenta para sus pedidos y/o consultas.

Miguel Gomez

  • Novato
  • *
  • Mensajes: 13
Hola que tal.
El ejemplo disksampler1 vemos que imprime las muestras en formato csv pero en la paginaweb, no como archivo descargable. Queremos usar el disksampler4 (por ser configurable) con la habilidad de escribir a un archivo descargable csv   ya que  las muestras  necesitadas ahora son de 5  veces por segundo.

Podrian ilustrarnos sobre como usar el disklogaddstring, porque tenemos en la compilación un error en la última fila (el ultimo canal. Logrmos descargar archivo csv pero contenido en formato distinto, binario.

gracias
« Última Modificación: julio 01, 2022, 14:03:09 pm por Miguel Gomez »

Soporte

  • Global Moderator
  • Experto
  • *****
  • Mensajes: 2296
  • Soporte Técnico
El ejemplo DiskSamplerLog1 vemos que imprime las muestras en formato csv pero en la paginaweb, no como archivo descargable. Queremos usar el DiskSamplerLog4 (por ser configurable) con la habilidad de escribir a un archivo descargable csv  ya que  las muestras  necesitadas ahora son de 5  veces por segundo.

Podrian ilustrarnos sobre como usar el DiskLogAddString, porque tenemos en la compilación un error en la última fila (el ultimo canal. Logrmos descargar archivo csv pero contenido en formato distinto, binario.

Buenos días Miguel,

Le paso el link al ejemplo DiskSamplerLog1 modificado para que tenga las opciones de DiskSamplerLog4 :

www.slicetex.com/docs/an/an036/files/examples/DiskSamplerLog1B.zip

Si bien, al ser algo tan genérico el ejemplo, es recomendable que en su proyecto lo optimice.

En este caso se ha modificado en función SamplersInit() de archivo Samplers.p para que los archivos del log tengan extensión CSV.

Código: (Pawn) [Seleccionar]
DiskLogInit(1, "vin", "csv", "/web", 36000, 500, DISKLOG_OPT_PPPPPXXX|DISKLOG_OPT_SEMICOLON|DISKLOG_OPT_CIRCULAR|DISKLOG_OPT_FAST_WRITE)

También, como le expliqué en otro ejemplo, puede modificarlo en este lugar para que tengan en el nombre de archivo la fecha YYYYMMDD.csv, si es necesario.

En el evento @OnVinBufFullA() se utiliza el código original del ejemplo DiskSamplerLog1, prácticamente sin cambios, siendo la parte fundamental DiskLogAddString() que escribe texto en el archivo CSV.

Código: (Pawn) [Seleccionar]
@OnVinBufFullA()
{   
   new TimeStart
   
   //
   // Guardar estampa de tiempo del inicio del evento.   
   //
   
   TimeStart = TimeGetMillis()   
   
   //
   // Copiar todas las muestras desde el buffer interno del "sampler" al array temporales.
   //
   // Nota: Las muestras de cada canal son colocadas en una dimensión del array por vez.
   // Como el array tiene dos dimensiones, utilizamos solo un índice para seleccionar el canal,
   // ver definición del array en Samplers.inc.
   //
   
   for(new Ch=0; Ch < SAMPLERS_CH; Ch++)
   {
      VinGetBuf(Ch+1, VinBuf[Ch], 0, SAMPLERS_BUF_SIZE)
   }
   
   //
   // Guardar todas las muestras VIN en la entrada del log de tarjeta Micro-SD.
   //
   
   for(new i=0; i < SAMPLERS_BUF_SIZE; i++)
   {         
      //
      // Atención: El siguiente códígo es para SAMPLERS_CH=5, si es diferente, debe adaptar la función
      // DiskLogAddString() para que tome más o menos argumentos de acuerdo a la cantidad de canales.
      //
     
      if(SAMPLERS_CH == 5)
      {
         // Agregar una entrada con formato de cadena de texto al canal 1 del DiskLog de la tarjeta Micro-SD.
         // Nota[1]: Separamos cada valor con ";" para que cumpla con el formato de archivo CSV.
         // Nota[2]: Los valores analógicos son "float" y llevan punto decimal. En Excel debe especificar si un número tiene "." o "," para el decimal.
         // Nota[3]: Puede convertir a voltaje con VinToVoltage() en una variable intermedia y luego aplicar la función MathScale() para converir a unidades de ingeniería.
         DiskLogAddString(1, "%f;%f;%f;%f;%f",  \
                             VinToVoltage(1, VinBuf[0][i], 12),     \
                             VinToVoltage(2, VinBuf[1][i], 12),     \
                             VinToVoltage(3, VinBuf[2][i], 12),     \
                             VinToVoltage(4, VinBuf[3][i], 12),     \
                             VinToVoltage(5, VinBuf[4][i], 12))
      }
      else
      {
         // Error!... Si SAMPLERS_CH es distinto a 5, debe adaptar este código
         // para que imprima en el archivo CSV más/menos canales.
         DiskLogAddString(1, "Adaptar codigo en @OnVinBufFullA!")
      }
   }
   
   //
   // Calcular tiempo insumido de procesamiento por el evento para mostrar en la página web.
   //
   
   SamplerEventTimeMS = TimeGetMillis() - TimeStart
}


Notar como la función DiskLogAddString() se encarga de imprimir las muestras al archivo de texto en formato CSV:

Código: (Pawn) [Seleccionar]
         DiskLogAddString(1, "%f;%f;%f;%f;%f",  \
                             VinToVoltage(1, VinBuf[0][i], 12),     \
                             VinToVoltage(2, VinBuf[1][i], 12),     \
                             VinToVoltage(3, VinBuf[2][i], 12),     \
                             VinToVoltage(4, VinBuf[3][i], 12),     \
                             VinToVoltage(5, VinBuf[4][i], 12))

Es lo logra con la cadena de formato "%f;%f;%f;%f;%f", donde cada código %f indica que debe remplazarse por un valor float del argumento variable de la función. Colocamos punto y coma ";" como separador, ya que así es el formato CSV.

Por ejemplo, el primer código %f corresponde a VinToVoltage(1, VinBuf[ 0 ][ i ], 12), que convierte a voltaje la muestra almacenada en el array VinBuf[][] del canal 1 a voltaje (ver manual). Ya que las muestras almacenadas por los SAMPLER están en formato binario, por lo que primero se convierten a voltaje y luego lo imprimimos a texto.

También puede colocar el valor de voltaje en una variable intermedia, por ejemplo, en el array Voltage[] y luego imprimir con DiskLogAddString():

Código: (Pawn) [Seleccionar]

new Float: Voltage[6]

Voltage[1] = VinToVoltage(1, VinBuf[0][i], 12)
Voltage[2] = VinToVoltage(2, VinBuf[0][i], 12)
Voltage[3] = VinToVoltage(3, VinBuf[0][i], 12)
Voltage[4] = VinToVoltage(4, VinBuf[0][i], 12)
Voltage[5] = VinToVoltage(5, VinBuf[0][i], 12)

DiskLogAddString(1, "%f;%f;%f;%f;%f",  Voltage[1] , Voltage[2] , Voltage[3], Voltage[4], Voltage[5])

Entonces, si quiere convertir a unidades de ingeniería, puede utilizar la función MathScale(InValue, InMin, InMax, OutMin, OutMax) de forma simple. Esta función, escala el valor InValue entre los límites InMin e InMax a los valores OutMin y OutMax.

Por ejemplo, supongamos que 0V representan 10 °C, mientras que 5V representan 85 °C, hacemos:

MathScale(InValue, 0, 5, 10, 85)

Cualquier valor de InValue entre 0 y 5 será escalado proporcionalmente entre 10 y 85.

Si fuera corriente, por ejemplo supongamos que 4 mA representan 10 °C, mientras que 20 mA representan 85 °C, hacemos:

MathScale(InValue, 4, 20, 10, 85)

Cualquier valor de InValue entre 4 y 20 será escalado proporcionalmente entre 10 y 85.

Entonces, yendo a DiskLogAddString(), podemos remplazar como:

Código: (Pawn) [Seleccionar]

new Float: Sensors[6]

Sensors[1] = MathScale(VinToVoltage(1, VinBuf[0][i], 12), 0, 5, 10, 85)
Sensors[2] = MathScale(VinToVoltage(2, VinBuf[0][i], 12), 0, 5, 10, 85)
Sensors[3] = MathScale(VinToVoltage(3, VinBuf[0][i], 12), 0, 5, 10, 85)
Sensors[4] = MathScale(VinToVoltage(4, VinBuf[0][i], 12), 0, 5, 10, 85)
Sensors[5] = MathScale(VinToVoltage(5, VinBuf[0][i], 12), 0, 5, 10, 85)

DiskLogAddString(1, "%f;%f;%f;%f;%f",  Sensors[1] , Sensors[2] , Sensors[3], Sensors[4], Sensors[5])

Obviamete, si son 6 canales, debés agregar una %f más al código de formato:

Código: (Pawn) [Seleccionar]
DiskLogAddString(1, "%f;%f;%f;%f;%f;%f",  Sensors[1] , Sensors[2] , Sensors[3], Sensors[4], Sensors[5], Sensors[6])

Es cuestión de que lo dejes optimizado y prolijo para tu proyecto específico.

Los códigos de formato admisibles para DiskLogAddString() son los mismos que para la función nLcdPrintf(), por ejemplo %f para float, y %d para enteros, podés ver una explicación de lo códigos en el Manual de Programación, buscar nLcdPrintf(), sección 9.2.

Saludos!

« Última Modificación: julio 04, 2022, 13:27:16 pm por Soporte »
SOPORTE TÉCNICO

Slicetex Electronics
www.slicetex.com

Atención: Desde el 26 de enero al 21 de febrero de 2023, cerramos por vacaciones. Tenga en cuenta para sus pedidos y/o consultas.