El algoritmo KNN ponderado en Arduino

Ya hemos visto como funciona el algoritmo KNN en Arduino, simplemente busca los vecinos más cercanos y mira cuales es la clase más numerosa entre ellos. Esta estrategia puede tener problemas cuando las distintas categorías están muy mezcladas o en puntos que están en la frontera entre dos categorías. En esos casos un punto puede estar muy cerca de unos pocos vecinos de una clase pero la mayoría de vecinos (más lejana) ser de otra clase.

Una forma de solucionar esto es que no todos los vecinos valgan lo mismo. Los más cercanos valen más que los más lejanos. En el algoritmo KNN tradicional cada vecino vale lo mismo «1», en la versión ponderada cada vecino vale una constante fija w dividida por la distancia (w/dist). Ahora sumamos cada uno de esos valores de cada clase y asignamos la clase que más sume. La constate w se usa para evitar que el resultado sea muy pequeño cuando las distancias son muy grandes.

La confianza también cambia, ahora es el valor de la suma de los vecinos de la clase mayoritaria, dividida entre el total de la suma de los pesos de todos los K vecinos.

Un ejemplo lo podemos ver en la imagen de debajo donde los puntos verdes son clasificados como pertenecientes a la clase azul (X) en lugar de a la clase roja (+) si se usa el algoritmo KNN normal, pero son correctamente clasificados si se usa la versión ponderada.

Para K = 3 los puntos verdes son mal clasificados por KNN

La librería ArduinoKNN no contempla este algoritmo por lo que tendremos que implementarlo nosotros usando esta librería como base. Podéis usar la librería Arduino_KNNw que implementa algunas mejoras sobre

En este caso tenemos que usar la función; classifyWeighted(input, K ,w ); Siendo input el elemento a clasificar (un array), K el número de vecinos que se tendrán en cuenta y w la constate por la que se dividirá la distancia, w = 1 por defecto. Si ya sabemos usar Arduino_KNN (si no aquí podéis leerlo) su uso es idéntico:

int class = myKNN.classifyWeighted(input, 3);
float confidence = myKNN.confidence();

Podéis ver un ejemplo aqui.

Asserts de código en Arduino

Un assert es una comprobación que se realiza en el código para verificar que todo es correcto, si la comprobación no es correcta el programa termina. En el caso de Arduino se llama a la función abort() que deshabilita todas las interrupciones y entra en un bucle infinito. Es una medida de precaución para evitar continuar ejecutando un programa cuando algo va mal y no tiene solución o no se sabe que es lo que falla.

Para usar asserts es necesario incluir la librería assert.h. Un assert se escribe usando la función assert pasando como parámetro una comparación lógica que será verdadera o falsa. Si es verdadera el programa continuará, si es falsa se detendrá.

Veamos un ejemplo:

#include <assert.h>
int a = 5;
int b = 1;
int c;

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // esperamos a que el puerto este inicializado
  }
}

void loop() {
  a--;
  divide();
  delay(1000);
}

void divide(){
  assert(a != 0);
  c = b/a;
  Serial.print(b);
  Serial.print("/");
  Serial.print(a);
  Serial.print(" = ");
  Serial.println(c);
}

Este texto mejorado y ampliado forma parte de mi libro sobre como mejorar tus programas en Arduino. Puedes echarle un vistazo aquí.

Puedes echar un vistazo a la versión en vídeo de este entrada:

Haz click para ver el vídeo en mi canal de Youtube

Calcular la altura usando la presión atmosférica y la temperatura. Arduino Nano Sense.

Teniendo un sensor de presión y uno de temperatura podemos hacer el «truco» de estimar la altura de un punto. Para ello usaremos una versión de la ecuación hipsométrica . Para su mayor comprensión voy a des componerla en partes:

Tk = T + 273.15</p>
Pd = (P0 / P) ^ 1/ 5,257
h = (Pd - 1) * Tk / 0,0065

T es la temperatura medida en grados Celsius, Tk es el resultado de convertir a grados Kelvin.

