← Índice del curso

Microcontroladores · Tema 36

Lectura de sensores: acondicionamiento y calibración

Conectar un sensor y leer un número es el comienzo. Para convertir ese número en una medida en la que se pueda confiar hay que preparar la señal antes del conversor, corregir los errores del sensor con una calibración, domar el ruido con filtros y desconfiar de lo que no tiene sentido. Este tema reúne las técnicas que separan un termómetro de juguete de un instrumento.

01 · Punto de partida

De la lectura a la medida

En el taller del tema 30 convertiste el código de un ADC en grados con una fórmula. Pero ¿cuánto vale ese número? El LM35 tiene una exactitud de décimas de grado en el mejor de los casos; la referencia de 1,1 V tiene una tolerancia del 10 %; una resistencia del divisor tiene el 1 %; y la lectura salta porque hay ruido. El resultado puede tener cuatro cifras y ser correcto en una sola.

Medir bien es una cadena de pasos, y cada uno puede arruinar el resultado o mejorarlo:

Cadena de medición completa Un sensor entrega una señal que se acondiciona (divisor, amplificador, filtro), se convierte con un ADC, se calibra y se pasa a unidades, se filtra digitalmente y se valida antes de usarla. Sensormagnitud física Acondicionardivisor · ganancia · filtro ADCcódigo de 10 bits Calibraroffset, ganancia, unidades Filtrarpromedio, mediana Validarrango, saltos, falla hardware analógicosoftware

Los temas 27 a 30 ya trataron el conversor; acá nos ocupamos de lo que va antes y después de él.

02 · Tipos de sensores

Qué entrega cada sensor

Sensores según su salida y cómo se leen.
SalidaEjemplosCómo se leeCuidados
Tensión proporcionalLM35, potenciómetro, acelerómetro analógicoADC directoRango, ruido, referencia
Resistencia variableNTC, fotorresistor, sensor de flexiónDivisor o puente + ADCNo linealidad, autocalentamiento
Corriente (lazo 4–20 mA)Transmisores industriales de presión o nivelResistencia de 250 Ω → 1 a 5 VEl 4 mA como cero detecta el cable roto
Puente de bajo nivel (mV)Celda de carga, galga extensométricaAmplificador de instrumentación o conversor de 24 bits (HX711)Señales de milivolts, ruido y deriva
Digital por busBME280, MPU6050, TMP102I2C o SPI (temas 33 y 34)Coeficientes de compensación de fábrica
Pulsos o frecuenciaAnemómetro, caudalímetro, ultrasonido (duración del eco)Contador o captura de un temporizador (tema 24)Rebotes, resolución temporal

Los sensores digitales ya entregan un valor convertido y suelen traer su propia compensación, por eso son tentadores. Pero el procedimiento de este tema vale igual: hay que verificar el rango, filtrar si hace falta, y calibrar contra una referencia cuando se busca exactitud.

03 · Vocabulario

Características de un sensor

La hoja de datos de un sensor está llena de términos que conviene distinguir:

Términos básicos de una medición.
TérminoQué significa
RangoValores mínimo y máximo que puede medir el sensor
SensibilidadCambio de la salida por unidad de la magnitud (por ejemplo 10 mV/°C)
OffsetSalida cuando la magnitud vale cero
ResoluciónMenor cambio que se puede distinguir (limitado por el ADC y el ruido)
ExactitudQué tan cerca está la medición del valor verdadero
Precisión o repetibilidadQué tan parecidas son mediciones repetidas de lo mismo
LinealidadCuánto se aparta la salida de una recta
HistéresisDiferencia de la lectura según se llegue desde arriba o desde abajo
DerivaCambio lento de la salida con el tiempo o la temperatura
Tiempo de respuestaLo que tarda en reflejar un cambio (un termistor con funda: segundos o minutos)

Dos confusiones merecen atención. Resolución no es exactitud: un conversor de 16 bits conectado a un sensor de ±1 °C da números con cuatro decimales, de los cuales solo importa el primero. Y precisión no es exactitud: un instrumento puede dar siempre el mismo valor (muy preciso) con un error constante de 2 °C (poco exacto). La calibración corrige este último tipo de error, el sistemático; el ruido aleatorio se trata con filtros.

04 · Antes del ADC

Acondicionar la señal

