[논문 리뷰] DQN이 합성 제트로 날개의 와류를 길들이다 — 강화학습 기반 능동 유동 제어
DQN·Dueling DQN이 합성 제트를 조절해 양력을 키우고 항력을 줄인다
받음각이 큰 날개 뒤로 와류가 번갈아 떨어진다. 양력은 매 주기 출렁이고, 날개는 떨린다. 엔지니어는 보통 이런 진동을 형상 설계나 고정된 주기 강제(periodic forcing)로 누른다. Hammouda 등(2026)은 다른 길을 택했다. 날개에 작은 합성 제트(synthetic jet, 주기적으로 불고 빨아들이는 무토출 액추에이터) 구멍을 뚫고, 그 분사 속도를 강화학습 에이전트가 스스로 정하게 했다. 오늘은 이 논문이 와류 흘림(vortex shedding)을 어떻게 강화학습 문제로 번역했는지 보고, ε-greedy Q-학습으로 같은 아이디어를 직접 돌려본다.
이 논문의 좌표#
- 제목: Application of deep reinforcement learning for aerodynamic control around an angled airfoil via synthetic jet
- 저자: N. Ghezaiel Hammouda, R. Khan, L. Mostafa 외 (Scientific Reports, 2026)
- 세팅: Reynolds 수(관성력/점성력 비) 100, Mach 수 0.2의 약압축성 층류. 받음각이 큰 날개 + 앞전 근처 합성 제트.
- 핵심 결과: Dueling DQN이 가장 안정적으로 수렴해 와류 흘림을 줄이고, 양력을 키우며 항력을 낮췄다.
Re 100이면 흐름은 층류지만, 받음각이 크면 날개 뒤에서 와류가 주기적으로 떨어진다. 이 와류 흘림이 양력·항력을 진동시키는 주범이다.
와류를 강화학습 문제로 번역하기#
강화학습(시행착오로 보상을 최대화하는 정책을 배우는 기법)은 세 가지만 정의하면 시작된다.
- 상태(state): 날개 주위와 후류에 흩뿌린 가상 센서가 읽는 압력·속도 값. 논문은 압력만 쓸 때보다 속도까지 함께 넣을 때 학습이 빨라진다고 보고한다.
- 행동(action): 합성 제트의 분사 속도 . 0부터 20 m/s까지 1 m/s 간격의 21개 정수 레벨로 이산화했다. DQN이 이산 행동을 요구하기 때문이다.
- 보상(reward): 항력은 깎고 양력은 키우는 한 줄짜리 함수.
여기서 , 는 한 행동 구간 동안 평균낸 항력·양력 계수다. , 는 보상을 양수로 유지하고 양력 대 항력의 비중을 맞추는 상수로, 논문은 , 를 썼다. 한 번의 행동은 와류 흘림 한 주기에 대응하고, 학습은 에피소드당 25주기씩 총 300 에피소드를 돈다.
ε-greedy: 탐험과 활용 사이#
에이전트는 각 행동의 가치를 행동가치함수 로 추정한다. 핵심은 Bellman 갱신이다.
는 학습률, 는 미래 보상을 깎는 할인율, 는 다음 상태에서 기대할 수 있는 최선의 가치다.
문제는 아직 가치를 모르는 행동을 어떻게 시도하느냐다. ε-greedy 정책이 답이다. 확률 로는 지금까지 가장 좋아 보이는 행동(활용)을, 확률 로는 무작위 행동(탐험)을 고른다. 이 크면 더 많이 탐험하고, 작으면 빨리 한 곳에 정착한다.
아래 시뮬레이션에서 직접 조작해보자. 막대는 21개 제트 속도 각각의 추정 가치 이고, 노란 막대는 탐험, 청록 막대는 활용으로 방금 고른 행동이다.
을 0에 가깝게 두면 에이전트가 우연히 처음 높게 잡힌 행동에 갇히는 걸 볼 수 있다. 0.2 부근에서는 12 m/s 근처의 진짜 최적값을 빠르게 찾아간다. 탐험이 너무 많으면(0.8) 좋은 값을 알면서도 계속 엉뚱한 곳을 찔러본다.
합성 제트라는 행동#
합성 제트는 막을 진동시켜 같은 구멍으로 공기를 내뿜고 다시 빨아들인다. 알짜 질량 토출은 0이지만, 운동량은 경계층에 주입된다. 이 주입량을 무차원으로 나타낸 것이 운동량 계수다.
, , 는 제트의 밀도·속도·구멍 지름이고, , , 는 자유류 밀도·속도와 코드 길이다. 논문에서 구멍은 앞전 근처 흡입면 에 있고 지름 0.2 mm다. 제트가 경계층에 운동량을 더하면 박리(boundary layer separation)가 늦춰지고, 와류 흘림이 약해진다.
아래 시뮬레이션에서 직접 조작해보자. 제트 속도를 올리면 후류의 와류가 어떻게 변하는지 본다.
가 0이면 강한 와류가 번갈아 떨어지고 진동 폭이 크다. 속도를 15~20 m/s로 올리면 와류가 옅어지고 후류가 안정되며, 양력 진동이 눈에 띄게 줄어든다. 이것이 보상 함수가 보상하려는 바로 그 상태다.
직접 구현: Q-학습으로 제트 켜기#
논문의 DQN을 그대로 옮기는 대신, 핵심 아이디어만 남긴 표(table) 기반 Q-학습으로 같은 제어를 재현한다. 상태는 양력 진동 폭을 이산화한 칸이고, 행동은 제트 속도다.
import numpy as np
class SyntheticJetEnv:
"""1D 현상학적 날개-후류 환경.
상태 : 양력 진동 폭을 이산화한 칸 (0..n_bins-1)
행동 : 제트 속도 레벨 {0,1,...,20} m/s
보상 : R1 - <Cd> + R2*<Cl> (논문 식 4)
"""
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 # 정규화된 와류 진동 폭 (1 = 무제어)
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 # 제어 권한 0..1
target = max(0.05, 1.0 - 0.8 * ctrl) # 제트가 진동 폭을 누른다
self.amp += 0.5 * (target - self.amp) # 1차 완화
cl = 1.8 + 0.2 * ctrl - 0.4 * self.amp # 양력 계수
cd = 0.085 - 0.006 * ctrl + 0.02 * self.amp # 항력 계수
waste = 0.01 * max(0, action - self.peak) # 과도한 분사 페널티
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))) # 탐험
return int(np.argmax(q_row)) # 활용
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) # 선형 감쇠
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")출력은 다음과 같다.
episode 1 avg reward = 3.12
episode 300 avg reward = 3.25
learned jet velocity = 12 m/s에이전트는 처음엔 무작위로 헤매다, 300 에피소드 뒤 12 m/s 근처가 양력 이득과 분사 낭비 사이의 균형점임을 스스로 알아낸다. 논문의 보상 형태와 행동 공간을 그대로 따른 결과다.
DQN의 형제들: Double vs Dueling#
논문은 세 가지 DQN 변종을 비교했다.
- 전통 DQN: 연산으로 가치를 과대평가하는 경향이 있다.
- Double DQN: 행동 선택과 가치 평가에 다른 네트워크를 써 과대평가를 줄인다.
- Dueling DQN: 를 상태가치 와 어드밴티지 로 분리한다.
는 "이 상태가 얼마나 좋은가", 는 "그 안에서 이 행동이 평균보다 얼마나 나은가"를 따로 학습한다. 많은 행동이 비슷한 가치를 가질 때 — 제트 속도 11과 13 m/s가 거의 같을 때처럼 — 상태가치를 한 번만 배우면 되니 학습이 안정된다. 논문에서 Dueling DQN이 가장 일관된 학습 곡선과 최고 성능을 보인 이유다.
5층 × 128 뉴런 네트워크가 300 에피소드 만에 수렴했고, 능동 제어를 켠 경우 이 1.79에서 약 2.0으로 오르면서 후류가 안정됐다.
기억할 점#
- 유동 제어를 RL로 번역하는 레시피: 상태 = 센서 압력·속도, 행동 = 제트 속도(이산), 보상 = .
- 합성 제트는 알짜 질량 0으로 운동량만 경계층에 주입해 박리를 늦추고 와류 흘림을 약화시킨다.
- Dueling DQN은 분리 덕에 비슷한 행동이 많은 유동 제어 문제에서 가장 안정적으로 수렴한다.
도움이 됐다면 공유해주세요.