O(1) en ROMUna LUT es un arreglo precalculado estáticamente (generalmente con un script de Python en tu PC) y guardado en la memoria inmutable del microcontrolador. En lugar de usar la unidad lógico-aritmética (ALU) para calcular y = e^(x*k), tu procesador simplemente hace una búsqueda en un índice: y = arreglo[x]. Sustituyes carga computacional intensiva por carga de almacenamiento.
En el C Estándar, declarar un arreglo grande como float API54[100]; asimilará inmediatamente 400 bytes de tu valiosa memoria RAM. Como vimos en los capítulos de MISRA-C y LwIP, la RAM es nuestro recurso más escaso.
El secreto industrial es declarar el arreglo como static const float32_t. La palabra clave const le dice al compilador GCC (Linker) que este arreglo jamás cambiará. En lugar de ubicarlo en la sección .data o .bss (SRAM), lo inyecta permanentemente en la sección .rodata (Read-Only Data) de la memoria Flash del STM32. Consultarlo es instántaneo y el costo en RAM es de cero absolutos.
Para buscar en un arreglo (arreglo[i]), la variable i DEBE ser un entero. Pero la temperatura es decimal (ej. 25.4 °C). El truco metrológico consiste en multiplicar la lectura del sensor de temperatura (PT100) por 10 y usar enteros (`254`), aplicando un offset para temperaturas negativas.
Circuito Termométrico: Para lograr una resolución de 0.1°C de forma industrial, no puedes usar un sensor barato como el LM35 o un DHT11. El estándar es sumergir una sonda RTD PT100 (Clase A) directamente en el flujo de Gas LP, conectada a un conversor ADC especializado como el MAX31865 vía SPI, el cual entregará lecturas extremadamente precisas y blindadas contra ruido.
Ejercicio 1: Implementaremos la Tabla API 54 para una mezcla de Gas LP de densidad estándar. Aplicaremos Bounds Checking (Regla 18.1 de MISRA-C) para garantizar que si el sensor de temperatura falla y arroja 999°C, nuestra máquina no lea un segmento prohibido de la memoria y colapse.
/**
* @file api_table54.c
* @brief Algoritmo de Compensación Termodinámica (API Table 54) - MISRA-C:2012
*/
#include <stdint.h>
typedef float float32_t;
// =========================================================================
// DEFINICIONES DE LA TABLA (LUT)
// =========================================================================
// Rango de operación comercial: -10.0 °C a +50.0 °C
// Resolución de la tabla: 0.1 °C
// Total de entradas: 601 valores (Desde -100 hasta 500 en décimas)
#define TEMPERATURA_MIN_DECIMAS (-100) // -10.0 °C
#define TEMPERATURA_MAX_DECIMAS (500) // 50.0 °C
#define TOTAL_ENTRADAS_LUT (601U)
// El calificador 'const' forza este arreglo a vivir en la memoria FLASH (.rodata)
// Ahorrando RAM. El VCF a 20.0 °C es siempre 1.0000 (Temperatura Base México).
static const float32_t API54_LUT_DENSIDAD_0_540[TOTAL_ENTRADAS_LUT] = {
1.0825F, // Índice 0 (-10.0 °C)
1.0822F, // Índice 1 (-9.9 °C)
// ... (Cientos de valores calculados matemáticamente en PC u obtenidos de la Norma) ...
1.0000F, // Índice 300 (20.0 °C) - Punto de Equilibrio
0.9997F, // Índice 301 (20.1 °C)
// ...
0.9680F, // Índice 405 (30.5 °C) - El Gas está dilatado
// ...
0.9100F // Índice 600 (50.0 °C) - Gas extremadamente caliente y dilatado
};
// =========================================================================
// FUNCIÓN METROLÓGICA (CERTIFICADA MISRA-C)
// =========================================================================
/**
* @brief Calcula el volumen compensado a Temperatura Base (20°C)
* @param litros_brutos: Volumen crudo leído de la turbina
* @param temp_decimas: Temperatura del gas en décimas de grado (ej. 305 = 30.5°C)
* @retval Volumen facturable compensado
*/
float32_t API54_Compensar_Volumen(float32_t litros_brutos, int16_t temp_decimas) {
float32_t vcf = 1.0F; // Fallback: Si algo falla, el factor de corrección es 1 (sin corrección)
// 1. REGLA MISRA 18.1: Comprobación Estricta de Límites (Bounds Checking)
// Evitamos lecturas OOB (Out-of-Bounds) que provocarían un HardFault.
if ((temp_decimas >= TEMPERATURA_MIN_DECIMAS) && (temp_decimas <= TEMPERATURA_MAX_DECIMAS)) {
// 2. Mapeo de Rango Físico a Índice de Arreglo (0-index)
// Ejemplo: Si entra -100 (-10.0°C), le sumamos 100 y leemos el índice 0.
// Si entra 305 (30.5°C), le sumamos 100 y leemos el índice 405.
uint16_t indice_lut = (uint16_t)(temp_decimas - TEMPERATURA_MIN_DECIMAS);
// 3. Extracción de Tiempo Constante O(1) desde la Memoria ROM
vcf = API54_LUT_DENSIDAD_0_540[indice_lut];
} else {
// Alerta Crítica: El sensor PT100 está desconectado o el gas está congelado.
// Aquí dispararíamos un flag de error de hardware en el sistema:
// Disparar_Alarma(ERROR_PT100_FUERA_DE_RANGO);
}
// 4. Retornamos la multiplicación final
return (litros_brutos * vcf);
}
Objetivo del día: Cumplimiento Normativo (NOM) y Precisión Volumétrica por Software.
En México, la Dirección General de Normas (DGN) y la PROFECO (Nom-010-SCFI-1994 y posteriores) exigen que todos los instrumentos de medición de hidrocarburos operen bajo un esquema de corrección de temperatura estricto, tomando los 20°C como volumen facturable base. En países europeos es a 15°C. Si vendes gas a 35°C (muy común en el norte y costa del país), el líquido está dilatado. Sin la corrección termodinámica, el usuario estaría pagando un 4% de volumen "fantasma" que es puro espacio molecular dilatado. Y viceversa: en invierno, la estación regalaría gas a los clientes.
Al programar la **Compensación por Look-Up Table (API 54)** inyectada en la memoria Flash, mataste tres pájaros de un tiro: Primero, cumples con la ley para que tu Despachador sea legalmente vendible y certificable. Segundo, mantienes tu código **100% MISRA-C Compliant** al aislar un arreglo constante validado por Bounds-Checking. Tercero, evitas que tu procesador Cortex-M4 sufra una sobrecarga por cálculos exponenciales/logarítmicos en tiempo real, resolviendo la termodinámica de fluidos con una extracción de memoria de 1 ciclo de reloj (`O(1)`). Esto es lo que diferencia a una tesis de investigación de un producto maduro, industrial y altamente rentable.
static const, obligamos al compilador y al *Linker* a almacenar los datos permanentemente en la memoria **Flash ROM (Sección .rodata)**, salvando la preciada memoria RAM para el RTOS y evitando la fatiga del procesador.