El objetivo del acondicionamiento es hacer que la señal del sensor ocupe todo el rango del ADC, con la menor cantidad de ruido posible. Las herramientas más usadas:

  • Divisor resistivo. Reduce tensiones altas al rango del ADC: Vsal = Vent · R2 / (R1 + R2). Cuidar la impedancia de fuente (tema 27).
  • Amplificación. Un sensor de milivolts desperdicia casi todo el rango del ADC. Un amplificador no inversor con ganancia G = 1 + Rf/Rg sube la señal. Una celda de carga de 2 mV/V con 5 V de excitación entrega 10 mV a fondo de escala: con ganancia 100 llega a 1 V y con la referencia de 1,1 V usa 930 cuentas (10,8 g por cuenta para 10 kg) en lugar de 9 (1,1 kg por cuenta).
  • Offset y escala. Un sensor que entrega de −1 V a +1 V se desplaza y se escala (con un amplificador operacional) a 0–5 V; el ADC solo mide positivos.
  • Lazo de corriente. Un transmisor industrial de 4 a 20 mA se convierte con una resistencia de 250 Ω en 1 a 5 V. El 4 mA que representa «cero» tiene una ventaja: 0 mA (cable cortado) es una falla evidente.
  • Filtro antialias y de ruido. Un RC pasa-bajos antes del ADC (tema 27) elimina el ruido de alta frecuencia.
  • Protección. Una resistencia en serie (1 kΩ) con diodos de sujeción o un zener evita que un pico dañe el pin del microcontrolador.

Con las señales muy pequeñas (puentes de milivolts) se usan conversores dedicados de 24 bits y ganancia programable, como el HX711. Resuelven el amplificador y el ADC juntos, y el microcontrolador solo lee un número por una interfaz serie.

05 · Corregir el sistema

Calibración

Los errores sistemáticos (el offset del sensor, la tolerancia de la referencia, las resistencias) son constantes y se pueden medir y restar. Calibrar es medir cómo responde el sistema ante valores conocidos y guardar la corrección. Hay tres niveles:

  • Un punto (offset). Se mide una referencia conocida (agua con hielo a 0 °C) y se resta la diferencia. Corrige el offset, pero no un error de ganancia.
  • Dos puntos (offset y ganancia). Se mide en dos valores, lo más separados posible dentro del rango de trabajo, y se calcula una recta: valor = ref1 + (lectura − lec1) · (ref2 − ref1) / (lec2 − lec1). Es la calibración estándar.
  • Varios puntos. Para sensores no lineales se mide en muchos valores y se interpola entre ellos con una tabla, o se ajusta un polinomio. Es lo que hace el BME280 con sus coeficientes de fábrica.

Un ejemplo con el LM35 y la referencia de 1,1 V: con agua y hielo (0,0 °C) la lectura es 6 y con agua a 40,0 °C (medida con un termómetro de referencia) es 375. La pendiente es 40 / 369 = 0,1084 °C por cuenta (la ideal era 0,1074) y el offset es −0,65 °C. Con la lectura 234, la fórmula sin calibrar daba 25,14 °C; la calibrada da 24,72 °C: un error de 0,4 °C que la calibración eliminó.

Reglas para calibrar bien:

  • Usá una referencia mejor que el sensor (un termómetro certificado, un peso patrón, un voltímetro de buena calidad): la calibración no puede ser más exacta que su referencia.
  • Elegí puntos en los extremos del rango de trabajo, no en el centro.
  • Esperá a que el sensor se estabilice en cada punto (térmico, mecánico).
  • Medí un punto intermedio de verificación: si la recta falla ahí, el sensor no es lineal y hace falta más de dos puntos.
  • Guardá los coeficientes en la EEPROM (tema 8) para que sobrevivan a un reinicio, con valores de fábrica por defecto y una suma de verificación.
  • Repetí la calibración si cambian las condiciones: otra placa, otra alimentación, otro sensor.
#include <avr/eeprom.h>

typedef struct { int16_t lec1, lec2; int32_t ref1, ref2; } Calib;   // referencias en centésimas
static Calib EEMEM calib_ee = { 6, 375, 0, 4000 };                  // valores de fábrica