P0 es la presión a nivel del mar o en el nivel que se tome como origen. Ese será el punto h = 0. La presión al nivel del mar es de 1013,25 milibares.

P es la presión en el lugar de la medición.

h es la altura en metros entre los puntos donde se han medido P0 y P.

Esta formula toma alguna simplificaciones, como que T es constante para todas las alturas, despreciar la humedad del aire o considerar la variación de la presión lineal respecto a la altura. Sin embargo suele dar buenos resultados hasta los 9000 metros.

Partiendo del código que ya vimos para leer la temperatura y presión atmosférica con un Arduino Nano Sense solo hemos de añadir los cálculos para hallar la altura:

#include <Arduino_LPS22HB.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!BARO.begin()) {
    Serial.println("Failed to initialize pressure sensor!");
    while (1);
  }
}

float hmean = -1;

void loop() {
  // read the sensor value
  float p = BARO.readPressure(MILLIBAR);

  // print the sensor value
  Serial.print("Pressure = ");
  Serial.print(p);
  Serial.println(" kPa");

  float t = BARO.readTemperature();

  // print the sensor value
  Serial.print("Temperature = ");
  Serial.print(t);
  Serial.println(" C");

  float p0 = 1013.25; //milibares
  float tk = t + 273.15;
  float pd = pow((p0 / p), (1 / 5.257));
  float h = (pd - 1) * tk / 0.0065;
  if(hmean == -1){
    hmean = h;
  } else {
    hmean = (hmean + h) / 2;
  }
  Serial.print("h = ");
  Serial.print(hmean);
  Serial.println(" m");
  // print an empty line
  Serial.println();

  // wait 1 second to print again
  delay(1000);
}

La variable h tiene la altura calculada. Pero no se usa directamente, se usa la variable hmean, que calcula la media de los valores anteriores con el actual. Esto es un truco para suavizar los «saltos» que da debido al ruido de los sensores.

En este caso hemos usado P0 como el valor de la presión atmosférica a nivel del mar, sin embargo P0 puede ser medido en cualquier punto y con eso calcular la altura respecto a ese punto.

Clasificación por vecinos más cercanos. KNN y NN en Arduino.

KNN significa K Nearest Neighbourd o en castellano «los k vecinos más cercanos». Es un algoritmo de clasificación (indica aque clase pertenece uque parte de unos datos de ejemplo ya clasificados contra los que compara con los nuevos datos.

Supongamos que tenemos un montón de ejemplo clasificados. Estos ejemplos están repartidos en un espacio de N dimensiones o, dicho de forma más cercana a los programadores, cada caso es un vector de N elementos. Cuando nos dan un punto nuevo, que no está en los ejemplos, podemos ver de que clase son los K vecinos más cercanos y concluir que el nuevo punto, posiblemente, es de la clase mayoritaria.

Este algoritmo requiere calcular la distancia a cada vecino, ordenarlos según esta distancia y elegir los k primeros.

Implementación

Podemos usar la librería Arduino_KNN.h. No ha sido pensada de propio para Arduino UNO, sin embargo funciona sin problemas con él. Su uso es muy sencillo basta con proporcionar cada uno de los ejemplos y la clase a la que corresponde.

El primer paso es incluir la librería:

#include <Arduino_KNN.h>

Luego creamos una instancia a de la clase KNNClassifier indicando cual es la dimensión de nuestros datos:

KNNClassifier myKNN(2);

Para añadir ejemplos se usa la función addExample(), pasando en el primer parámetro el vector que representa al vecino y en el segundo la clase (que debe de ser un entero).

myKNN.addExample(example1, 1);

Finalmente, cuando todos los ejemplos están añadidos se puede clasifica un elemento con la función classify(); Que toma como primer parámetro el elemento a clasificar y como segundo el número de vecinos K a comparar:

int myKNN.classify(input, k);

Veamos un ejemplo adaptado de los de la librería :

#include <Arduino_KNN.h>

KNNClassifier myKNN(2);

void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.println("Añadiendo ejemplos: ");
  Serial.println();

  // add examples to KNN
  float example1[] = { 7.0, 7.0 }; // clase 1
  float example2[] = { 5.0, 5.0 }; // clase 2
  float example3[] = { 9.0, 9.0 }; // clase 3
  float example4[] = { 6.0, 6.0 }; // clase 2

  myKNN.addExample(example1, 1); // clase 1
  myKNN.addExample(example2, 2); // clase 2
  myKNN.addExample(example3, 3); // clase 3
  myKNN.addExample(example4, 2); // clase 2

  Serial.println("Clasificar entrada:");

  float input[] = { 5.5, 5.5 };

  int classification = myKNN.classify(input, 3); // K = 3

  Serial.print("Clasificacion = ");
  Serial.println(classification);
}

