El Control Activo de Rechazo de Perturbacionse (ADRC) es un paradigma de control robusto que se basa en la estimación y compensación en tiempo real de las pertrubaciones internas y externas de un sistema. Su estructura fundamental se compone de tres módulos interconectados, cada uno con una función específica para lograr un rendimiento de control superior:
- Diferenciador de Seguimiento (TD - Tracking Differentiator): Genera trayectorias de referencia suaves y sus derivadas para la señal de entrada deseada, evitando cambios bruscos.
- Observador de Estados Expandido (ESO - Extended State Observer): Estima los estados del sistema y la "perturbación total" (interna y externa) en tiempo real.
- Ley de Retroalimentación de Error de Estado No Lineal (NLSEF - Nonlinear State Error Feedback): Combina las estimaciones del ESO y las referencias del TD mediante una función no lineal para generar la señal de control.
A continuación, exploraremos la implementación de cada componente a través de ejemplos de código.
Diferenciador de Seguimiento (TD)
El Diferenciador de Seguimiento (TD) es crucial para suavizar las señales de comando, transformando una referencia instantánea en una trayectoria de transición gradual. Esto es especialmente útil para proteger los actuadores de cambios bruscos y generar señales de velocidad o aceleración suavizadas. Su implementación discreta puede visualizarse de la siguiente manera:
class TrackingDifferentiator:
def __init__(self, r_param, h_step):
self.r_param = r_param # Parámetro de velocidad de seguimiento
self.h_step = h_step # Paso de tiempo de discretización
self.estado1 = 0.0 # Estado actual de la señal suavizada
self.estado2 = 0.0 # Estado actual de la derivada de la señal suavizada
def actualizar(self, referencia_deseada):
# Cálculos intermedios para la lógica del TD
delta_t = self.r_param * self.h_step
aux0 = self.h_step * self.estado2
aux_y = self.estado1 + aux0
# Cálculo de la raíz cuadrada para la función de transición
# Aseguramos que el argumento de sqrt no sea negativo
argumento_sqrt = delta_t**2 + 8 * self.r_param * abs(aux_y - referencia_deseada)
if argumento_sqrt < 0:
argumento_sqrt = 0 # Prevenir errores por números negativos (teóricamente no debería ocurrir)
aux1 = (argumento_sqrt)**0.5
# Lógica de conmutación para la actualización del estado principal (v1)
if abs(aux_y - referencia_deseada) > delta_t:
self.estado1 += self.h_step * self.estado2 - self.r_param * self.h_step * self.signo(aux_y - referencia_deseada)
else:
self.estado1 += self.h_step * self.estado2 - (aux_y - referencia_deseada) * self.h_step * self.r_param / delta_t
# Función de saturación (fal o su equivalente) para la derivada (v2)
error_fal = (aux_y - referencia_deseada) / delta_t
if abs(error_fal) > 1:
sat_val = self.signo(error_fal)
else:
sat_val = error_fal
self.estado2 -= self.r_param * self.h_step * sat_val
return self.estado1, self.estado2
def signo(self, valor):
if valor > 0: return 1
if valor < 0: return -1
return 0
# Ejemplo de uso:
# td = TrackingDifferentiator(r_param=10, h_step=0.01)
# v1_out, v2_out = td.actualizar(referencia_deseada=100)
El parámetro r_param define la velocidad con la que el TD persigue la referencia. Un valor mayor resulta en un seguimiento más rápido, pero puede introducir mayor oscilación. h_step es el paso de tiempo de discretización, generalmente igual al período de muestreo del sistema. La función clave aquí es la lógica de conmutación en la actualización de estado1 y la función de saturación implícita en la actualización de estado2, que aseguran una transición suave incluso para referencias escalón.
Observador de Estados Expandido (ESO)
El Observador de Estados Expandido (ESO) es el componente central del ADRC, diseñado para estimar no solo los estados observables del sistema, sino también un "estado expandido" que representa la perturbación total (incluidas las no linealidades, los errores de modelado y las perturbaciones externas). Para un sistema de segundo orden, esto implica estimar tres estados:
class ExtendedStateObserver:
def __init__(self, b_val, h_step, beta1, beta2, beta3):
self.b_coef = b_val # Coeficiente de entrada conocido del sistema
self.h_step = h_step # Paso de tiempo de discretización
self.beta1 = beta1 # Ganancia del observador para el primer estado
self.beta2 = beta2 # Ganancia del observador para el segundo estado
self.beta3 = beta3 # Ganancia del observador para el estado expandido
self.estado_x1 = 0.0 # Estimación del primer estado
self.estado_x2 = 0.0 # Estimación del segundo estado (derivada)
self.estado_x3 = 0.0 # Estimación del estado expandido (perturbación total)
def funcion_fal(self, error, alpha_exp, delta_band):
# Función fal utilizada por el ESO para el manejo de errores
if abs(error) > delta_band:
return abs(error)**alpha_exp * self.signo(error)
else:
return error / (delta_band**(1 - alpha_exp))
def signo(self, valor):
if valor > 0: return 1
if valor < 0: return -1
return 0
def actualizar(self, medicion_salida, entrada_control):
error_observacion = medicion_salida - self.estado_x1
# Actualización de los estados del observador
self.estado_x1 += self.h_step * (self.estado_x2 + self.beta1 * error_observacion)
self.estado_x2 += self.h_step * (self.estado_x3 + self.beta2 * self.funcion_fal(error_observacion, 0.5, 0.01) + self.b_coef * entrada_control)
self.estado_x3 += self.h_step * (self.beta3 * self.funcion_fal(error_observacion, 0.25, 0.01))
return self.estado_x1, self.estado_x2, self.estado_x3
# Ejemplo de uso:
# # Las ganancias beta suelen sintonizarse como beta1=3w, beta2=3w^2, beta3=w^3, donde w es el ancho de banda del observador.
# # w podría ser de 3 a 5 veces el ancho de banda del sistema.
# eso = ExtendedStateObserver(b_val=1.0, h_step=0.01, beta1=100, beta2=3000, beta3=10000)
# x1_est, x2_est, x3_est = eso.actualizar(medicion_salida=50, entrada_control=10)
El estado estado_x3 representa la estimación en tiempo real de la perturbación total que afecta al sistema. La función funcion_fal, con sus parámetros alpha_exp y delta_band, ayuda a manejar los errores de observación de manera no lineal, otorgando mayor ganancia a errores pequeños para mejorar la precisión y menor ganancia a errores grandes para asegurar la estabilidad frente al ruido. Las ganancias beta1, beta2 y beta3 determinan el ancho de banda del observador y, por ende, su velocidad de convergencia y rechazo de ruido.
Ley de Retroalimentación de Error de Estado No Lineal (NLSEF)
La Ley de Retroalimentación de Error de Estado No Lineal (NLSEF) es la última etapa del ADRC, donde las estimaciones del ESO y las trayectorias de referencia del TD se combinan para calcular la señal de control. Esta etapa utiliza una función de retroalimentación no lineal para mejorar la robustez y el rendimiento del sistema.
class NonlinearStateErrorFeedback:
def __init__(self, b_val_nominal, kp_gain, kd_gain):
self.b_nominal = b_val_nominal # Coeficiente nominal de la entrada del sistema
self.kp_gain = kp_gain # Ganancia proporcional para el error del primer estado
self.kd_gain = kd_gain # Ganancia diferencial para el error del segundo estado
def funcion_fal(self, error_val, alpha_exp, delta_band):
# Función fal utilizada por el NLSEF para la retroalimentación de errores
if abs(error_val) > delta_band:
return abs(error_val)**alpha_exp * self.signo(error_val)
else:
return error_val / (delta_band**(1 - alpha_exp))
def signo(self, valor):
if valor > 0: return 1
if valor < 0: return -1
return 0
def calcular_control(self, ref_suavizada_td, deriv_ref_td, estado_obs_x1, estado_obs_x2, perturb_total_obs):
error_estado1 = ref_suavizada_td - estado_obs_x1
error_estado2 = deriv_ref_td - estado_obs_x2
# Combinación no lineal de los errores de estado
# Los exponentes 0.5 y 0.25 son valores empíricos comunes
componente_u0 = (self.kp_gain * self.funcion_fal(error_estado1, 0.5, 0.01) +
self.kd_gain * self.funcion_fal(error_estado2, 0.25, 0.01))
# Compensación de la perturbación total estimada y linealización dinámica
# b_nominal es el coeficiente de entrada del sistema
senal_control = (componente_u0 - perturb_total_obs) / self.b_nominal
return senal_control
# Ejemplo de uso:
# nlsef = NonlinearStateErrorFeedback(b_val_nominal=1.0, kp_gain=50, kd_gain=5)
# u_output = nlsef.calcular_control(
# ref_suavizada_td=td.estado1,
# deriv_ref_td=td.estado2,
# estado_obs_x1=eso.estado_x1,
# estado_obs_x2=eso.estado_x2,
# perturb_total_obs=eso.estado_x3
# )
La función funcion_fal en el NLSEF tiene un comportamiento específico: para errores grandes (abs(e) > delta), la ganancia es menor debido al exponente alpha_exp (generalmente menor que 1), lo que previene el sobreimpulso. Para errores pequeños, la ganancia es mayor, mejorando la precisión en el estado estacionario. El término - perturb_total_obs es la esencia de la "autodisturbación" del ADRC, compensando directamente las perturbaciones estimadas. Dividir por b_nominal realiza una linealización dinámica, haciendo que el sistema interno se comporte como un integrador puro para la señal componente_u0.
Para la simulación y sintonización de ADRC, se recomienda un proceso iterativo: primero, asegúrese de que el ESO converge adecuadamente ajustando las ganancias beta. Luego, sintonice el TD ajustando su parámetro r_param para obtener la suavidad deseada. Finalmente, ajuste las ganancias kp_gain y kd_gain y los parámetros alpha_exp y delta_band en el NLSEF para optimizar la respuesta dinámica y la robustez del control. Los exponentes 0.5 y 0.25 en las funciones fal son valores empíricos que a menudo proporcionan un buen equilibrio entre velocidad de respuesta y estabilidad.