// Convierte una lectura de 10 bits a centésimas de grado con la recta de dos puntos
static int32_t calibrar(uint16_t lectura, const Calib *c) {
    int32_t span_ref = c->ref2 - c->ref1;
    int32_t span_lec = (int32_t)c->lec2 - c->lec1;
    return c->ref1 + ((int32_t)lectura - c->lec1) * span_ref / span_lec;   // 1023 * 4000 cabe en 32 bits
}

/* al arrancar:  Calib c;  eeprom_read_block(&c, &calib_ee, sizeof c);
   para recalibrar:  eeprom_update_block(&c, &calib_ee, sizeof c);   */

06 · Cuentas sin coma flotante

Unidades con aritmética entera

Un AVR de 8 bits no tiene unidad de coma flotante: cada float se emula con subrutinas que ocupan Flash (1 a 2 KB) y tardan decenas de microsegundos. La alternativa es la aritmética de punto fijo: se trabaja con enteros que representan la magnitud multiplicada por una potencia de 10 o de 2.

  • Escala decimal. Guardar la temperatura en centésimas (2472 = 24,72 °C) o la presión en milibares. Para mostrarla, se divide y se imprime el resto con ceros a la izquierda (tema 32).
  • Escala binaria. Multiplicar por una pendiente fraccionaria se hace con un factor entero y un desplazamiento: (lectura − lec1) · M >> 10, donde M es la pendiente por 1024. Con la pendiente 10,84 cent/cuenta, M = 11 100 y el error de la versión entera frente a la de coma flotante es de 1,08 centésimas de grado como máximo, mucho menos que lo que importa.
  • Desbordamientos. Siempre hay que preguntarse cuál es el valor máximo intermedio: 1023 × 11 100 son 11,3 millones, que exige 32 bits (tema 10). Un int de 16 bits fallaría sin avisar.
  • Redondeo. Una división entera trunca; sumar la mitad del divisor antes de dividir redondea al más cercano.

Cuándo usar float: en prototipos y en cálculos complicados (logaritmos del termistor, tema 30) que se hacen pocas veces por segundo. En cálculos frecuentes y simples (promedios, escalados), el punto fijo ahorra memoria y tiempo.

07 · Domar el ruido

Filtrado digital

El filtro correcto depende del tipo de ruido. Tres técnicas cubren casi todo:

  • Media móvil. Promedia las últimas N lecturas. Reduce el ruido aleatorio por √N y retrasa la respuesta unas N/2 muestras. Un pico aislado se reparte entre las N muestras de la ventana. Se implementa con un buffer circular y una suma acumulada.
  • Filtro exponencial (IIR de primer orden): y += (x − y) / 2k. Una resta, un desplazamiento y una suma; no necesita buffer. La constante de tiempo es de unas 2k muestras.
  • Mediana. Ordena las últimas N lecturas y elige la del medio. Descarta por completo los valores aislados (picos) sin desdibujar los escalones. Es la mejor para interferencias esporádicas; reduce poco el ruido continuo.

Se pueden combinar: mediana de 3 o 5 para eliminar picos y después un promedio para suavizar. Todo filtro tiene un precio: retardo. Un filtro que deja la señal muy limpia pero tarda un segundo en responder sirve para una temperatura y no para un control rápido.

// Media móvil de N = 8 (potencia de 2) con suma acumulada
#define MA_N 8
static uint16_t ma_buf[MA_N];
static uint32_t ma_suma;
static uint8_t  ma_i;

static uint16_t media_movil(uint16_t x) {
    ma_suma += x;  ma_suma -= ma_buf[ma_i];
    ma_buf[ma_i] = x;
    ma_i = (uint8_t)((ma_i + 1) & (MA_N - 1));
    return (uint16_t)(ma_suma / MA_N);              // al principio el buffer vacío da valores bajos: se inicializa con la primera lectura
}

// Filtro exponencial con k bits fraccionarios (evita la zona muerta del truncamiento)
#define EMA_K 3
static int32_t ema_acc;                             // valor × 2^K
static uint16_t exponencial(uint16_t x) {
    ema_acc += (int32_t)x - (ema_acc >> EMA_K);
    return (uint16_t)(ema_acc >> EMA_K);
}

// Mediana de tres: elimina un pico aislado
static uint16_t mediana3(uint16_t a, uint16_t b, uint16_t c) {
    if (a > b) { uint16_t t = a; a = b; b = t; }     // a <= b
    if (b > c) b = c;                              // b = min(b, c)
    return a > b ? a : b;                          // máximo de a y b
}