void loop() {

}

Confianza

Hay una medida que puede servir de guía de lo segura que es cada estimación, la confianza. Su valor esta entre 0 y 1, siendo 1 el máximo de confianza. Se calcula tomando todos los vecinos que entran dentro de «los K vecinos más cercanos» se cuentan aquellos cuya clase es mayoritaria y se divide por K. Por ejemplo si tenemos K igual a 5 y hay 3 vecinos de la misma clase C1, la confianza de la clasificación será de 3/5 = 0,6 . Si todos los vecinos fueran de la clase C1 la confianza seria de 5/5 = 1. La clasificación en ambos casos puede ser la misma, la clase C1, pero la confianza no.

Para saber la confianza de una clasificación en la librería Arduino_KNN.h podemos llamar a la función confidence() justo después de realizar la clasificación.

float myKNN.confidence();

NN El vecino más cercano

Tiene una estrategia aún mas simple. Buscas el ejemplo más cercano y le asignas la misma clase. Se la conoce como NN Nearest Neighbourd (el vecino más cercano). Aunque no es la forma más optima de implementarlo se puede como el algoritmo KNN usado K = 1.

 int classification = myKNN.classify(input, 1);

Crear un detector de metales con un magnetómetro o brújula digital.

Vamos a usar un magnetómetro o brújula digital como detector de metales. Para ello vamos a convertir un problema en una ventaja. Cualquier metal magnético cerca del magnetómetro mete ruido en las lecturas, mucho ruido tanto que puede imposibilitar leer los resultados. Usaremos ese ruido para detectar que estamos cerca de un metal magnético o un imán.

En mi caso usaré el magnetómetro del Arduino Nano 33 BLE Sense (ya vimos como leerlo) aunque la ideas sirve cualquier otro magnetómetro, habrá que adaptar el código y los valores empleados.

Realmente es muy sencillo crear un detector de metales. Basta con detectar el ruido y es un ruido tan grande que deja ridículas las lecturas del campo magnético terrestre. Para ello mediremos la intensidad del campo magnético. Lo hacemos elevando al cuadrado el valor de cada eje de magnetómetro, sumándolas y calculando su raíz cuadrada. El del Arduino Nano Sense tiene tres ejes por lo que el calculo lo haremos con el siguiente código.

 IMU.readMagneticField(x, y, z);
 float field = sqrt((x*x) + (y*y) + (z*z))

Ese valor lo podemos comparar con distintos umbrales calculados a base de prueba y error para saber lo cerca que estamos de un metal. En este caso usaremos cuatro niveles, cada uno asociado a un color del LED RGB. Desde «no se detecta nada» a «estas encima de un metal». Lo colores de menos a más son: blanco, verde, amarillo, rojo.

Para evitar verse influido por las condiciones del entorno (por ejemplo que haya metal cerca que hace que siempre se active nuestro detector) puede ser necesario calcular un «offset inicial» cuando se activa el microcontrolador. Este offset es una lectura inicial (la situaremos en la función setup) que se usará para ajustar el valor del campo en el resto de las lecturas. Para decidir si se realiza esta lectura o no se se realiza a través de una constante CALCULATE_OFFSET

if(CALCULATE_OFFSET){
  while(!IMU.magneticFieldAvailable()){    
  }
  IMU.readMagneticField(x, y, z);
  offset = sqrt((x*x) + (y*y) + (z*z));
}

Para corregir el valor del campo respecto de este offset basta con restarlo:

