01 · Punto de partida
Por qué hace falta más que P
Seguimos con el horno de los temas anteriores: 100 W, 2000 J/K, 0,5 K/W (constante de tiempo de 1000 s) y un sensor que tarda 20 s en enterarse. Con el proporcional puro (banda de 5 °C) la temperatura se estabiliza en 37,73 °C, a 2,27 °C de la consigna de 40 °C, y si el ambiente baja de 15 a 5 °C se queda 3,18 °C por debajo. La razón es estructural: para mantener 40 °C hace falta cierta potencia, y un controlador que solo mira el error presente solo puede dar esa potencia si el error no es cero.
El PID agrega dos cosas a la ley proporcional:
- Memoria (integral): suma el error a lo largo del tiempo. Mientras quede un error, la suma sigue creciendo y empuja la salida hasta que el error se anula. Con ella el control encuentra solo la potencia necesaria, sea cual sea el ambiente.
- Anticipación (derivada): mide con qué rapidez cambia la variable y frena la salida antes de pasarse, igual que se levanta el pie del acelerador al ver que se llega a la curva.
Una frase para recordar la idea: el término P actúa sobre el presente del error, el I sobre su pasado acumulado y el D sobre su futuro previsible.
02 · La ley
Los tres términos
En la forma «estándar» (con la ganancia delante de los tres términos), la salida es:
La forma «paralela» equivalente usa tres ganancias independientes: Ki = Kp / Ti y Kd = Kp · Td. Con la forma estándar, Ti y Td son tiempos en segundos y tienen un significado físico: Ti es lo que tarda la integral en igualar a la acción proporcional si el error se mantiene constante, y Td es el tiempo con el que la derivada «adelanta» a la proporcional ante una rampa del error. En el horno, Kp se mide en 1/°C (la salida va de 0 a 1), Ti y Td en segundos.
| Al aumentar… | Velocidad de respuesta | Sobreimpulso | Error en régimen | Estabilidad | Ruido en la salida |
|---|---|---|---|---|---|
| Kp | Más rápida | Aumenta | Disminuye (no se anula) | Empeora | Aumenta |
| La integral (Ti menor) | Algo más rápida | Aumenta | Se anula | Empeora | Casi igual |
| La derivada (Td mayor) | Casi igual | Disminuye | Sin efecto | Mejora (hasta un punto) | Aumenta mucho |
La integral es la que elimina el error en régimen: si se queda un error constante e, la integral crece sin límite a razón Kp e / Ti y empuja la salida hasta que el error desaparece; por eso, en régimen, el término I contiene la potencia que el proceso necesita. En el horno con el ambiente a 5 °C, cualquier PI bien ajustado termina en 40,00 °C con el 70 % de potencia, que es justo lo que hace falta para vencer una pérdida de 35 K / 0,5 K/W = 70 W. El proporcional puro, con la misma perturbación, queda en 36,82 °C con el 64 %.
03 · Discretizar
El PID en un microcontrolador
En un programa, el tiempo avanza a pasos de Ts (el período del lazo, tema 41) y las operaciones continuas se aproximan:
- Integral: una suma,
I ← I + Ki · e · Ts. - Derivada: una diferencia,
(yk − yk−1) / Ts. - Período de muestreo: constante y exacto (
proximo += periodo, tema 41), y bastante menor que los tiempos del proceso: una regla es Ts ≤ Ti / 10 y ≤ Td / 5, y del orden de un décimo del tiempo de respuesta deseado. Un muestreo irregular altera la integral y la derivada.
Cuatro detalles que separan un PID de libro de uno que funciona:
- Derivada sobre la medida, no sobre el error. Si la consigna da un salto, el error salta, y su derivada es un pico enorme (un «golpe» o derivative kick). Con Kp = 1, Td = 10 s, Ts = 1 s y un salto de 3 °C, el pico sería de
1 × 10 × 3 / 1 = 30en la salida, cuando el máximo útil es 1. Derivando la medida (−de/dtcon consigna constante es igual ady/dtcon signo cambiado), el salto de consigna no produce ningún golpe. - Derivada filtrada. Derivar amplifica el ruido de alta frecuencia sin límite. Se agrega un filtro de primer orden con constante Td / N (con N entre 5 y 20), de modo que la ganancia a alta frecuencia queda limitada a
Kp (1 + N). - Salida saturada y anti-windup (sección siguiente).
- Transferencia sin saltos (bumpless): al pasar de manual a automático, o al volver de una falla, la integral se inicializa con el valor que hace que la salida sea la actual (
I = u − Kp e); si no, la salida da un salto brusco.
Otras decisiones de implementación: las ganancias en las unidades de la variable de proceso (para no confundir °C con décimas de grado), la dirección de la acción (calefacción o refrigeración, como en el tema 42) y la reacción ante una medida inválida (tema 40): salida segura y estado congelado, para no integrar basura.
04 · Los límites del actuador
Saturación y anti-windup
El actuador tiene límites: el calefactor no puede dar más del 100 % ni menos del 0 %. Cuando el controlador pide más (por ejemplo, al arrancar el horno frío, con 25 °C de error), la salida satura; pero la integral no lo sabe y sigue acumulando error. Es el windup: la integral se carga mucho más allá de lo que el actuador puede aplicar, y cuando la temperatura por fin se acerca a la consigna, la integral acumulada sigue empujando la salida a pleno y la temperatura se pasa. Solo se «descarga» cuando el error ha sido negativo durante un buen rato.
| Protección | Sobreimpulso | Entra en ±0,5 °C a los | Integral máxima |
|---|---|---|---|
| Solo P (Kp = 0,2) | 0,00 °C | no llega (37,73 °C) | — |
| Ninguna | 13,15 °C | 2106 s | 20,45 (2045 % de la salida) |
| Pinza (integración condicional) | 0,00 °C | 741 s | 0,50 |
| Retrocálculo con Tt = 50 s | 0,00 °C | 880 s | 0,50 |
| Retrocálculo con Tt = Ti = 200 s | 0,90 °C | 845 s | 0,96 |
Sin protección, la integral llega a 20,45: el controlador «cree» que hay que dar un 2045 % de potencia, y la temperatura se pasa 13,15 °C y tarda casi 35 minutos en volver a la banda. Con la pinza, el mismo PI no se pasa y entra en la banda a los 741 s; el límite físico (calentar a 100 % hasta 39,5 °C) es de unos 673 s, así que se llega a menos de un 10 % de ese mínimo. Las técnicas más usadas:
- Pinza (clamping) o integración condicional: no se integra cuando la salida está saturada y el error empuja hacia la saturación. Es la más simple y robusta.
- Retrocálculo (back-calculation): se realimenta a la integral la diferencia entre la salida limitada y la que pedía el controlador, con una constante Tt:
I ← I + (Ts/Tt)·(u − usin limitar). Con Tt grande, desacumula lento (0,90 °C de sobreimpulso con 200 s); con Tt chico, rápido. - Limitar la propia integral a un rango razonable.
- Congelar o reiniciar la integral cuando el sensor falla, el modo es manual o el cambio de consigna es grande (en un salto de consigna grande, algunos controladores desactivan la integral hasta que el error es pequeño).
El windup no solo aparece al arrancar: ocurre siempre que la salida satura con un error sostenido, como una perturbación grande, un actuador desconectado o un cambio de consigna brusco. La integral sin protección es el error de implementación más común de un PID casero.
05 · Sintonizar
Ajuste de las ganancias
Tres ganancias dan un espacio amplio de malas elecciones. Una sintonía incorrecta oscila: con la integral muy rápida (Kp = 0,5; Ti = 20 s) el horno oscila 1,34 °C pico a pico; con ganancias altas (Kp = 2 o 3, Ti = 100 s), 0,79 y 0,86 °C. Con una ganancia de 1 y Ti = 100 s, la oscilación es nula. Hay tres familias de métodos para encontrar buenos valores sin tanteo ciego:
1. Ziegler-Nichols de lazo cerrado
Con el control proporcional solo, se sube Kp hasta que el lazo oscila de forma sostenida: esa es la ganancia crítica Ku y el período de la oscilación, Tu. Se toman las ganancias de la tabla:
| Tipo | Kp | Ti | Td | En el horno |
|---|---|---|---|---|
| P | 0,5 Ku | — | — | Kp = 0,79 |
| PI | 0,45 Ku | Tu / 1,2 | — | Kp = 0,71; Ti = 66 s |
| PID | 0,6 Ku | Tu / 2 | Tu / 8 | Kp = 0,95; Ti ≈ 40 s; Td = 9,9 s |
Ziegler-Nichols es una buena primera aproximación pero tiende a ser agresiva (amortigua cada oscilación a un cuarto de la anterior). Ante una perturbación de 10 °C en el ambiente, el PI de ZN deja un desvío máximo de 0,32 °C y el PID de ZN, de 0,24 °C; el PI (1; 100 s), 0,29 °C, y el P solo, 3,18 °C sin recuperarse. Su desventaja práctica: llevar un proceso real a la oscilación sostenida puede ser peligroso (un horno, una caldera) o lento.
2. El método del relé
Se obtiene la oscilación crítica de forma segura con el control todo o nada del tema anterior: un relé con histéresis casi nula hace oscilar el proceso con amplitud a y período Tu. La ganancia crítica se estima como Ku ≈ 4d / (π a), donde d es la amplitud de la salida del relé (0,5 si va de 0 a 1 alrededor del 50 %). En el horno: amplitud a = 0,50 °C y período de 80 s dan Ku ≈ 1,27 (el valor real es 1,58: un 20 % de error, aceptable) y Tu = 80 s (79 s reales). Es la base de los autotune de los controladores comerciales.
3. Respuesta al escalón y regla lambda
Se aplica un escalón de potencia con el lazo abierto y se mide la ganancia K del proceso, su constante de tiempo τ y su retardo θ (en el horno: 50 °C, 1000 s y 20 s). La regla lambda (SIMC) elige un tiempo de respuesta deseado λ y da:
| λ | Kp | Ti | Sobreimpulso | Entra en la banda a los |
|---|---|---|---|---|
| 50 s | 0,286 | 280 s | 0,00 °C | 841 s |
| 100 s | 0,167 | 480 s | 0,00 °C | 1144 s |
| 200 s | 0,091 | 880 s | 0,00 °C | 2091 s |
Tiene la ventaja de que un solo número, λ, controla el compromiso entre rapidez y robustez. Y en la práctica, el procedimiento de tanteo también sirve: con Ki = Kd = 0, subir Kp hasta que apenas oscile y quedarse con la mitad; agregar la integral con Ti del orden de Tu hasta que el error en régimen desaparezca sin oscilar; y agregar derivada solo si el proceso es rápido y el sensor limpio (sección siguiente). Siempre, de a un parámetro por vez y con el actuador protegido.
06 · El término delicado
La derivada y el ruido
La derivada es la más tentadora y la más peligrosa. Mejora la estabilidad de procesos con inercia, pero amplifica el ruido en proporción a su frecuencia: un sensor ruidoso convierte cada muestra en un salto de la salida. Con un ruido de 0,1 °C de desviación típica en el sensor, la salida (de 0 a 1) del horno varía así:
| Controlador | Ganancia a alta frecuencia | Desviación típica de u |
|---|---|---|
| PI | 1 | 0,106 |
| PID, Td = 10 s, N = 10 | 11 | 0,397 |
| PID, Td = 30 s, N = 10 | 11 | 0,426 |
| PID, Td = 30 s, N = 100 | 101 | 0,479 |
La derivada multiplica la variación de la salida por cuatro, y la salida varía en un 40 % de su rango solo por ruido: un relé o una válvula se gastaría rápido, y una resistencia calefactora recibiría una potencia que fluctúa sin sentido. Y la derivada del proceso del horno aporta poco: la dinámica es lenta (1000 s) y el retardo (20 s) es pequeño frente a ella. Las reglas prácticas:
- Temperatura, nivel, humedad, caudal: procesos lentos con sensores ruidosos → PI, sin derivada.
- Posición y velocidad de motores con encoder (tema 31): señales limpias y dinámica rápida → la derivada ayuda a frenar a tiempo.
- Si se usa derivada: siempre filtrada (N de 5 a 10), sobre la medida, con un sensor filtrado (tema 5), y comprobando la variación de la salida con el sistema quieto.
07 · De la práctica
Mejoras prácticas
- Prealimentación (feedforward): si se conoce la perturbación o la potencia de régimen, se suma directamente a la salida. En el horno,
uff = (consigna − ambiente) / (Pmáx R)= 50 % con 15 °C de ambiente; el PI solo corrige lo que falte. Es lo que hace el «sesgo» del tema anterior, pero calculado en vez de fijo. - Ponderación de la consigna: aplicar la acción proporcional a una fracción de la consigna reduce el sobreimpulso ante cambios de consigna sin afectar el rechazo de perturbaciones.
- Rampa de consigna: en vez de un salto, hacer que la consigna avance de a poco: evita el golpe y respeta los límites del actuador.
- Limitar la velocidad de variación de la salida (slew rate), para no maltratar al actuador.
- Banda muerta (tema 42) o histéresis de salida si el actuador es ruidoso o tiene holgura.
- Ganancias programadas (gain scheduling): ganancias distintas según el punto de trabajo, si el proceso es muy no lineal (un horno es más lento a baja temperatura).
- Control en cascada: un lazo exterior lento (temperatura) fija la consigna de uno interior rápido (corriente o potencia).
08 · Elegir
Qué PID para cada problema
| Proceso | Controlador | Período Ts | Observaciones |
|---|---|---|---|
| Temperatura de un horno o una incubadora | PI | 0,5 a 2 s | Lento, ruidoso; ventana larga si la salida es un relé |
| Nivel de un tanque | PI (o P) | 0,5 a 5 s | El proceso ya integra: cuidado con la doble integral |
| Velocidad de un motor DC con encoder | PI | 5 a 20 ms | La medida es el conteo de pulsos filtrado (tema 26) |
| Posición de un servo o un eje | PD o PID | 1 a 10 ms | La derivada da amortiguamiento; sensor limpio |
| Caudal o presión | PI | 10 a 100 ms | Rápido; ruido considerable |
| Rumbo de un robot (giroscopio) | PD | 5 a 20 ms | Se deriva directamente la velocidad angular del giroscopio (tema 20) |
| Luz con realimentación óptica (tema 16) | PI | 10 a 100 ms | Con corrección gamma en la salida |
El criterio de muestreo es siempre el mismo: tomar un período mucho menor que el tiempo en que el proceso responde, de modo que se vean varias muestras en cada cambio. Muestrear mucho más rápido no mejora el control y solo agrega ruido; mucho más lento, lo vuelve inestable.
09 · Programación
Código del PID
Una clase PID con la interfaz Controlador de los temas 40 y 42: derivada filtrada sobre la medida, integral con pinza, salida limitada, estado seguro ante un dato inválido y transferencia sin saltos. El lazo, cada segundo y sin bloqueos, igual que antes; cambiar del proporcional al PID es cambiar una línea.
// ---------- PID de posición con derivada filtrada sobre la medida y anti-windup por pinza ----------
// Usa la interfaz Controlador de los temas 40 y 42: la aplicación pide una potencia entre 0 y 1.
class PID : public Controlador {
public:
// ts: período del lazo en segundos (debe coincidir con el real); ti = 0 desactiva la integral; td = 0, la derivada
PID(float kp, float ti, float td, float ts, float n = 10.0f)
: kp_(kp), ti_(ti), td_(td), ts_(ts), n_(n) {}
void sintonizar(float kp, float ti, float td) { kp_ = kp; ti_ = ti; td_ = td; }
float calcular(float consigna, float medida) override {
if (isnan(medida)) return 0.0f; // dato inválido: salida 0 y se congela el estado (sin integrar basura)
float e = consigna - medida;
if (!inicializado_) { previa_ = medida; inicializado_ = true; }
float p = kp_ * e; // presente
if (td_ > 0.0f) { // derivada de la MEDIDA (no del error) y filtrada:
float a = td_ / (td_ + n_ * ts_); // el cambio de consigna no produce un golpe y el ruido
d_ = a * d_ - kp_ * td_ * n_ / (td_ + n_ * ts_) * (medida - previa_); // queda limitado a K_p (1 + N)
}
previa_ = medida;
float ki = (ti_ > 0.0f) ? kp_ / ti_ : 0.0f; // pasado: K_i = K_p / T_i
float iNueva = i_ + ki * e * ts_;
float sinLimitar = p + iNueva + d_;
float u = constrain(sinLimitar, 0.0f, 1.0f);
if (sinLimitar != u && e * (sinLimitar - u) > 0.0f) iNueva = i_; // pinza: saturado y el error empuja más: no integrar
i_ = iNueva;
return constrain(p + i_ + d_, 0.0f, 1.0f);
}
// Transferencia sin saltos (de manual a automático, o tras una falla): la integral se ajusta para que la salida no cambie
void reiniciar(float salidaActual, float consigna, float medida) {
i_ = constrain(salidaActual - kp_ * (consigna - medida), 0.0f, 1.0f);
d_ = 0.0f;
previa_ = medida;
inicializado_ = true;
}
private:
float kp_, ti_, td_, ts_, n_;
float i_ = 0.0f, d_ = 0.0f, previa_ = 0.0f;
bool inicializado_ = false;
};
// ---------- Lazo: cada segundo, sin bloqueos (temas 40 a 42) ----------
Ds18b20 sensor(dallas, 0);
SalidaRele calefactor(Config::PIN_CALEFACTOR, 60000UL); // ventana de 60 s para la potencia proporcional
PID controlador(0.5f /* K_p en 1/°C */, 200.0f /* T_i en s */, 0.0f /* sin derivada */, 1.0f /* T_s en s */);
bool habiaFalla = true;
void loop() {
static uint32_t proximo = 0;
if ((int32_t)(millis() - proximo) >= 0) {
proximo += 1000; // T_s exacto, sin deriva
Lectura l = sensor.leer();
if (l.estado != Estado::OK) { // ante la duda, apagado, y se recuerda para retomar sin salto
calefactor.apagar();
habiaFalla = true;
} else {
if (habiaFalla) { controlador.reiniciar(0.0f, Config::CONSIGNA_C, l.valor); habiaFalla = false; }
calefactor.establecer(controlador.calcular(Config::CONSIGNA_C, l.valor));
}
}
calefactor.actualizar();
}
Las ganancias se pueden guardar en EEPROM (tema 40) y ajustar sin recompilar. Para depurar, conviene registrar el error y las tres contribuciones (P, I, D) por el puerto serie a una frecuencia baja: es la manera más rápida de ver cuál de los términos hace algo raro.
10 · Verificación
Errores típicos y verificación
| Síntoma | Causa | Defensa |
|---|---|---|
| Se pasa mucho de la consigna al arrancar y tarda en volver | Windup de la integral | Pinza o retrocálculo; salida saturada realimentada |
| Salto brusco de la salida al cambiar la consigna | Derivada sobre el error | Derivar la medida; rampa de consigna |
| La salida tiembla o el actuador vibra | Derivada sin filtrar o con mucha ganancia, ruido del sensor | Filtro con N entre 5 y 10; filtrar la medida; quitar la D |
| Oscilación sostenida | Kp o integral demasiado altos para el retardo | Bajar Kp; aumentar Ti; acercar el sensor |
| Oscilación lenta con períodos largos | Ti demasiado corto | Aumentar Ti (al menos del orden de Tu) |
| Nunca llega a la consigna (con PI) | Integral deshabilitada o saturada, ti = 0 | Verificar Ti y la pinza; ¿llega el actuador a la potencia necesaria? |
| El PID se vuelve loco tras un cable suelto | La integral acumuló o se usó el dato inválido | Congelar el estado y reiniciar sin saltos al volver |
| El comportamiento cambia si cambia el período | Ts real distinto del asumido (lazo irregular) | Período exacto con proximo += periodo; medir Ts real |
| Empuja en sentido contrario | Signo del error mal puesto | Probar el sentido con una perturbación manual |
| Funciona en el verano, no en el invierno | Proceso no lineal con una única sintonía | Ganancias programadas; sintonizar en el peor caso |
- Empezá en manual: verificá el sentido y la potencia de régimen con la salida fija.
- Registrá la consigna, la medida, la salida y las contribuciones P, I y D durante una prueba con escalón y otra con perturbación.
- Probá la saturación a propósito: pedí una consigna inalcanzable un rato y volvé a una alcanzable: no debe haber sobreimpulso por windup.
- Medí el ruido de la salida con el sistema quieto y comprobá que no maltrata al actuador.
- Simulá la falla del sensor y verificá el estado seguro y la reanudación sin saltos.
11 · Analogía con programación
Un PID simulado con windup, ajuste y ruido
Implementamos el PID de la sección anterior en Python y lo aplicamos al mismo horno simulado del tema 42: el arranque en frío con y sin protección contra el windup, la respuesta a una perturbación, las sintonías que oscilan, el efecto de la derivada sobre el ruido, las reglas de ajuste (Ziegler-Nichols, relé y lambda) y el golpe de derivada.
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
# ---- Planta: el horno del tema 42 (100 W, 2000 J/K, 0,5 K/W, retardo del sensor de 20 s) ----
P_MAX, CAP, RES = 100.0, 2000.0, 0.5
M32 = 2 ** 32
class Ruido:
def __init__(self, sigma, semilla=12345):
self.sigma, self.x = sigma, semilla
def dato(self):
if self.sigma == 0:
return 0.0
s = 0.0
for _ in range(6):
self.x = (self.x * 1664525 + 1013904223) % M32
s += self.x / M32
return (s - 3) / 0.7071 * self.sigma
class PID:
"""PID de posición: derivada sobre la medida con filtro, salida limitada a 0..1 y tres modos de anti-windup."""
def __init__(self, kp, ti=math.inf, td=0.0, ts=1.0, n=10.0, modo="pinza", tt=None):
self.kp, self.ti, self.td, self.ts, self.n, self.modo = kp, ti, td, ts, n, modo
self.tt = tt if tt is not None else (ti if not math.isinf(ti) else math.inf)
self.i = self.d = 0.0
self.previa = None
def paso(self, consigna, medida):
e = consigna - medida
if self.previa is None:
self.previa = medida
p = self.kp * e
if self.td > 0: # derivada filtrada, sobre la medida: sin golpe al cambiar la consigna
a = self.td / (self.td + self.n * self.ts)
self.d = a * self.d - self.kp * self.td * self.n / (self.td + self.n * self.ts) * (medida - self.previa)
self.previa = medida
ki = 0.0 if math.isinf(self.ti) else self.kp / self.ti
i_nueva = self.i + ki * e * self.ts
sin_limitar = p + i_nueva + self.d
u = min(1.0, max(0.0, sin_limitar))
if self.modo == "pinza" and sin_limitar != u and e * (sin_limitar - u) > 0:
i_nueva = self.i # saturado y el error empuja más: no integrar
elif self.modo == "retro" and not math.isinf(self.tt):
i_nueva += self.ts / self.tt * (u - sin_limitar) # realimentar el exceso para desacumular
self.i = i_nueva
return min(1.0, max(0.0, p + self.i + self.d))
def simular(ctrl, consigna=40.0, t_amb=15.0, retardo=20, sigma=0.0, segundos=10800, perturbacion=None):
temp = t_amb
pasado = [temp] * (retardo + 1)
ruido = Ruido(sigma)
historia = []
for t in range(segundos):
if perturbacion and t == perturbacion[0]:
t_amb = perturbacion[1]
medida = pasado[0] + ruido.dato()
u = ctrl.paso(consigna, medida)
temp += (P_MAX * u - (temp - t_amb) / RES) / CAP
pasado.append(temp)
pasado.pop(0)
historia.append((temp, u, ctrl.i))
return historia
def metricas(historia, consigna=40.0):
temps = [t for t, _, _ in historia]
sobre = max(0.0, max(temps) - consigna)
ultimo = max((k for k, v in enumerate(temps) if abs(v - consigna) > 0.5), default=0)
final = sum(temps[-600:]) / 600
return sobre, ultimo, final
# ---- 1. Los tres términos y el anti-windup (arranque en frío) ----
print("controlador sobreimpulso entra en ±0,5 °C T final integral máx.")
for nombre, c in (("P (K_p = 0,2)", PID(0.2)),
("PI (0,5; Ti = 200 s) sin protección", PID(0.5, 200, modo="ninguno")),
("PI (0,5; Ti = 200 s) con pinza", PID(0.5, 200)),
("PI (0,5; Ti = 200 s) retro Tt = 50 s", PID(0.5, 200, modo="retro", tt=50)),
("PI (0,5; Ti = 200 s) retro Tt = Ti", PID(0.5, 200, modo="retro"))):
h = simular(c)
sobre, ultimo, final = metricas(h)
print(f"{nombre:36s} {sobre:6.2f} °C {ultimo:6d} s {final:6.2f} {max(i for _, _, i in h):6.2f}")
# ---- 2. Perturbación: el ambiente baja de 15 a 5 °C a los 6000 s ----
print()
print("perturbación (ambiente 15 -> 5 °C a los 6000 s):")
for nombre, c in (("P (K_p = 0,2)", PID(0.2)), ("PI (0,5; Ti = 200 s)", PID(0.5, 200)), ("PI (1; Ti = 100 s)", PID(1.0, 100)),
("PI de Ziegler-Nichols (0,71; 66 s)", PID(0.71, 66)), ("PID de Ziegler-Nichols (0,95; 39,5 s; 9,9 s)", PID(0.95, 39.5, 9.9))):
h = simular(c, segundos=12000, perturbacion=(6000, 5.0))
tramo = [t for t, _, _ in h][6000:]
desvio = max(abs(v - 40) for v in tramo)
final = sum(t for t, _, _ in h[-600:]) / 600
u = sum(u for _, u, _ in h[-600:]) / 600
print(f" {nombre:44s} desvío máx. {desvio:5.2f} °C final {final:6.2f} °C potencia final {u * 100:3.0f} %")
# ---- 3. Mala sintonía ----
print()
print("sintonías que oscilan (última hora de 2 h):")
for nombre, c in (("PI (1; Ti = 100 s): bien", PID(1.0, 100)), ("PI (0,5; Ti = 20 s): integral muy rápida", PID(0.5, 20)),
("PI (2; Ti = 100 s): ganancia alta", PID(2.0, 100)), ("PI (3; Ti = 100 s): ganancia muy alta", PID(3.0, 100))):
temps = [t for t, _, _ in simular(c, segundos=7200)][-3600:]
print(f" {nombre:42s} oscilación {max(temps) - min(temps):5.3f} °C")
# ---- 4. La derivada y el ruido de 0,1 °C ----
print()
print("ruido de 0,1 °C en el sensor: variación de la salida (desviación típica, 0 a 1):")
for nombre, c in (("PI (1; 100 s)", PID(1.0, 100)), ("PID Td = 10 s, N = 10", PID(1.0, 100, 10)),
("PID Td = 30 s, N = 10", PID(1.0, 100, 30)), ("PID Td = 30 s, N = 100", PID(1.0, 100, 30, n=100))):
u = [x for _, x, _ in simular(c, sigma=0.1, segundos=7200)][-3600:]
media = sum(u) / len(u)
sd = math.sqrt(sum((x - media) ** 2 for x in u) / len(u))
print(f" {nombre:24s} u media {media:5.3f} desviación típica {sd:5.3f} ganancia de alta frecuencia {c.kp * (1 + c.n) if c.td > 0 else c.kp:5.1f}")
# ---- 5. Ajuste por Ziegler-Nichols de lazo cerrado y por el método del relé ----
print()
tau, retardo, k_planta = RES * CAP, 20.0, P_MAX * RES
w = 0.05
for _ in range(60):
w = (math.pi - math.atan(w * tau)) / retardo
ku, tu = math.sqrt(1 + (w * tau) ** 2) / k_planta, 2 * math.pi / w
print(f"ganancia crítica K_u = {ku:.2f} 1/°C (banda crítica {1 / ku:.2f} °C) y período T_u = {tu:.0f} s")
print(f" P: K_p = {0.5 * ku:.2f}")
print(f" PI: K_p = {0.45 * ku:.2f}, Ti = {tu / 1.2:.0f} s")
print(f" PID: K_p = {0.6 * ku:.2f}, Ti = {tu / 2:.1f} s, Td = {tu / 8:.1f} s")
temp, pasado, estado = 15.0, [15.0] * 21, []
for t in range(10800): # relé ideal (histéresis cero): produce la oscilación crítica
u = 1.0 if pasado[0] < 40 else 0.0
temp += (P_MAX * u - (temp - 15.0) / RES) / CAP
pasado.append(temp)
pasado.pop(0)
estado.append((temp, u))
ultima = [t for t, _ in estado][-3600:]
amplitud = (max(ultima) - min(ultima)) / 2
cambios = [k for k in range(3600 - 1) if estado[-3600 + k][1] != estado[-3600 + k + 1][1]]
periodo = 2 * (cambios[-1] - cambios[0]) / (len(cambios) - 1)
ku_rele = 4 * 0.5 / (math.pi * amplitud)
print(f"método del relé: amplitud {amplitud:.2f} °C y período {periodo:.0f} s -> K_u estimada {ku_rele:.2f} 1/°C (real {ku:.2f}, error {abs(ku_rele - ku) / ku * 100:.0f} %)")
# ---- 6. Regla de la lambda (SIMC) a partir de una prueba de escalón ----
print()
for lam in (50, 100, 200):
kp = tau / (k_planta * (lam + retardo))
ti = min(tau, 4 * (lam + retardo))
h = simular(PID(kp, ti))
sobre, ultimo, final = metricas(h)
print(f" lambda = {lam:3d} s: K_p = {kp:.3f}, Ti = {ti:4.0f} s -> sobreimpulso {sobre:4.2f} °C, entra en la banda a los {ultimo} s")
# ---- 7. Golpe de la derivada al cambiar la consigna ----
print()
kp, td, ts, salto = 1.0, 10.0, 1.0, 3.0
print(f"salto de consigna de {salto:.0f} °C con derivada sobre el error: pico de {kp * td * salto / ts:.0f} en la salida (el máximo útil es 1); sobre la medida: 0")
Resultado: el PI (0,5; Ti = 200 s) sin protección acumula una integral de 20,45 en el arranque y se pasa 13,15 °C (2106 s para volver a la banda); con pinza, 0,00 °C y 741 s (la integral máxima es 0,50); con retrocálculo Tt = 50 s, 0,00 °C y 880 s, y con Tt = Ti, 0,90 °C. Ante la baja de ambiente de 15 a 5 °C, el P solo se desvía 3,18 °C y se queda en 36,82 °C con el 64 %; los PI y PID vuelven a 40,00 °C con el 70 % (desvíos máximos de 0,39; 0,29; 0,32 y 0,24 °C). Las sintonías (0,5; 20 s), (2; 100 s) y (3; 100 s) oscilan 1,338; 0,789 y 0,860 °C. Con 0,1 °C de ruido, la desviación típica de la salida pasa de 0,106 (PI) a 0,397 con una derivada de 10 s y a 0,479 con N = 100. Ziegler-Nichols da, para Ku = 1,58 y Tu = 79 s, PI = (0,71; 66 s) y PID = (0,95; 40 s; 9,9 s); el método del relé estima Ku = 1,27 (error del 20 %) con un período de 80 s; la regla lambda con 100 s da (0,167; 480 s) sin sobreimpulso. La derivada sobre el error con un salto de 3 °C daría un pico de 30 en la salida.
12 · Exploración interactiva
Términos, windup, ajuste y ruido
Los cuatro instrumentos usan el mismo horno simulado del programa de Python (consigna de 40 °C, ambiente de 15 °C, 20 s de retardo, un paso por segundo). El primero permite ajustar Kp, Ti y Td; el segundo compara la integral con y sin protección; el tercero calcula las ganancias de Ziegler-Nichols y las prueba; el cuarto muestra qué hace la derivada con el ruido.
Instrumento 1: los tres términos
Instrumento 2: windup de la integral
Instrumento 3: ajuste por Ziegler-Nichols
Instrumento 4: la derivada y el ruido
Recorrido guiado
- Con Kp = 1, Ti = 100 s, pinza y sin ruido: sin sobreimpulso, entra en la banda hacia los 670 s y, tras la perturbación de los 100 min, el desvío máximo es de unos 0,3 °C: el PI vuelve a 40,00 °C con el 70 % de potencia. Elegí «sin integral»: queda en el error del proporcional.
- Elegí Kp = 0,5 con Ti = 20 s: el lazo oscila (≈ 1,3 °C pico a pico). Con Kp = 3 y Ti = 100 s oscila por la ganancia alta (≈ 0,86 °C).
- Con Kp = 0,5, Ti = 200 s y anti-windup «ninguno»: sobreimpulso de unos 13 °C y 35 minutos para volver; con «pinza», sin sobreimpulso.
- Subí el ruido a 0,1 °C con Td = 10 s: la desviación típica de la salida pasa de 0,11 a unos 0,40 y el estado avisa de que la salida es ruidosa. Con Td = 0 vuelve a ser aceptable.
- En el windup, con Kp = 0,5 y Ti = 200 s: sin protección, 13,15 °C de sobreimpulso y una integral máxima de 20,45; con pinza, 0,00 °C y 0,50. Con Ti = 1000 s el windup es menor pero sigue presente.
- En Ziegler-Nichols, con Ku = 1,58 y Tu = 79 s y el PID: Kp = 0,95, Ti = 39,5 s y Td = 9,9 s; casi sin sobreimpulso. Si se sobreestima Ku (3, por ejemplo) con PI, las ganancias resultan demasiado altas para el horno y el lazo oscila.
- Pasá a P en Ziegler-Nichols: Kp = 0,5 Ku = 0,79 y un error en régimen apreciable: ZN no elimina el error con P solo.
- En el ruido, con Td = 30 s y N = 100, la ganancia a alta frecuencia es de 101 y la salida varía todavía más: un N más alto filtra menos el ruido de la derivada.
Desafío: el PID de un motor con encoder
Un motor DC (tema 31) se controla en velocidad con un encoder que da 20 pulsos cada 10 ms (un período de muestreo de 10 ms), y el proceso responde en unos 100 ms. ¿Qué controlador y qué período? PI con Ts = 10 ms (diez veces menor que la respuesta): la medida es la velocidad calculada por conteo de pulsos (con la cuantización de 1 pulso por muestra, un 5 % a 20 pulsos), y la derivada solo amplificaría esa cuantización: se evita. La integral elimina el error de velocidad cuando cambia la carga. Windup: el motor satura el PWM al 100 % al arrancar; hace falta pinza o retrocálculo. Salida: el PWM del puente H (tema 30), con un tiempo mínimo para no invertir sentido bruscamente. Seguridad: si el encoder deja de dar pulsos con la salida alta, el motor está trabado o el cable cortado: tras un tiempo límite, apagar (tema 44). Para la posición, en cambio, el motor es un integrador y se usa PD o PID con derivada filtrada, porque la medida es más limpia.
13 · Método de trabajo
Cómo poner en marcha un PID, para cualquier proceso
- Verificá en manual el sentido, la potencia de régimen y el límite del actuador antes de cerrar el lazo.
- Elegí un período de muestreo constante, mucho menor que el tiempo de respuesta, y programalo sin deriva.
- Empezá con PI; agregá derivada solo si el proceso es rápido, el sensor limpio y hace falta amortiguar.
- Obtené Ku y Tu (relé o tanteo) o la respuesta al escalón (K, τ, θ), y calculá las ganancias iniciales.
- Implementá bien los detalles: derivada sobre la medida y filtrada, anti-windup, salida limitada, estado seguro ante datos inválidos y transferencia sin saltos.
- Ajustá de a un parámetro con pruebas de escalón y de perturbación; busque rapidez sin oscilación.
- Probá los casos malos: saturación sostenida, sensor desconectado, consigna imposible, arranque en frío.
- Registrá y documentá las ganancias, la fecha y las condiciones de la sintonía; guardalas en la EEPROM.
Si el arranque se pasa, es el windup; si salta al cambiar la consigna, la derivada sobre el error; si la salida tiembla, la derivada o el ruido; si oscila, la ganancia o la integral; si no llega, la integral.
14 · Comprensión
Confusiones frecuentes
«Un PID siempre es mejor que un PI»
La derivada amplifica el ruido; en procesos lentos y con sensores ruidosos empeora la salida sin mejorar el control. Muchos lazos industriales (temperatura, nivel) usan PI.
«La integral solo sirve para eliminar el error en régimen»
También rechaza perturbaciones y encuentra la potencia de régimen sola. A cambio, introduce un desfasaje que empeora la estabilidad y el windup.
«Si la salida está saturada, la integral no importa»
Justamente entonces es cuando acumula: sin protección sigue sumando error y produce el sobreimpulso al salir de la saturación.
«Para ajustar un PID basta con subir la ganancia hasta que responda rápido»
Subirla acerca el lazo a la oscilación y amplifica el ruido. El procedimiento seguro parte de Ku o de un modelo y se afina de a un parámetro.
«Ziegler-Nichols da el ajuste final»
Da un punto de partida, algo agresivo. Casi siempre hay que reducir un poco la ganancia o alargar Ti según el sobreimpulso que se tolere.
«El período de muestreo no importa mientras sea rápido»
Un período irregular altera la integral y la derivada; uno demasiado largo agrega retardo; uno demasiado corto, ruido. Debe ser constante y adecuado al proceso.
15 · Práctica guiada
Predecí antes de comprobar
1. Formas del PID
Un PID estándar tiene Kp = 2 (1/°C), Ti = 50 s y Td = 5 s. ¿Cuánto valen Ki y Kd en la forma paralela?
Ver solución
Ki = Kp/Ti = 2/50 = 0,04 por °C y por segundo; Kd = Kp·Td = 2 × 5 = 10 s/°C.
2. Ziegler-Nichols
Un proceso oscila con Ku = 3 y Tu = 40 s. ¿Qué ganancias da Ziegler-Nichols para un PID?
Ver solución
Kp = 0,6 × 3 = 1,8; Ti = 40/2 = 20 s; Td = 40/8 = 5 s.
3. Golpe de la derivada
Con Kp = 0,5, Td = 20 s y Ts = 2 s, la consigna salta 4 °C. ¿Qué pico produce la derivada sobre el error en el primer paso? ¿Y sobre la medida?
Ver solución
0,5 × 20 × 4 / 2 = 20, veinte veces el máximo útil (la salida satura). Sobre la medida: 0, porque la medida no salta.
4. Windup
Un PI con Kp = 0,5 y Ti = 200 s mantiene un error de 10 °C durante 300 s con la salida saturada. ¿Cuánto vale la integral al final, sin protección?
Ver solución
Ki = 0,5/200 = 0,0025 por °C·s; I = 0,0025 × 10 × 300 = 7,5, es decir 750 % de la salida; el actuador solo puede dar 100 %. Descargarla exige un error negativo acumulado de 3000 °C·s.
5. Ruido
Un PID con Kp = 1 y N = 10 tiene derivada filtrada. ¿Cuánto vale su ganancia a alta frecuencia y qué hace con un ruido de 0,1 °C?
Ver solución
Kp(1 + N) = 1 × 11 = 11. Un ruido de 0,1 °C a alta frecuencia podría aparecer como hasta 1,1 en la salida, más que todo su rango (0 a 1); en la simulación, la desviación típica sube de 0,106 a 0,397.
6. Diagnóstico
Un PID de temperatura, al arrancar con la cámara fría, se pasa 10 °C de la consigna y tarda media hora en volver; luego funciona bien en régimen. ¿Qué pasa y qué cambiás?
Ver solución
Windup de la integral durante el arranque (la salida estuvo saturada mucho tiempo). Se agrega anti-windup (pinza o retrocálculo) y, opcionalmente, una rampa de consigna. Solo afecta al arranque porque en régimen la salida no satura.
16 · Síntesis
Ideas para recordar
- El PID suma tres acciones sobre el error: proporcional (presente), integral (pasado acumulado) y derivativa (tendencia): u = Kp[e + (1/Ti)∫e dt + Td de/dt].
- La integral elimina el error en régimen y encuentra sola la potencia necesaria (70 % con 5 °C de ambiente en el horno), a costa de empeorar la estabilidad.
- En un microcontrolador: período Ts constante, derivada sobre la medida y filtrada (ganancia Kp(1 + N)), salida limitada y transferencia sin saltos.
- Sin anti-windup, la integral se carga mucho más allá del actuador (20,45 en el horno) y la temperatura se pasa 13 °C; la pinza o el retrocálculo lo evitan.
- Ziegler-Nichols (Kp = 0,6 Ku, Ti = Tu/2, Td = Tu/8) da un punto de partida agresivo; el método del relé estima Ku y Tu con seguridad; la regla lambda ajusta rapidez y robustez con un solo número.
- La derivada amplifica el ruido (0,106 → 0,397 de desviación típica de la salida con 0,1 °C de ruido): en procesos lentos y ruidosos se usa PI.
- Derivar la medida y no el error evita el golpe al cambiar la consigna (un pico de 30 en el ejemplo).
- Antes de cerrar el lazo: probar en manual, proteger la saturación, definir el estado seguro ante datos inválidos y registrar las contribuciones P, I y D.
¿Listo para el tema 44?
Antes de avanzar, explicá qué es el windup y cómo se evita, calculá las ganancias de Ziegler-Nichols para un PID con Ku = 2 y Tu = 30 s y decí por qué la derivada se aplica a la medida y con un filtro. Si podés justificar las tres respuestas, ya sabés poner en marcha un PID.
En el próximo tema nos ocupamos de lo que pasa cuando algo sale mal: seguridad, fallos y robustez, con sensores defectuosos, límites de seguridad, perros guardianes y modos seguros.