[Reseña de artículo] Cómo una DQN domó los vórtices de un perfil con un chorro sintético — Control activo de flujo por aprendizaje por refuerzo
DQN y Dueling DQN controlan un chorro sintético para subir la sustentación y bajar la resistencia
Detrás de un perfil aerodinámico con un ángulo de ataque alto, los vórtices se desprenden en alternancia. La sustentación oscila en cada ciclo y el ala vibra. Los ingenieros suelen sofocar esa vibración con ajustes de geometría o un forzamiento periódico fijo (periodic forcing). Hammouda y colaboradores (2026) tomaron otro camino. Perforaron en el ala un pequeño chorro sintético (synthetic jet, un actuador de masa neta cero que sopla y aspira por turnos) y dejaron que un agente de aprendizaje por refuerzo decidiera por sí mismo su velocidad de soplado. Hoy veremos cómo el artículo tradujo el desprendimiento de vórtices (vortex shedding) en un problema de aprendizaje por refuerzo, y luego ejecutaremos la misma idea con Q-learning ε-greedy.
Dónde se ubica este artículo#
- Título: Application of deep reinforcement learning for aerodynamic control around an angled airfoil via synthetic jet
- Autores: N. Ghezaiel Hammouda, R. Khan, L. Mostafa y otros (Scientific Reports, 2026)
- Escenario: flujo laminar débilmente compresible con número de Reynolds (relación fuerza de inercia/viscosa) 100 y número de Mach 0,2. Un perfil con ángulo alto y un chorro sintético cerca del borde de ataque.
- Resultado clave: Dueling DQN convergió de forma más fiable, reduciendo el desprendimiento de vórtices mientras subía la sustentación y bajaba la resistencia.
A Re 100 el flujo es laminar, pero con un ángulo de ataque alto los vórtices se desprenden periódicamente detrás del ala. Ese desprendimiento es lo que hace oscilar la sustentación y la resistencia.
Traducir los vórtices a un problema de aprendizaje por refuerzo#
El aprendizaje por refuerzo (aprender una política que maximiza la recompensa por ensayo y error) solo necesita definir tres cosas para arrancar.
- Estado (state): presión y velocidad que leen sensores virtuales repartidos alrededor del perfil y en la estela. El artículo informa que añadir la velocidad a la presión acelera el aprendizaje.
- Acción (action): la velocidad de soplado del chorro . Se discretiza en 21 niveles enteros de 0 a 20 m/s con paso de 1 m/s, porque la DQN exige un conjunto de acciones discreto.
- Recompensa (reward): una función de una línea que recorta la resistencia y eleva la sustentación.
Aquí y son los coeficientes de resistencia y sustentación promediados sobre un intervalo de acción. y son constantes que mantienen la recompensa positiva y equilibran sustentación frente a resistencia; el artículo usó , . Una acción abarca un periodo de desprendimiento de vórtices, y el entrenamiento corre 300 episodios de 25 periodos cada uno.
ε-greedy: entre exploración y explotación#
El agente estima el valor de cada acción con la función de valor de acción . El núcleo es la actualización de Bellman.
es la tasa de aprendizaje, el factor de descuento que reduce la recompensa futura y el mejor valor alcanzable desde el siguiente estado.
El truco está en cómo probar acciones cuyo valor aún se desconoce. La política ε-greedy responde a eso. Con probabilidad elige la acción que parece mejor hasta ahora (explotación); con probabilidad elige una al azar (exploración). Un grande explora más; uno pequeño se asienta antes.
Pruébalo en la simulación de abajo. Las barras son el valor estimado de cada una de las 21 velocidades del chorro; una barra amarilla marca una elección de exploración y una cian, de explotación.
Con cerca de 0 se ve cómo el agente queda atrapado en la acción que por azar pareció buena primero. Alrededor de 0,2 converge rápido hacia el óptimo real cercano a 12 m/s. Con demasiada exploración (0,8) sigue tanteando otros sitios aunque ya conozca el buen valor.
El chorro sintético como acción#
Un chorro sintético hace vibrar una membrana para soplar aire por un orificio y volver a aspirarlo. La masa neta expulsada es cero, pero se inyecta cantidad de movimiento en la capa límite. La medida adimensional de esa inyección es el coeficiente de cantidad de movimiento.
, , son la densidad, la velocidad y el diámetro del orificio del chorro; , , son la densidad y velocidad de la corriente libre y la cuerda. En el artículo el orificio está en el lado de succión cerca del borde de ataque, en , con 0,2 mm de diámetro. Cuando el chorro añade cantidad de movimiento a la capa límite, la separación (boundary layer separation) se retrasa y el desprendimiento de vórtices se debilita.
Pruébalo en la simulación de abajo. Sube la velocidad del chorro y observa cómo cambian los vórtices de la estela.
Con se desprenden vórtices fuertes en alternancia y el vaivén de es amplio. Lleva la velocidad a 15–20 m/s y los vórtices se desvanecen, la estela se asienta y la oscilación de sustentación se reduce de forma visible. Ese es justo el estado que la función de recompensa premia.
Manos a la obra: encender el chorro con Q-learning#
En lugar de portar la DQN del artículo al pie de la letra, reproducimos el mismo control con un Q-learning basado en tabla (table) que conserva solo la idea central. El estado es la amplitud de oscilación de la sustentación discretizada, y la acción es la velocidad del chorro.
import numpy as np
class SyntheticJetEnv:
"""Entorno fenomenológico 1D de perfil-estela.
Estado : amplitud de oscilacion de sustentacion discretizada (0..n_bins-1)
Accion : nivel de velocidad del chorro {0,1,...,20} m/s
Recompensa : R1 - <Cd> + R2*<Cl> (Ec. 4 del articulo)
"""
def __init__(self, n_bins=6, peak=12, R1=3.0, R2=0.2, seed=0):
self.n_bins, self.peak = n_bins, peak
self.R1, self.R2 = R1, R2
self.rng = np.random.default_rng(seed)
self.amp = 1.0 # amplitud de desprendimiento normalizada (1 = sin control)
def reset(self):
self.amp = 1.0
return self._bin()
def _bin(self):
return min(self.n_bins - 1, int(self.amp * self.n_bins))
def step(self, action):
ctrl = action / 20.0 # autoridad de control 0..1
target = max(0.05, 1.0 - 0.8 * ctrl) # el chorro reduce la amplitud
self.amp += 0.5 * (target - self.amp) # relajacion de primer orden
cl = 1.8 + 0.2 * ctrl - 0.4 * self.amp # coeficiente de sustentacion
cd = 0.085 - 0.006 * ctrl + 0.02 * self.amp # coeficiente de resistencia
waste = 0.01 * max(0, action - self.peak) # penalizacion por soplar de mas
reward = self.R1 - cd + self.R2 * cl - waste
reward += self.rng.normal(0, 0.05)
return self._bin(), reward
def epsilon_greedy(q_row, eps, rng):
if rng.random() < eps:
return int(rng.integers(len(q_row))) # explorar
return int(np.argmax(q_row)) # explotar
def train_jet_controller(episodes=300, steps=25, alpha=0.1, gamma=0.9, eps0=0.3):
env = SyntheticJetEnv()
n_actions = 21
Q = np.zeros((env.n_bins, n_actions))
rng = np.random.default_rng(1)
history = []
for ep in range(episodes):
s = env.reset()
eps = eps0 * (1 - ep / episodes) # decaimiento lineal
total = 0.0
for _ in range(steps):
a = epsilon_greedy(Q[s], eps, rng)
s2, r = env.step(a)
Q[s, a] += alpha * (r + gamma * Q[s2].max() - Q[s, a])
s, total = s2, total + r
history.append(total / steps)
best = int(np.argmax(Q.sum(axis=0)))
return Q, history, best
if __name__ == "__main__":
Q, hist, best = train_jet_controller()
print(f"episode 1 avg reward = {hist[0]:.3f}")
print(f"episode 300 avg reward = {hist[-1]:.3f}")
print(f"learned jet velocity = {best} m/s")La salida se ve así.
episode 1 avg reward = 3.12
episode 300 avg reward = 3.25
learned jet velocity = 12 m/sEl agente vaga al azar al principio y, tras 300 episodios, descubre por sí mismo que cerca de 12 m/s está el punto de equilibrio entre la ganancia de sustentación y el soplado desperdiciado. Eso se deduce directamente de la forma de la recompensa y del espacio de acciones del artículo.
Los hermanos de la DQN: Double vs Dueling#
El artículo comparó tres variantes de DQN.
- DQN clásica: el operador tiende a sobrestimar los valores.
- Double DQN: usa redes separadas para la selección de acción y la evaluación del valor, frenando esa sobrestimación.
- Dueling DQN: separa en un valor de estado y una ventaja .
aprende "qué tan bueno es este estado", mientras que aprende "cuánto mejor que el promedio es esta acción dentro de él". Cuando muchas acciones comparten un valor similar —como cuando las velocidades de chorro 11 y 13 m/s son casi idénticas— basta con aprender el valor de estado una sola vez, lo que estabiliza el entrenamiento. Por eso la Dueling DQN mostró la curva de aprendizaje más consistente y el mejor rendimiento en el artículo.
Una red de 5 capas × 128 neuronas convergió en 300 episodios y, con el control activo encendido, subió de 1,79 a cerca de 2,0 mientras la estela se asentaba.
Qué recordar#
- La receta para plantear el control de flujo como RL: estado = presión y velocidad de sensores, acción = velocidad de chorro (discreta), recompensa = .
- Un chorro sintético inyecta cantidad de movimiento pura con masa neta cero, retrasando la separación y debilitando el desprendimiento de vórtices.
- La Dueling DQN, gracias a la separación , converge de forma más estable en problemas de control de flujo donde muchas acciones se parecen.
Comparte si te resultó útil.