float field = sqrt((x*x) + (y*y) + (z*z))-offset; 

Vamos a juntar todo esto en un ejemplo:

#include <Arduino_LSM9DS1.h>

const bool CALCULATE_OFFSET = true;
float offset = 50; //valor por defecto
float x, y, z;

void setup() {
  Serial.begin(9600);  

  if (!IMU.begin()) {
    Serial.println("Error al inicializar IMU!");
    while (1);
  }
  if(CALCULATE_OFFSET){
    while(!IMU.magneticFieldAvailable()){    
    }
    IMU.readMagneticField(x, y, z);
    offset = sqrt((x*x) + (y*y) + (z*z));
  }

  // activar todos los pins del led RGB
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

}

float oldX, oldY, oldZ;

void loop() {

  float difX, difY, difZ;

  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(x, y, z);
    float field = sqrt((x*x) + (y*y) + (z*z))-offset; 
    if(field > 450){
      Serial.print(field);
      Serial.println(" metal");
      //rojo
      digitalWrite(LEDR, LOW);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
    } else if(field > 150){
      Serial.print(field);
      Serial.println(" metal");
      //amarillo
      digitalWrite(LEDR, LOW);
      digitalWrite(LEDG, LOW);
      digitalWrite(LEDB, HIGH);
    } else if(field > 20){
      Serial.print(field);
      Serial.println(" metal");
      //verde
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, LOW);
      digitalWrite(LEDB, HIGH);
    } else {
      Serial.println(field);
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
    }    
  }
}

Un ultimo detalle, si usas una placa de Arduino como detector de metales, cuida con los pines. Si entran en contacto con el metal pueden producirse un cortocircuito.

Leer el magnetómetro o brújula digital con Arduino Nano 33 BLE Sense (sensor LSM9DS1)

El modulo LSM9DS1 del Arduino Nano 33 BLE sense incluye un magnetómetro o brújula digital de 3 ejes. X , Y y Z. Su función principal es detectar el campo magnético terrestre en cada uno de los ejes de la placa. El eje X va a lo ancho de la placa, el Z a lo largo y el Y es perpendicular.

El primer paso es incluir la librería

#include <Arduino_LSM9DS1.h>

Inicializar el sensor a través de la instrucción IMU.begin() que devolverá true si todo va bien o false si hay algún error durante la inicialización.

  if (!IMU.begin() ) {
    Serial.println("Error al inicializar el sensor");
  }

Para saber si hay alguna lectura disponible se pude usar la función IMU.magneticFieldAvailable()

  if (IMU.magneticFieldAvailable()) {

  }

Para obtener el valor se usa IMU.readMagneticField(x, y, z); Siendo x, y, z tres variables de tipo float donde devolverá los valores del campo magnético en el eje correspondiente:

IMU.readMagneticField(x, y, z);

El campo magnético de mide en microteslas

Veamos todo el código de ejemplo:

#include <Arduino_LSM9DS1.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!IMU.begin()) {
    Serial.println("Error al inicializar el sensor");
  }
}

float x,y,z;

void loop() {
  // comprobar si hay una lectura disponible
  if (IMU.magneticFieldAvailable()) {    
    IMU.readMagneticField(x, y, z);
    Serial.print("x: ");
    Serial.print(x);
    Serial.print(" y: ");
    Serial.print(x);
    Serial.print(" z: ");
    Serial.println(z);
  }
  delay(500);  
}

Sensor de proximidad con Arduino Nano 33 BLE Sense (sensor APDS9960)

Además de leer colores, gestos y luz ambiental, el sensor APDS9960es capaz de leer la proximidad de un objecto al mismo.

El primer paso es incluir la librería

#include <Arduino_APDS9960.h>

Inicializar el sensor a través de la instrucción APDS.bgin() que devolverá true si todo va bien o false si hay algún error durante la inicialización.

  if (!APDS.begin()) {
    Serial.println("Error al inicializar el sensor");
  }

Para saber si hay alguna lectura disponible se pude usar la función APDS.proximityAvailable()

  if (APDS.proximityAvailable()) {

  }

