DÍA 157 DE 365

Fase 3: Comunicaciones y Redes Industriales

📖 Teoría a Estudiar

El Enigma Analógico y los Puntos Fijos

Los sensores analógicos raramente son perfectos. Un sensor de presión de $4-20\text{mA}$ podría tener una leve desviación (offset) al principio de su rango y otra diferente al final de su rango. Para corregirlo, el fabricante te entrega un "Certificado de Calibración", que es básicamente una lista de coordenadas (X, Y). Por ejemplo: A 1.00 Voltio, la presión es 0 PSI. A 2.50 Voltios, la presión es 52 PSI. A 4.00 Voltios, es 105 PSI.

¿Qué presión hay si el ADC lee 3.00 Voltios? Como es una curva deforme, no podemos usar la clásica ecuación de la recta simple ($y = mx+b$) para toda la gráfica. Debemos encontrar en qué "tramo" estamos, y trazar una recta imaginaria solo entre los dos puntos que nos rodean.

Interpolación Lineal a Tramos (Piecewise Linear Interpolation)

El algoritmo es elegantemente sencillo:

  1. Tener una tabla de puntos de calibración ordenados ascendentemente según el eje X.
  2. Recorrer la tabla buscando el intervalo correcto: encontrar un punto $X_1$ que sea menor o igual a nuestra lectura, y el siguiente punto $X_2$ que sea mayor.
  3. Aplicar la fórmula de la pendiente para calcular el valor exacto $Y_{out}$:
    $$ Y_{out} = Y_1 + (X_{in} - X_1) \cdot \frac{Y_2 - Y_1}{X_2 - X_1} $$
CORRECCIÓN MULTIPUNTO E INTERPOLACIÓN LINEAL A TRAMOS Y (Salida Corregida) X (Entrada ADC / Temp) P0 P1 (X1, Y1) P2 (X2, Y2) P3 X_in Y_out X1 Y1 X2 Y2 Matemática del Procesador Pendiente = (Y2 - Y1) / (X2 - X1) DeltaX = (Xin - X1) Yout = Y1 + (DeltaX * Pendiente) 1. Encontrar el Tramo (Bucle For) Si (Xin >= X1) Y (Xin <= X2)

⚙️ Ejercicios Prácticos

Ejercicio 1: Vamos a definir la estructura de la tabla de calibración en C, lista para alojarse en la memoria Flash (Sector 5). Crearemos una función de protección (Clamping) que prevenga la división por cero si el usuario ingresa dos puntos X idénticos por error, y que fije los topes superior e inferior si el sensor arroja un valor fuera del rango calibrado.


/**
 * @file interpolador_multipunto.c
 * @brief Algoritmo Bare-Metal de Interpolación Lineal para Sensores y Tablas API
 */

#include "stm32f401xe.h"
#include <stdint.h>

// =========================================================================
// DEFINICIÓN DE ESTRUCTURAS
// =========================================================================

// Punto cartesiano simple
typedef struct {
    float x; // Valor crudo del hardware (Ej. Voltios, o ADC de 0 a 4095)
    float y; // Valor de ingeniería real (Ej. Presión en PSI, o Temperatura en °C)
} PuntoCalibracion_t;

// La estructura global de la tabla. Al usar empaquetado, 
// podemos recibir todo esto en un solo chorro de bytes por Modbus RS485.
#pragma pack(push, 1)
typedef struct {
    uint16_t num_puntos;
    PuntoCalibracion_t puntos[20]; // Capacidad para curvas de 20 puntos
} TablaCalibracion_t;
#pragma pack(pop)

// Simulación de la tabla alojada en la memoria Flash (Día 146)
// Imagina que esto está en el Sector 5 (0x08020000)
TablaCalibracion_t tabla_presion = {
    .num_puntos = 4,
    .puntos = {
        {0.5f, 0.0f},   // 0.5V  -> 0 PSI
        {1.5f, 35.0f},  // 1.5V  -> 35 PSI
        {3.0f, 90.0f},  // 3.0V  -> 90 PSI
        {4.5f, 150.0f}  // 4.5V  -> 150 PSI
    }
};

/**
 * @brief Encuentra la salida (Y) correspondiente a una entrada (X) interpolando
 * 
 * @param x_in Valor actual del sensor que queremos traducir
 * @param tabla Puntero a la estructura de la tabla de calibración
 * @return float El valor real corregido (Y_out)
 */
