제6부 심화 주제
6.1 모델예측제어 (MPC)
제6부 심화 주제 · 시작. LQR(4.5)은 해석적으로 간결하지만 제약을 명시적으로 못 다뤘다(4.5.9). 실제 시스템에는 액추에이터 한계·안전 경계 같은 하드 제약이 있다. MPC는 매 스텝 모델로 미래를 예측해 제약 하의 최적 제어를 온라인으로 푼다. 자율주행·공정·로봇의 고급 제어 표준이다.
이 장을 마치면 MPC의 수평선·재계획(receding horizon) 구조를 설명하고, MPC가 제약 있는 유한구간 LQR임을 이해하며, 안정성·계산이 대가가 따름을 알아야 한다. (개념·진입점 위주 — BK-03의 약속대로.)
6.1.1 동기 — 제약을 명시적으로
4.5.9에서 LQR의 한계를 봤다: 액추에이터가 $\pm5 \,\mathrm{N}$로 포화되는데 LQR은 그것을 모르고 $10 \,\mathrm{N}$를 요구한다. 안티와인드업(2.5.6.3)은 사후 보정이지, 제약을 설계에 넣은 것이 아니다.
MPC의 발상: *제약을 최적화 문제에 직접 넣고, 매 스텝 풀자. "이 입력·상태 한계를 지키면서, 앞으로 N스텝 동안 비용을 최소화하는 최적 입력열은?"을 실시간으로 계산한다. 제약을 예측*해 미리 대응하는 것이 핵심 — 벽에 부딪히기 전에 미리 감속한다.
6.1.2 핵심 아이디어 — 수평선 위에서 계획, 한 발만 실행
이 후퇴 수평선(receding horizon)이 MPC의 본질이다:
- 예측: 현재 상태에서 모델로 미래 $N$스텝(예측 수평선)을 예측한다.
- 최적화: 제약을 지키며 비용 최소인 입력열
u_k…u_{k+N−1}을 푼다. - 실행: 첫 입력
u_k만 적용한다. - 재계획: 다음 스텝 새 측정으로 1~3 반복.
왜 첫 입력만? 다음 스텝에는 새 측정이 들어와 더 나은 계획을 세울 수 있으니까. 재최적화 자체가 피드백이다 — 계획은 개루프지만, 매 스텝 다시 풀어 폐루프가 된다.
6.1.3 최적화 문제 (QP)
매 스텝 푸는 문제(현재 상태 $x$에서):
$$\min_{u_0,\ldots,u_{N-1}} \quad \underbrace{\sum_{i=0}^{N-1}\left(x_i^T Q x_i + u_i^T R u_i\right)}_{\text{단계 비용}} + \underbrace{x_N^T P_f x_N}_{\text{종단 비용}}$$
- s.t.
- $x_0 = x$ (현재 상태)
- $x_{i+1} = A x_i + B u_i$ (모델 동역학)
- $u_{\min} \le u_i \le u_{\max}$ (입력 제약 ★ LQR엔 없던 것)
- $x_{\min} \le x_i \le x_{\max}$ (상태 제약)
- 모델이 선형 + 비용이 2차 + 제약이 선형이면, 이것은 2차 계획법(QP, Quadratic Program)이다 — 잘 연구된 볼록 최적화라 매 스텝 빠르게 푼다.
- 비선형 모델·제약이면 비선형 계획(NLP) → 계산 비용이 크다(NMPC, 6.1.8).
6.1.4 LQR과의 관계 — 제약 있는 유한구간 LQR
MPC와 LQR은 같은 계열이다:
- 제약 없고 수평선 $N\to\infty$인 MPC = LQR(4.5). 같은 2차 비용을 무한구간으로 풀면 일정 이득 $K$가 나온다.
- 즉 MPC = "제약을 추가하고 유한구간으로 자른 LQR을 매 스텝 다시 푸는 것"(4.5.6의 유한구간 리카티가 뿌리).
- 종단 비용
P_f: 유한구간으로 자른 꼬리를 보상하려고, 끝 상태에 LQR 리카티 해 $P$를 종단 비용으로 쓴다 → 유한 $N$으로도 무한구간에 가깝게, 안정성도 돕는다(6.1.7).
한 줄: 제약이 활성 안 되면 MPC는 LQR처럼 행동하고, 제약에 닿으면 그것을 지능적으로 존중한다. 제약이 MPC의 존재 이유다.
6.1.5 튜닝 조정 변수 — 수평선·가중·종단
- 예측 수평선 $N$: 멀리 볼수록 좋지만(제약·미래 대비) 계산↑. 보통 지배 동특성의 정착시간을 덮을 만큼.
- 제어 수평선 $N_c \le N$: 입력을 바꾸는 구간(나머지는 고정)을 줄여 계산 절감.
- $Q, R$: LQR과 같은 성능 vs 노력(4.5.2).
- 종단 비용·종단 집합
P_f, X_f: 안정성·실현가능성의 핵심(6.1.7).
6.1.6 제약 — 입력·상태·종단, hard vs soft
- 입력 제약: 포화(
|u|≤u_max), 변화율($\vert\Delta u\vert\le$) — 액추에이터 물리 한계. - 상태 제약: 안전 경계(속도·위치·각도 한계, 장애물 회피).
- 종단 제약: 끝 상태를 안전 집합에 넣어 안정성 보장(6.1.7).
- 하드 vs 소프트: 하드 제약은 반드시 지켜야 하지만, 외란으로 위반이 불가피하면 문제가 실현불가(infeasible)가 되어 풀이가 없다. 소프트 제약(슬랙 변수 + 큰 벌점)으로 "되도록 지키되 불가피하면 약간 위반 허용"해 실현불가를 피한다. 상태 제약은 보통 소프트로(센서 잡음·외란 대비), 입력 제약은 하드로(물리 한계).
6.1.7 안정성·실현가능성 — 대가가 따른다
⚠️ 단순한 MPC는 불안정하거나 실현불가가 될 수 있다. "매 스텝 최적"이 폐루프 안정을 보장하지 않는다.
안정성·재귀적 실현가능성(recursive feasibility, 한 번 풀 수 있으면 이후에도 풀 수 있음)을 위해 보통 종단 재료(terminal ingredients)를 더한다:
- 종단 비용
P_f(LQR 리카티 해): 잘린 꼬리를 보상. - 종단 제약 집합
X_f: 끝 상태를 불변 안전 집합(그 안에서는 LQR이 제약 지키며 안정) 안에 유지하기. - 또는 수평선 $N$을 충분히 길게.
이 재료가 있으면 "비용함수가 리아푸노프 함수 역할"을 해 안정성을 증명할 수 있다(6.2의 리아푸노프와 연결). 정직히: 이론적 보장에는 신경 써야 하며, 검토 없이 작성한 MPC는 위험하다.
6.1.8 계산 — 온라인 QP, 실시간
MPC의 대가는 매 스텝 최적화를 푼다는 것이다.
- QP 솔버: 선형 MPC는 OSQP·qpOASES 같은 빠른 QP 솔버로 ms 안에. 실시간 루프(3.3)에 들어가려면 예측 가능한 시간 안에 풀려야.
- 명시적 MPC(explicit MPC): 작은 문제는 해를 미리 계산(상태공간을 영역으로 나눠 각 영역의 선형 법칙)해 온라인은 조회만 — 초고속이나 차원에 취약.
- 임베디드 MPC: 코드 생성(예: CVXGEN, acados)으로 MCU에서.
- 비선형 MPC(NMPC): 비선형 모델·제약 → NLP, SQP·내부점법으로. 훨씬 계산 비용이 크지만 강한 비선형(드론 고기동·로봇)에 필요.
6.1.9 도구로 — cvxpy로 선형 MPC
# mpc.py — 선형 MPC 한 스텝 (cvxpy QP)
import cvxpy as cp, numpy as np
# A,B: 모델, Q,R,Pf: 가중, x0: 현재상태, N: 수평선, umin/umax: 제약
def mpc_step(A, B, Q, R, Pf, x0, N, umin, umax):
n, m = B.shape
x = cp.Variable((n, N+1)); u = cp.Variable((m, N))
cost = 0; constr = [x[:,0] == x0]
for k in range(N):
cost += cp.quad_form(x[:,k], Q) + cp.quad_form(u[:,k], R)
constr += [x[:,k+1] == A @ x[:,k] + B @ u[:,k]]
constr += [u[:,k] >= umin, u[:,k] <= umax] # 입력 제약
cost += cp.quad_form(x[:,N], Pf) # 종단 비용(LQR P)
cp.Problem(cp.Minimize(cost), constr).solve()
return u[:,0].value # 첫 입력만 적용 → 다음 스텝 재호출
$Pf$엔 ct.lqr(이산계는 ct.dlqr)의 리카티 해 $P$를 넣어라(6.1.4·6.1.7). 제약 umin/umax를 좁혀 가며 MPC가 LQR과 달리 포화를 미리 존중하는지 관찰하라.
실측 확인: 이중적분기 A=[[1,dt],[0,1]], B=[[0],[dt]](dt=0.1)에 Q=diag(10,1), R=1로 ct.dlqr이 준 $K, P$를 그대로 mpc_step에 넣어, $x0=[5,0]$(목표 0)·u_max=1 제약·예측 수평선 $N=10$에서 확인했다(아래 폐루프 비교도 동일하게 $N=10$):
LQR 게인 K = [2.7617, 2.6491]
x0 = [5, 0]
LQR 요청 u = −K·x0 = −13.809 (|u|≤1 제약을 모른다)
MPC 첫 입력 u0 = −1.000 (제약을 자동으로 만족)
LQR은 제약을 모르고 물리적으로 불가능한 $u\approx-13.8$을 요구한다 — 실제라면 액추에이터가 이를 강제로 $\pm1$로 자를 수밖에 없다(사후 포화). MPC는 최적화 안에 제약을 넣었으므로 첫 스텝부터 이미 u_max=1을 스스로 존중한다.
두 정책을 40스텝(4 s) 폐루프로 실행해 비교(LQR 쪽은 매 스텝 u=−Kx를 계산한 뒤 [−1,1]로 사후 클램프해 적용):
t x_mpc v_mpc u_mpc | x_lqr v_lqr u_lqr
0.0 5.0000 0.0000 −1.0000 | 5.0000 0.0000 −1.0000
2.0 3.1000 −2.0000 −1.0000 | 3.1000 −2.0000 −1.0000
3.0 1.0165 −1.6891 1.0000 | 0.9104 −1.8900 1.0000
3.9 −0.1436 −0.7891 1.0000 | −0.4306 −0.9900 1.0000
초반에는 둘 다 포화(|u|=1)라 궤적이 같지만, MPC는 수평선 안에서 미리 감속 시점을 계산해(종단 비용 $Pf$가 "늦게 서면 비용이 크다"고 알려줌) 목표를 덜 오버슈트한다 — 4 s 뒤 위치가 MPC −0.223, LQR+사후클램프 −0.530(오버슈트 약 2.4배). 사후 클램프는 "일단 최댓값을 출력하고 뒤늦게 보정하는" 반응적 방식인 반면, MPC는 포화를 계획에 넣어 선제 대응한다 — 이것이 6.1.1의 동기("벽에 부딪히기 전에 미리 감속")가 수치로 나타난 모습이다.
(✅ cvxpy 1.7.5 · control 0.10.2 · numpy 2.2.6, ce-verify 도커에서 위 스크립트를 직접 실행해 확인한 실측값이다.)
6.1.10 정직 — 모델·계산·안정성
- 모델 기반: MPC는 모델로 예측한다 — 모델이 틀리면 예측·제약 존중이 다 틀린다(1.1.11·1.4). 강인 MPC·적응 MPC가 이를 다루지만 복잡.
- 계산 비용: 매 스텝 최적화는 PID·LQR보다 계산 부하가 훨씬 크다. 실시간 마감을 못 지키면 위험(3.3.9).
- 안정성·실현가능성은 대가가 따른다(6.1.7): 종단 재료 없이는 이론 보장이 없다.
- 튜닝: $N, Q, R$, 제약, 소프트 가중까지 조정 변수가 많다 — 시뮬레이션·검증이 필수.
그럼에도 제약을 명시적으로 다루는 유일한 체계적 방법이라, 액추에이터·안전 제약이 엄격한 현대 시스템에서 표준이 되어 간다.
6.1.10.1 선택 가이드 — PID vs LQR vs MPC
| PID | LQR | MPC | |
|---|---|---|---|
| 모델 필요 | 불필요(오차 기반 규칙) | 필요(선형 $A,B$) | 필요(선형·비선형) |
| 제약 처리 | 없음(포화는 사후 클램프+안티와인드업, 2.5.6.3) | 없음(4.5.9) | 명시적(입력·상태 제약을 최적화에 직접, 6.1.3) |
| 다변수·커플링 | SISO 위주, 다변수는 루프별 임시방편 | 자연스러움($Q,R$로 전 상태 동시 최적화) | 자연스러움(+ 제약까지) |
| 계산 비용 | 매우 낮음(곱셈 몇 개) | 낮음(리카티는 오프라인, 온라인은 u=−Kx) | 높음(매 스텝 QP/NLP, 6.1.8) |
| 튜닝 조정 변수 | $K_p,K_i,K_d$(2.5) | $Q,R$(4.5.2) | $N,Q,R$, 제약, 종단(6.1.5) |
| 안정성 보장 | 경험적(여유로 사후 확인, 2.4) | 이론적(LQR 여유, 4.5) | 종단 재료 없이는 없음(6.1.7) |
| 적합 상황 | 단순 루프, 제약이 느슨하거나 계산 자원이 극히 제한적 | 다변수 성능 최적화가 필요하나 제약이 여유로 흡수될 정도 | 제약을 실제로 계속 만나고, 위반 시 안전·성능이 크게 저하됨 |
고르기(견해): 제약이 느슨하면 PID로 충분하다 — 구현·튜닝이 압도적으로 쉽다. 제약이 있지만 여유(margin)로 흡수될 정도면 LQR(+안티와인드업) — 계산을 오프라인에 다 끝내 두어 온라인은 곱셈뿐이니 계산 비용이 낮다. 제약을 실제로 계속 스치고, 위반하면 대가가 크면 MPC — 매 스텝 최적화라는 비용(6.1.8)을 계산 예산이 감당해야 한다. 셋은 배타적이지 않다 — 종단 비용(6.1.4)이 보여주듯 MPC는 무한구간·무제약 극한에서 LQR로 수렴하고, 실무는 흔히 "먼저 PID로 시작 → 다변수·제약이 걸림돌이 되면 LQR·MPC로 승격"의 순서를 따른다.
6.1.11 정리 — 그리고 다음 장
- MPC = 후퇴 수평선 최적 제어: 모델로 $N$스텝 예측 → 제약 하 최적 입력열 → 첫 입력만 실행 → 재계획(6.1.2). 재최적화가 곧 피드백.
- 선형+2차+선형제약 = QP를 매 스텝(6.1.3). 제약 없고 $N\to\infty$이면 LQR, MPC = 제약 있는 유한구간 LQR(6.1.4).
- 제약(입력·상태·종단, 하드/소프트)이 존재 이유(6.1.6). 안정성·실현가능성은 종단 재료로 확보해야(6.1.7), 대가는 온라인 계산(6.1.8).
다음 6.2에서는 선형화에 의존하지 않고 비선형을 직접 다루는 비선형 제어(리아푸노프 안정성·피드백 선형화·슬라이딩 모드)를 개념 위주로 본다.
6.1.12 연습·생각해 볼 것
- 왜 MPC. 액추에이터가 $\pm5 \,\mathrm{N}$로 포화되는 시스템에서, LQR + 안티와인드업과 MPC의 차이를 "제약을 언제 고려하나" 관점에서 설명하라. (6.1.1)
- 후퇴 수평선. MPC가 $N=20$스텝을 계획하고 1스텝만 실행하는 이유는? 20스텝을 다 실행하고 다시 계획하면 무엇이 악화되나? (6.1.2)
- LQR 극한. MPC에서 제약을 모두 제거하고 $N\to\infty$로 보내면 무엇이 되나? 종단 비용
P_f를 LQR 리카티 해로 두는 이유는? (6.1.4·6.1.7) - 하드 vs 소프트. 외란으로 상태 제약을 순간 위반할 수밖에 없는 상황에서 하드 제약을 쓰면 무슨 일이 생기나? 소프트 제약(슬랙)이 어떻게 구하나? 입력 제약은 보통 어느 쪽인가? (6.1.6)
- 안정성 함정. "매 스텝 비용 최소면 폐루프도 안정"이 왜 틀린 주장인가? 안정성을 위해 무엇을 더하나? (6.1.7)
- 계산. 선형 MPC가 매 스텝 푸는 문제 유형은? 실시간 루프(3.3)에 넣을 때 가장 큰 걱정은? 작은 문제를 초고속으로 만드는 방법 하나는? (6.1.8)
- (손으로)
mpc.py로 이중적분기에 입력 제약을 주고 계단 추종을 시뮬레이션하라. 제약을 좁힐수록 MPC가 포화를 미리 존중하며 부드럽게 접근하는지, LQR(제약 무시)과 비교해 관찰하라. (검증 필요)
막히면 "예측·최적화·첫입력·재계획(후퇴 수평선), 제약 있는 유한구간 LQR, 안정성은 종단 재료로"로 돌아가라.