Para obtener el valor se usa APDS.readProximity()

int proximity = APDS.readProximity();

La lectura devuelve un int cuyo valor puede ser positivo entre 0 y 255 (aunque en mis pruebas no he logrado que pase de 252) que indica la distancia (a menor valor más cerca) o -1 que indica una lectura errónea del sensor. La lectura no viene en ninguna unidad de medida y habrá que convertirla realizando pruebas en una situación ambiental similar a la que se vaya a usar. De todas formas este valor hay que tomarlo más como una referencia que como un valor exacto. Por ejemplo los valores que pasan e 250 pueden interpretarse como («no hay nada cerca»), el valor 0 no indica «sobre el sensor» se alcanza con el objeto a unos 3 o 4 centímetros del mismo.

Veamos todo el código junto:

#include <Arduino_APDS9960.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!APDS.begin()) {
    Serial.println("Error al inicializar el sensor");
  }
}

void loop() {
  // comprobar si hay una lectura disponible
  if (APDS.proximityAvailable()) {
    int proximity = APDS.readProximity();
    Serial.println(proximity);
  }
  delay(500);  
}

Controlar el LED RGB de Arduino Nano 33 BLE Sense

Arduino Nano 33 BLE Sense incorpora un led RGB que permite mostrar distintos colores. Cada canal RGB (rojo, verde y azul) se controla de forma independiente. Su encendido y apagado va asociado al estado de un pin digital:

  • Rojo – Pin 22
  • Verde – Pin 23
  • Azul – Pin 24

Combinando los tres distintos colores se pueden conseguir 8 combinaciones: rojo, verde, azul, amarillo, rosa, celeste, blanco y apagado.

El primer paso es configurar el pin de cada LED como escritura. Cada pin tiene asociada una constante: LEDR, LEDG, LEDB.

  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

Una vez hecho eso podemos controlar el estado de cada color con digitalWrite.

Una cosa a tener en cuenta, y que puede volverte loco, es que los leds funcionan con lógica inversa: el estado LOW los enciende y el estado HIGH los apaga.

Veamos todo esto en un ejemplo que cambia el color del LED cada dos segundos:

void setup() {
  // activar todos los pins del led RGB
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);
}

void loop() {
  //blanco
  digitalWrite(LEDR, LOW);
  digitalWrite(LEDG, LOW);
  digitalWrite(LEDB, LOW);
  delay(2000);
  //rojo
  digitalWrite(LEDR, LOW);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);
  delay(2000);
  //verde
  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, LOW);
  digitalWrite(LEDB, HIGH);
  delay(2000);
  //azul
  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, LOW);
  delay(2000);
  //amarillo
  digitalWrite(LEDR, LOW);
  digitalWrite(LEDG, LOW);
  digitalWrite(LEDB, HIGH);
  delay(2000);
  //rosa
  digitalWrite(LEDR, LOW);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, LOW);
  delay(2000);
  //celeste
  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, LOW);
  digitalWrite(LEDB, LOW);
  delay(2000);  
  //apagado 
  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);
  delay(2000);  
}

Leer gestos con Arduino Nano 33 BLE Sense (sensor APDS9960)

Arduino Nano 33 BLE Sense incluye un sensor de gestos. Su funcionamiento es muy sencillo, tiene cuatro detectores infrarrojos con un led emisor. Cada uno está colocado en una de la esquinas del sensor. Cuando pasas la mano por encima de cada uno de los detectores se reflejan los infrarrojos en la piel y detectan el gesto. Viendo en qué orden los sensores detectan la mano sabe en qué dirección ocurre el gesto.

Este sistema tiene varios problemas:

  • Distancia de funcionamiento, el gesto tiene que realizarse cerca del sensor.
  • En según qué entornos puede dar lecturas falsas.
  • Puede tener problemas para detectar gestos con las manos sucias o con guantes.

Hablamos de manos pero realmente lee cualquier elemento que refleje suficiente luz infrarroja.

El sensor lee cuatro tipos gestos: arriba, abajo, izquierda, derecha.

