Skip to content

05_22_06_stability_validator - El Guardián de la Estabilidad Numérica

PROPÓSITO

El sistema de seguridad del Coefficient Calculator. Verifica que todos los coeficientes calculados resulten en sistemas estables, previene denormals, valida precisión numérica, y detecta potenciales overflow/underflow. Es el auditor que previene explosiones numéricas antes de que lleguen al procesamiento de audio.

Responsabilidad: Garantizar 100% de coeficientes estables y numéricamente seguros antes de su uso.


ESTRUCTURA

05_22_06_stability_validator/
├── include/
│   ├── stability_validator.hpp      # Validador principal
│   └── validation_result.hpp        # Estructura de resultados
├── src/
│   ├── pole_zero_analysis.cpp       # Análisis de polos y zeros
│   ├── denormal_prevention.cpp      # Prevención de denormals
│   └── precision_validation.cpp     # Validación de precisión
├── tests/
│   ├── test_unstable_filters.cpp    # Tests con filtros inestables
│   └── test_denormal_detection.cpp  # Tests de denormals
├── examples/
│   └── validate_custom_filter.cpp   # Ejemplo de validación
└── README.md

API PRINCIPAL

StabilityValidator

class StabilityValidator {
public:
    struct ValidationResult {
        bool is_stable;
        bool has_denormal_risk;
        bool sufficient_precision;
        std::string error_message;
    };

    // Validación completa
    ValidationResult validate_filter(const BiquadCoeffs& coeffs);

    // Verificaciones individuales
    bool poles_inside_unit_circle(const BiquadCoeffs& coeffs);
    bool finite_frequency_response(const BiquadCoeffs& coeffs);
    bool denormal_risk(const BiquadCoeffs& coeffs);
    bool sufficient_precision(const BiquadCoeffs& coeffs);

    // Correcciones automáticas
    void apply_denormal_prevention(BiquadCoeffs& coeffs);
    void upgrade_precision(BiquadCoeffs& coeffs);
};

PROCESO DE VALIDACIÓN

Coeficientes Calculados
┌────────────────────────┐
│  Check 1: Poles        │ → ¿Están dentro del círculo unitario?
│  |poles| < 1           │    NO → FILTRO INESTABLE ❌
└────────────────────────┘
         ↓ SÍ
┌────────────────────────┐
│  Check 2: Frequency    │ → ¿Gain finito en todas las frecuencias?
│  Response Finite       │    NO → RESPUESTA INFINITA ❌
└────────────────────────┘
         ↓ SÍ
┌────────────────────────┐
│  Check 3: Denormals    │ → ¿Coeficientes muy pequeños?
│  Risk Detection        │    SÍ → Aplicar prevención ⚠️
└────────────────────────┘
┌────────────────────────┐
│  Check 4: Precision    │ → ¿Precisión suficiente?
│  Validation            │    NO → Upgrade a double/long double ⚠️
└────────────────────────┘
   COEFICIENTES VALIDADOS ✅

ANÁLISIS DE POLOS Y ZEROS

Teoría

Para un filtro biquad:

H(z) = (b0 + b1*z^-1 + b2*z^-2) / (1 + a1*z^-1 + a2*z^-2)

El denominador define los polos del sistema. Para estabilidad, los polos deben estar dentro del círculo unitario en el plano Z:

|pole| < 1

Los polos se calculan resolviendo:

z^2 + a1*z + a2 = 0

poles = (-a1 ± sqrt(a1^2 - 4*a2)) / 2


DENORMALS: EL ENEMIGO INVISIBLE

¿Qué son los denormals?

Números de punto flotante extremadamente pequeños (< 1e-38 para float) que causan degradación masiva de performance (hasta 100x más lento) en algunas CPUs.

Detección

bool denormal_risk(const BiquadCoeffs& c) {
    const double DENORMAL_THRESHOLD = 1e-30;
    return (abs(c.b0) < DENORMAL_THRESHOLD ||
            abs(c.b1) < DENORMAL_THRESHOLD ||
            abs(c.b2) < DENORMAL_THRESHOLD ||
            abs(c.a1) < DENORMAL_THRESHOLD ||
            abs(c.a2) < DENORMAL_THRESHOLD);
}

Prevención

void apply_denormal_prevention(BiquadCoeffs& c) {
    const double DENORMAL_OFFSET = 1e-30;

    // Añadir offset microscópico a b0 (no audible)
    c.b0 += DENORMAL_OFFSET;

    // Compensar con DC blocker si necesario
    // (mantiene respuesta en frecuencia correcta)
}

EJEMPLO DE USO

#include "stability_validator.hpp"
#include "filter_coefficient_calculator.hpp"

// Calcular coeficientes
FilterCoefficientCalculator<double> calc;
auto coeffs = calc.butterworth_lpf(20000.0, 100.0, 44100.0); // Q muy alto

// Validar
StabilityValidator validator;
auto result = validator.validate_filter(coeffs);

if (!result.is_stable) {
    std::cerr << "❌ Filtro inestable: " << result.error_message << "\n";
    // NO usar estos coeficientes
} else if (result.has_denormal_risk) {
    std::cout << "⚠️  Denormal risk detectado, aplicando prevención...\n";
    validator.apply_denormal_prevention(coeffs);
}

// Ahora es seguro usar los coeficientes

CASOS PATOLÓGICOS A DETECTAR

Filtro Inestable

BiquadCoeffs unstable;
unstable.b0 = 1.0;
unstable.b1 = 0.0;
unstable.b2 = 0.0;
unstable.a1 = -1.5;  // Polo fuera del círculo unitario
unstable.a2 = 0.8;

// poles = 0.75 ± 0.66i → |pole| = 1.0 → INESTABLE

Q Extremadamente Alto

// Q = 1000 @ 10kHz @ 44.1kHz
// Produce polos muy cerca del círculo unitario
// Sensible a errores de precisión numérica

Frecuencia cerca de Nyquist

// freq = 21000 Hz @ sr = 44100 Hz
// Warping extremo, coeficientes inestables

TAREAS DE DESARROLLO

  • Implementar StabilityValidator class
  • Implementar pole-zero analysis con solver de polinomios
  • Implementar denormal detection y prevention
  • Implementar frequency response validation
  • Implementar precision validation
  • Implementar upgrade automático de precisión
  • Tests con filtros inestables conocidos
  • Tests con casos patológicos (Q alto, freq cerca Nyquist)
  • Benchmarks de overhead de validación (<5% del cálculo)
  • Documentación de teoría de estabilidad

MÉTRICAS DE CALIDAD

✅ 100% de filtros inestables detectados ✅ 0 denormals en producción (todos prevenidos) ✅ Overhead de validación < 5% del tiempo de cálculo ✅ Test coverage > 95% (crítico para seguridad)


REFERENCIAS

  • Teoría de Estabilidad: "Digital Signal Processing" - Oppenheim & Schafer
  • Denormals: "Avoiding Denormals" - Intel Optimization Manual
  • Pole-Zero Analysis: "Understanding Digital Signal Processing" - Lyons

Sin este módulo, coeficientes incorrectos llegarían al procesamiento de audio causando crashes, distorsión, o CPU spikes aleatorios.