El filtro exponencial tiene una trampa que conviene conocer. La versión «obvia» y += (x − y) >> k trabaja con enteros: cuando la diferencia es menor que 2k, el desplazamiento da 0 y y deja de avanzar: queda a hasta 2k − 1 cuentas del valor final (una zona muerta). Con k = 4 son 15 cuentas, más que el ruido que se quería filtrar. La solución es acumular con k bits fraccionarios, como en el código de arriba.

08 · Datos sospechosos

Desconfiar de la lectura

Un programa que usa cualquier lectura como verdad absoluta fallará algún día: un cable se corta, un conector se afloja, un sensor se moja. Algunas comprobaciones baratas detectan casi todo:

  • Rango. Un código de 0 o de 1023 (o de un extremo del lazo de 4–20 mA) indica corto, circuito abierto o saturación, no una medida válida (tema 30).
  • Velocidad de cambio. Una temperatura no sube 20 °C en un segundo. Un salto imposible es una interferencia o una falla.
  • Valor congelado. Un sensor ruidoso que de pronto da siempre exactamente lo mismo puede estar desconectado o colgado.
  • Redundancia. Dos sensores independientes que difieren mucho señalan que uno falla.
typedef enum { SENSOR_OK, SENSOR_FUERA_DE_RANGO, SENSOR_SALTO } EstadoSensor;

static EstadoSensor validar(uint16_t lectura, uint16_t anterior) {
    if (lectura < 10 || lectura > 1013) return SENSOR_FUERA_DE_RANGO;       // en corto o abierto
    uint16_t d = lectura > anterior ? lectura - anterior : anterior - lectura;
    if (d > 100) return SENSOR_SALTO;                                          // cambio imposible entre lecturas
    return SENSOR_OK;
}

Qué hacer cuando se detecta una falla es una decisión de diseño: mantener el último valor bueno, mostrar un error, pasar a un estado seguro. Un calefactor que sigue encendido porque el sensor se desconectó (y leyó «frío») es un clásico accidente evitable con una comprobación de rango.

09 · Cuánto se confía

Presupuesto de errores

La exactitud de una medición es la suma de las exactitudes de la cadena. Se hace una lista con cada fuente de error, convertida a las mismas unidades:

Ejemplo: termómetro de 0 a 100 °C con ADC de 10 bits (resolución 0,098 °C).
FuenteDatoError en °C
Sensor±0,5 °C0,5
Conversor (offset, ganancia, linealidad)±2 LSB0,195
Referencia±1 % del fondo de escala1,0
Resistencias del acondicionamiento±0,1 %0,1
Ruido1 cuenta0,098
Peor caso (suma)1,89
Suma cuadrática (errores independientes)1,14

Tres lecciones. La referencia es el mayor aporte: con una referencia más precisa o con una medición ratiométrica (tema 27) el total baja mucho. La resolución (0,098 °C) es veinte veces menor que el error total: más bits no mejoran nada, y usar un conversor de 16 bits con esta cadena sería un derroche. Y la calibración elimina la mayor parte de los errores sistemáticos (referencia, ganancia, offset) pero no el ruido, la deriva ni la exactitud del instrumento de referencia.

10 · Analogía con programación

Calibrar y filtrar con datos simulados

Este programa calibra un LM35 con dos puntos en aritmética entera y mide el error frente a la versión de coma flotante, compara siete filtros sobre una señal con un escalón, ruido y picos (incluida la zona muerta del filtro exponencial entero), calcula el presupuesto de errores del ejemplo y las conversiones de un lazo de 4–20 mA y de una celda de carga.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

import math
import random

# 1) calibracion de dos puntos con aritmetica entera (centesimas de grado, pendiente x 1024)
raw1, v1 = 6, 0          # agua con hielo: 0,00 C
raw2, v2 = 375, 4000     # 40,00 C medidos con un termometro de referencia
pendiente = (v2 - v1) / (raw2 - raw1)            # centesimas por cuenta
M = round(pendiente * 1024)

def calibrado_float(raw):
    return v1 + (raw - raw1) * pendiente

def calibrado_entero(raw):
    return v1 + (((raw - raw1) * M) >> 10)

