jueves, 23 de febrero de 2017

Calibración de sensores y medida. Sensor de fotorresistencia (gl55)



El objetivo es estudiar el comportamiento de la medida de sensores con el fin de mejorar la toma de valores de dichos sensores realizando un calibrado y reducción del ruido.

Se dispone de un sensor de luz LDR para obtener la luminosidad. Como referencia se utiliza el sensor de luz presente en un Smartphone a través de la aplicación Lux Meter.

A continuación, se expone el esquema de conexiones que se utilizará durante la ejecución de las pruebas necesarias 



Cálculo del rando real de valores, puntos de la curva de transferencia y descripción de la linealidad

Para realizar los calculos pertinentes se desarrolla el siguiente código .ino:


#define ldr A0
void setup() {
  pinMode(ldr,INPUT);
  Serial.begin(9600);
}
void loop() {
  int lx=analogRead(ldr);
  Serial.println(lx);
  delay(1000);
}
 Mientras se obtienen las medidas del sensor es necesario obtener la luminosidad a traves de la aplicacion LuxMeter. Es necesario obtener un conjunto de valores representativos de todo el rango. Para cada medida obtenida se obtiene la medida real en la aplicacion:

 
Si se representan los datos obtenidos en un grafico se obtiene lo siguiente:
 




Calibración del offset y sensibilidad asumiendo que la curva es lineal

Realizando una regresion lineal de los datos obtenidos anteriormente es posible obtener lo siguiente:
 
 A partir de la regresion lineal se obtiene que la sensibilidad es 193,5 y el offset es 95,9

Calcular media, mediana y moda

Para calcular estas variables es necesario mantener la luminosidad constante y obtener varios valores:

 

 A través de los resultados se concluye que las medidas que obtiene el sensor son estables, es decir, sin variaciones bruscas. Con dichos resultados es posible determinar los parametros para los siguientes apartados

Calcular la media movil y mostrarla por pantalla. Inferir un valor adecuado para la tolerancia


De los resultados anteriores se deduce que la tolerancia debería ser 1 (aproximación de la desviación típica). Debido a que este valor de tolerancia es demasiado estricto se opta por seleccionar el valor 2.
El algoritmo para el cálculo de la media móvil es el siguiente





 

 El codigo .ino generado a partir del algoritmo anterior es el siguiente