Cada gesto tiene asociada una constante: GESTURE_UP, GESTURE_DOWN, GESTURE_LEFT, GESTURE_RIGHT.

También existe una constate para indicar que no se ha entendido el gesto: GESTURE_NONE.

Tal y como está colocado el sensor para leer correctamente los gestos el conector USB debe de quedar en la parte «inferior».

Lo primero es incluir la librería del sensor, que creara un objeto APDS:

#include <Arduino_APDS9960.h>

Después hay que ver iniciar el sensor con APDS.begin()

  if (!APDS.begin()) {
    Serial.println("Error al iniciar el sensor");
  }

Una vez el sensor está listo podemos comprobar si ha leído algún gesto con la instrucción APDS.gestureAvailable() que devolverá true cuando hay captado algún gesto. El gesto correspondiente lo podemos obtener con APDS.readGesture().

Veamos un código, adaptado de los ejemplos, para leer gestos:

#include <Arduino_APDS9960.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!APDS.begin()) {
    Serial.println("Error al iniciar el sensor");
  }
}

void loop() {
  //comprobar si se ha detectado algún gesto
  if (APDS.gestureAvailable()) {
    int gesture = APDS.readGesture();
    switch (gesture) {
      case GESTURE_UP:
        Serial.println("UP - arriba");
        break;

      case GESTURE_DOWN:
        Serial.println("DOWN - abajo");
        break;

      case GESTURE_LEFT:
        Serial.println("LEFT - izquierda");
        break;

      case GESTURE_RIGHT:
        Serial.println("RIGHT - derecha");
        break;

      default:        
        break;
    }
  }
}

Podemos ajustar la sensibilidad del sensor a los gestos con la instrucción APDS.setGestureSensitivity(sensitivity) siendo sensitivity un valor entre 0 y 100. Por defecto su valor es de 80. A más alto sea su valor más sensibilidad tendrá a los gestos, lo que significa que captará los mejor los gestos pero a cambio será más probable que lea gestos «erroneos».

Comparar temperaturas de los sensores en Arduino Nano 33 BLE Sense

Arduino Nano 33 BLE Sense tiene dos sensores que permiten leer la temperatura en grados centigrados: HTS221 y LPS22HB.

Leer los dos puede ser una manera de verificar los datos. Dentro del rango de temperatura normales para el ser humano deberían de dar resultados muy parecidos.

Es necesario incluir las librerías para ambos sensores e inicializarlos con begin().

Para poder leer la temperatura del sensor LPS22HB es necesario leer primero la presión.

Si queremos podemos aproximar la temperatura final con una media de ambas temperaturas.

Juntemos todo esto en un ejemplo:

#include <Arduino_LPS22HB.h>
#include <Arduino_HTS221.h>
void setup() {
  Serial.begin(9600);
  while (!Serial);
  if (!BARO.begin() || !HTS.begin()) {
    Serial.println("Failed to initialize sensor!");
    while (1);
  }
}
void loop() {
  float temperature1 = HTS.readTemperature();
  BARO.readPressure();
  float temperature2 = BARO.readTemperature();
  float mean = (temperature1+temperature2)/2;
  Serial.print("Temperature1 = ");
  Serial.print(temperature1);
  Serial.println(" C");
  Serial.print("Temperature2 = ");
  BARO.readPressure();
  Serial.print(temperature2);
  Serial.println(" C");
  Serial.print("Mean = ");
  Serial.print(mean);
  Serial.println(" C");
  Serial.println();
  delay(1000);
}

Veamos la salida de ejecutar el código:

Temperature1 = 26.47 C 
Temperature2 = 26.41 C
Mean = 26.44 C

Temperature1 = 26.52 C
Temperature2 = 26.41 C
Mean = 26.47 C

Temperature1 = 26.52 C
Temperature2 = 26.42 C
Mean = 26.47 C

Temperature1 = 26.45 C
Temperature2 = 26.42 C
Mean = 26.43 C

Temperature1 = 26.50 C
Temperature2 = 26.42 C
Mean = 26.46 C

Se puede ver que la temperatura no varía demasiado entre ambos sensores.