peor = max(abs(calibrado_entero(r) - calibrado_float(r)) for r in range(raw1, raw2 + 1))
print(f"pendiente = {pendiente:.4f} cent/cuenta, M = {M} (x1024)")
print(f"lectura 234: sin calibrar {234 * 1100 / 1024 / 10:.2f} C, calibrada {calibrado_float(234) / 100:.2f} C, entera {calibrado_entero(234) / 100:.2f} C")
print(f"error maximo de la version entera: {peor:.2f} centesimas de grado")

# 2) filtros sobre un escalon con ruido y picos
def senal(seed=7, ruido=3, picos=0.03, n=100, escalon=50):
    r = random.Random(seed)
    verdad = [100 if i < escalon else 200 for i in range(n)]
    x = []
    for t in verdad:
        v = t + r.uniform(-ruido, ruido)
        if r.random() < picos:
            v += 80 if r.random() < 0.5 else -80
        x.append(round(v))
    return verdad, x

def media_movil(x, n):
    return [sum(x[max(0, i - n + 1):i + 1]) / len(x[max(0, i - n + 1):i + 1]) for i in range(len(x))]

def exponencial_entero(x, k):
    y, salida = x[0], []
    for v in x:
        y += (v - y) >> k                    # truncamiento: zona muerta de hasta 2^k - 1
        salida.append(y)
    return salida

def exponencial_fraccionario(x, k):
    acc, salida = x[0] << k, []              # el acumulador guarda k bits fraccionarios
    for v in x:
        acc += v - (acc >> k)
        salida.append(acc >> k)
    return salida