float Interpolacion_Lineal(float x_in, TablaCalibracion_t* tabla) {
    
    // 1. FILTROS DE SEGURIDAD (Clamping)
    // Si la tabla está vacía o mal formada, retornamos el mismo número 
    // para evitar que la máquina explote por división entre cero.
    if (tabla->num_puntos < 2) return x_in;
    
    // Si la lectura está por debajo de nuestro punto de calibración más bajo,
    // fijamos el resultado al mínimo (Extrapolación plana de seguridad industrial).
    if (x_in <= tabla->puntos[0].x) {
        return tabla->puntos[0].y;
    }
    
    // Si la lectura supera nuestro máximo calibrado, lo topamos.
    uint16_t ultimo_idx = tabla->num_puntos - 1;
    if (x_in >= tabla->puntos[ultimo_idx].x) {
        return tabla->puntos[ultimo_idx].y;
    }
    
    // 2. BÚSQUEDA DEL INTERVALO
    for (uint16_t i = 0; i < ultimo_idx; i++) {
        
        float x1 = tabla->puntos[i].x;
        float y1 = tabla->puntos[i].y;
        float x2 = tabla->puntos[i+1].x;
        float y2 = tabla->puntos[i+1].y;
        
        // Verificamos si nuestra lectura cae dentro de este "tramo"
        if (x_in >= x1 && x_in <= x2) {
            
            // Protección contra tabla corrupta (X2 = X1 provocaría división por cero)
            if (x2 == x1) return y1; 
            
            // 3. APLICAR ECUACIÓN DE LA RECTA
            // Nota: Gracias al FPU de Hardware (Cortex-M4F), esto cuesta 3 ciclos de reloj.
            float pendiente = (y2 - y1) / (x2 - x1);
            float y_out = y1 + ((x_in - x1) * pendiente);
            
            return y_out;
        }
    }
    
    // Fallback: Si por error matemático de punto flotante se escapa del bucle
    return 0.0f; 
}


int main(void) {
    
    // Inicializar FPU (Día 151)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));
    
    while(1) {
        
        // En nuestro Súper Bucle, extraemos voltaje del ADC (0 - 5.0V)
        // float voltaje_crudo = Leer_ADC_Sensor();
        float voltaje_crudo = 2.0f; // Simulación: Sensor indica 2.0V
        
        // Traducimos el voltaje a Presión Física usando nuestra curva.
        // A 2.0V, el código verá que cae en el tramo de 1.5V y 3.0V.
        // Interpolaridad calculará exactamente: 53.33 PSI
        float presion_real = Interpolacion_Lineal(voltaje_crudo, &tabla_presion);
        
        // Podemos usar este mismo motor para la Temperatura vs Densidad LPG (Tablas API)
        // factor_densidad = Interpolacion_Lineal(temp_actual, &tabla_api_2540);
        // volumen_compensado = litros_crudos * factor_densidad;
        
        // (Continúa lógica Modbus o Pantalla LCD...)
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Cumplimiento Metrológico Estándar API 2540.

El fluido Gas LP se expande brutalmente con el calor. Si despachas 100 Litros de gas al mediodía (30°C), en realidad estás entregando mucha menos masa molecular que si los despachas en la madrugada (10°C). Las autoridades (PROFECO) exigen que todas las ventas se "compensen" matemáticamente al volumen que tendrían si el gas estuviera exactamente a $20.0 °C$.

El estándar API entrega una tabla de referencia con factores de densidad. Pero tu PT100 (sensor de temperatura) te arroja lecturas exactas con decimales, como `26.8°C`. Utilizando tu función de **Interpolación Multipunto**, tu STM32 lee la temperatura en tiempo real y calcula de la Tabla API el coeficiente exacto de compensación, multiplicándolo por la lectura bruta del caudalímetro. Has creado un sistema dinámico. Si cambias la marca del sensor o calibras el equipo, simplemente envías una nueva `TablaCalibracion_t` desde el Servidor por el cable RS485; el sistema la escribe en Flash y reajusta automáticamente la fidelidad de sus lecturas sin cambiar una sola línea del código fuente en C.

📝 Resumen del Día