#define ldr A0
int in;
int arr_med[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int leng_med = 10;
int med_min = 8;
int med_max = 913;
int old_index = 0;
int out = 0;
int out_temp = 0;
int tol = 0;
void setup() {
  // put your setup code here, to run once:
  pinMode(ldr, INPUT);
  for(int i=0; i<leng_med;i++){
    arr_med[i]=0;
  }
  leng_med = 10;
  med_min = 10;
  med_max = 950;
  old_index = 0;
  out = 0;
  out_temp = 0;
  tol = 2;
  Serial.begin(9600);
}
int mean_med() {
  float sum = 0;
  for (int i = 0; i < leng_med; i++) {
    sum = sum + arr_med[i];
  }
  return round(sum / leng_med);
}
void loop() {
  in = analogRead(ldr);
  while (in < med_min && in > med_max) {
    in = analogRead(ldr);
  }
 arr_med[old_index] = in;
  old_index = (old_index + 1) % leng_med;
  int mean = mean_med();
  if (in > (mean - tol) && in < (mean + tol)) {
    out = mean;
  }
  Serial.println(out);
  delay(500);
}

Usar una tabla lookup para generar un valor linealizado

En este apartado se construye una tabla lockup con el fin de realizar una regresión lineal utilizando la interpolación.
La tabla lockup utilizada está construida por los mismos valores que el primer apartado: 

 

El valor linealizado se obtiene a partir de la siguiente formula:
 
 




El codigo final en el lenguaje .ino es el siguiente:

#define ldr A0
int real[5] = {0, 74, 323, 626, 934};
int medida[5] = {8, 742, 852, 867, 913};
int n = 5;
void setup() {
  pinMode(ldr, INPUT);
  Serial.begin(9600);
  Serial.println("Tabla Lockup");
  Serial.println("Medida, Real");
  for (int i = 0; i < 5; i++) {
    Serial.print(medida[i]);
    Serial.print(",");
    Serial.println(real[i]);
  }
  Serial.println("");
  Serial.println("-------------");
  Serial.println("");
  Serial.println("Ejecucion de pruebas");
  Serial.println("Medida, Real");
}
void loop() {
  int data_out = 0;
  int data_in = analogRead(ldr);
  if (data_in < medida[10]) {
    data_out = real[0];
  } else if (data_in > medida[n - 1]) {
    data_out = real[n - 1];
  } else {
    int i = 1;
    while (i < (n - 1) && medida[i] < data_in) {
      i++;
    }
    data_out = map(data_in, medida[i - 1], medida[i], real[i - 1], real[i]);
  }
  Serial.print(data_in);
  Serial.print(",");
  Serial.println(data_out);
  delay(1000);
}

Realizar un programa que realice la calibracion lineal, lockuup y muestre valores en base a la media móvil

El programa comenzará pidiendo los valores reales de luminosidad para rellenar la tabla lockup (calibración inicial) y a continuación comienza el bucle principal del programa en el que se linealiza la entrada proveniente del sensor LDR utilizando la tabla lockup, se calcula la media móvil y se muestra por pantalla el valor de la medida

#define ldr A0
int real[5] = {0, 74, 323, 626, 934};
int medida[5] = {8, 742, 852, 867, 913};
int n = 5;
int arr_med[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int leng_med = 10;
int med_min = 8;
int med_max = 913;
int old_index = 0;
int out = 0;
int out_temp = 0;
int tol = 0;
int mean_med() {
  float sum = 0;
  for (int i = 0; i < leng_med; i++) {
    sum = sum + arr_med[i];
  }
  return round(sum / leng_med);
}
void setup() {
  for (int i = 0; i < leng_med; i++) {
    arr_med[i] = 0;
  }
  leng_med = 10;
  med_min = 10;
  med_max = 950;
  old_index = 0;
  out = 0;
  out_temp = 0;
  tol = 2;
  pinMode(ldr, INPUT);
  Serial.begin(9600);
  Serial.println("CALIBRACION DEL SENSOR");
  char continuar = 'n';
  while (continuar == 'n') {
    Serial.println("A continuacion se deberan introducir 5 valores de menor a mayor del sensor de iluminacion");
    int i = 0;
    while (i < n) {
      Serial.print("Introduzca el valor ");
      Serial.println((i + 1));
      while (!Serial.available()) {}
      real[i] = Serial.parseInt();
      medida[i] = analogRead(ldr);
      i++;
    }
    Serial.println("Tabla Lockup");
    Serial.println("Medida, Real");
    for (int i = 0; i < 5; i++) {
      Serial.print(medida[i]);
      Serial.print(",");
      Serial.println(real[i]);
    }
    do {
      Serial.println("¿Los valores son correctos? (y/n)");
      while (!Serial.available()) {
      }
      continuar = (char)Serial.read();
    } while (continuar != 'y' && continuar != 'n');
  }
  med_min = medida[0];
  med_max = medida[n - 1];
  //sustituir med_min med_max
  Serial.println("");
  Serial.println("-------------");
  Serial.println("");
  Serial.println("Ejecucion de pruebas");
}
void loop() {
  int out = 0;
  int in = 0;
  int data_out = 0;
  int data_in = analogRead(ldr);
  Serial.print("ldr");
  Serial.println(data_in);
  if (data_in < medida[0]) {
    data_out = real[0];
  } else if (data_in > medida[n - 1]) {
    data_out = real[n - 1];
  } else {
    int i = 1;
    while (i < (n - 1) && medida[i] < data_in) {
      i++;
    }
    data_out = map(data_in, medida[i - 1], medida[i], real[i - 1], real[i]);
  }
  in = data_out;
  while (in < med_min && in > med_max) {
    in = analogRead(ldr);
  }
  arr_med[old_index] = in;
  old_index = (old_index + 1) % leng_med;
  int mean = mean_med();
  if (in > (mean - tol) && in < (mean + tol)) {
    out = mean;
  }
  Serial.println(out);
  delay(500);
}

No hay comentarios:

Publicar un comentario