def mediana(x, w):
    salida = []
    for i in range(len(x)):
        ventana = sorted(x[max(0, i - 2 * ((w - 1) // 2)):i + 1])
        salida.append(ventana[len(ventana) // 2])
    return salida

def metricas(verdad, y, escalon=50):
    pasos = list(range(25, escalon)) + list(range(80, len(y)))
    rms = math.sqrt(sum((y[i] - verdad[i]) ** 2 for i in pasos) / len(pasos))
    retardo = next((i - escalon for i in range(escalon, len(y)) if y[i] >= 190), None)
    peor = max(abs(y[i] - verdad[i]) for i in range(5, len(y)) if i < escalon - 2 or i > escalon + 30)
    return rms, retardo, peor

verdad, x = senal()
print()
print("filtro                   error eficaz  retardo al 90 %  peor error")
for nombre, y in (("sin filtro", x), ("media movil de 4", media_movil(x, 4)), ("media movil de 16", media_movil(x, 16)),
                  ("exponencial k=2", exponencial_entero(x, 2)), ("exponencial k=4 (entero)", exponencial_entero(x, 4)),
                  ("exponencial k=4 (fraccion.)", exponencial_fraccionario(x, 4)), ("mediana de 5", mediana(x, 5))):
    rms, ret, peor = metricas(verdad, y)
    print(f"{nombre:26s} {rms:8.2f}      {str(ret) + ' muestras' if ret is not None else 'no llega':>14s}   {peor:7.0f}")

# 3) presupuesto de errores de un termometro de 0 a 100 C con 10 bits
rango, cuenta = 100.0, 100.0 / 1024
errores = {"sensor": 0.5, "conversor (2 LSB)": 2 * cuenta, "referencia 1 %": 1.0, "resistencias 0,1 %": 0.1, "ruido (1 cuenta)": cuenta}
print()
print({k: round(v, 3) for k, v in errores.items()})
print(f"peor caso {sum(errores.values()):.2f} C, suma cuadratica {math.sqrt(sum(v * v for v in errores.values())):.2f} C, resolucion {cuenta:.3f} C")

# 4) lazo de corriente de 4 a 20 mA con una resistencia de 250 ohm sobre un sensor de presion de 0 a 10 bar
print()
for bar in (0, 5, 10):
    ma = 4 + 16 * bar / 10
    v = ma / 1000 * 250
    print(f"{bar:2d} bar -> {ma:5.2f} mA -> {v:4.2f} V -> codigo {min(1023, int(v / 5 * 1024))}")
print("cable cortado (0 mA) -> 0 V -> codigo 0: por debajo de 0,9 V es una falla, no una presion")

# 5) celda de carga de 2 mV/V con 5 V de excitacion: 10 mV a fondo de escala
fs_mv = 2 * 5
for ganancia in (1, 100):
    tension = fs_mv * ganancia / 1000
    cuentas = min(1023, int(tension / 1.1 * 1024))
    print(f"ganancia {ganancia:3d}: {tension:.2f} V a 10 kg -> {cuentas} cuentas -> {10000 / max(1, cuentas):.1f} g por cuenta")

Resultado: la calibración corrige la lectura 234 de 25,14 °C a 24,72 °C, y la versión entera difiere de la de coma flotante en 1,08 centésimas como máximo. En la comparación de filtros, la mediana de 5 deja un error eficaz de 1,48 contra 11,65 sin filtro, con 2 muestras de retardo; el promedio de 16 baja a 3,03 pero tarda 14 muestras; el exponencial entero con k = 4 nunca llega al 90 % del escalón (zona muerta) y con bits fraccionarios sí, tras 39 muestras. El presupuesto da ±1,89 °C en el peor caso. Un lazo de 4–20 mA con 250 Ω da 1 V a 0 bar y 5 V a 10 bar, y una celda de carga pasa de 9 a 930 cuentas al amplificar por 100.

Los números de los filtros dependen de la semilla del generador de ruido; lo que importa es la comparación entre ellos.

11 · Exploración interactiva

Calibración, filtros y errores

La primera herramienta calcula la recta de calibración de dos puntos y la compara con la versión entera. La segunda simula un escalón con ruido y picos y aplica el filtro que elijas. La tercera suma el presupuesto de errores de tu cadena.

Banco de medición

1. Calibración de dos puntos

Recta de calibración—
Valor calibrado—
Versión entera—
Verificación—

2. Filtros sobre un escalón con ruido

Ruido residual—
Retardo—
Picos—

3. Presupuesto de errores

Resolución—
Aportes—
Peor caso—
Caso estadístico—

Recorrido guiado

  1. Con los valores de partida, la recta es 0,1084 unidades por cuenta con offset −0,65, y la lectura 234 da 24,715. La versión entera (pendiente × 1024) difiere en menos de una milésima. La nota compara con la calibración de un solo punto (24,49).
  2. Cargá el punto intermedio: lectura 200, referencia 20,5. La recta predice 21,03: el residuo de −0,53 indica que el sensor no es perfectamente lineal, o que hay un error en alguna referencia.
  3. En los filtros, con ruido 3 y picos 3 %: sin filtro el error eficaz es 15,8 cuentas. La media de 4 baja a 4,9 con 3 muestras de retardo; la media de 16, a 2,8 con 14; la mediana de 5, a 1,4 con 2 muestras y sin sufrir los picos.
  4. Con el exponencial y k = 2 el filtro funciona (3,95; 8 muestras). Con k = 4 el filtro entero nunca llega al 90 %: se detiene a 15 cuentas del valor final. Es la zona muerta del truncamiento.
  5. Subí los picos a 10 %: la media se ve muy afectada y la mediana casi no.
  6. En el presupuesto, con los valores del ejemplo, el peor caso es ±1,89 y el aporte mayor es la referencia. Pasá a 16 bits: la resolución mejora 64 veces y el total baja apenas un 15 %.
Desafío: ¿cuántos puntos para un NTC?

El termistor del tema 30 no es lineal: entre 0 y 100 °C su resistencia cambia más de 30 veces. Una calibración de dos puntos con una recta daría errores de varios grados en el centro. Tres opciones: (1) la ecuación Beta con β medido en dos puntos (da errores de unos pocos décimos en un rango de 30 °C); (2) la ecuación de Steinhart-Hart con tres puntos de calibración; (3) una tabla de 16 a 32 puntos con interpolación lineal y puntos más densos donde la curva es más pronunciada (los extremos). Para una temperatura ambiente de 15 a 35 °C, la ecuación Beta y dos puntos alcanzan.

12 · Comprensión

Confusiones frecuentes

«Un conversor de más bits mide mejor»

Solo si el resto de la cadena es mejor que su resolución. Con un sensor de ±1 °C, pasar de 10 a 16 bits agrega decimales sin agregar verdad.

«Promediar elimina todos los errores»

Reduce el ruido aleatorio. No corrige el offset, la ganancia ni la deriva, que son sistemáticos y se calibran, y no sirve si la señal cambia durante el promedio.

«Calibro una vez y me olvido»

Los sensores derivan con el tiempo y la temperatura. Cualquier cambio en la cadena (otro sensor, otra alimentación, otra placa) invalida la calibración.

«La media móvil es siempre mejor que la mediana»

Contra el ruido continuo, sí; contra picos aislados, no: la media reparte el pico entre todas las muestras de la ventana y la mediana lo descarta.

«Mi lectura es muy estable, así que es exacta»

Estable es preciso, no exacto. Un error sistemático constante (offset, referencia) da lecturas muy estables y erróneas. Solo una referencia externa lo revela.

13 · Práctica guiada

Predecí antes de comprobar

1. Calibrar con dos puntos

Un sensor da la lectura 20 cuando vale 1,5 unidades y 980 cuando vale 98,7. ¿Qué valor corresponde a la lectura 500?

Ver solución

Pendiente = (98,7 − 1,5) / (980 − 20) = 97,2 / 960 = 0,10125. Valor = 1,5 + (500 − 20) × 0,10125 = 50,1.

2. Un lazo de 4–20 mA

Un transmisor de presión de 0 a 10 bar entrega 12 mA a través de 250 Ω. ¿Qué presión es y qué código lee el ADC con referencia de 5 V?

Ver solución

Presión = (12 − 4) / 16 × 10 = 5 bar. Tensión = 12 mA × 250 Ω = 3,0 V → código 3,0 / 5 × 1024 = 614.

3. Una celda de carga

Una celda de 3 mV/V con 5 V de excitación entrega 15 mV a fondo de escala. ¿Cuál es la ganancia máxima del amplificador para usar la referencia de 1,1 V?

Ver solución

1,1 V / 15 mV = 73. En la práctica se elige una ganancia algo menor (por ejemplo 68) para dejar margen y no saturar el ADC.

4. La zona muerta

Un filtro exponencial entero con k = 3 se estabiliza ante un escalón creciente. ¿A cuántas cuentas del valor final puede quedar y cómo se evita?

Ver solución

Hasta 23 − 1 = 7 cuentas, porque la diferencia menor que 8 da 0 al desplazar. Se evita acumulando con bits fraccionarios (un acumulador de valor × 2k).

5. Un presupuesto

Un sensor de 0 a 50 unidades tiene ±1,0 de error, el ADC de 10 bits ±2 LSB y la referencia ±0,5 %. ¿Cuál es el error en el peor caso y cuál el aporte dominante?

Ver solución

Resolución = 50 / 1024 = 0,0488. Conversor = 2 × 0,0488 = 0,098. Referencia = 0,5 % × 50 = 0,25. Total: 1,0 + 0,098 + 0,25 = ±1,35 unidades. El aporte dominante es el sensor (1,0): pasar a 12 o 16 bits no mejoraría el total.

14 · Síntesis

Ideas para recordar

  • Una medición confiable es una cadena: sensor, acondicionamiento, ADC, calibración, filtro y validación; cada eslabón suma o resta exactitud.
  • El acondicionamiento (divisor, ganancia, filtro, protección) hace que la señal ocupe el rango del ADC; el lazo de 4–20 mA tiene el cero vivo y detecta cables cortados.
  • La calibración corrige errores sistemáticos: dos puntos dan offset y ganancia, y un punto intermedio revela la no linealidad. Se guarda en la EEPROM.
  • La aritmética de punto fijo (centésimas, factores por 1024) evita la coma flotante; hay que vigilar los desbordamientos y usar 32 bits en los productos.
  • Media móvil contra el ruido continuo, mediana contra picos y exponencial como filtro barato; cuidado con la zona muerta del exponencial entero.
  • Hay que validar la lectura (rango, saltos, valor congelado) antes de que el programa actúe sobre ella.
  • El presupuesto de errores muestra qué mejorar: más bits no sirven si domina el sensor o la referencia.

¿Listo para el tema 37?

Antes de avanzar, calibrá un sensor con dos puntos, elegí el filtro para un caso de ruido dado y estimá el error total de una cadena de medición. Si podés justificar las tres respuestas, tenés la base para trabajar con cualquier sensor.

En el próximo tema, un taller: un sensor I2C y un medidor de distancia. Leeremos un BME280 por I2C y mediremos distancias con un HC-SR04 usando la captura de un temporizador.