27.1.2.3. 파이썬 기호 연산 라이브러리(SymPy)를 활용한 C++ 야코비안 코드 자동 생성 원리

27.1.2.3. 파이썬 기호 연산 라이브러리(SymPy)를 활용한 C++ 야코비안 코드 자동 생성 원리

앞선 절들에서 강조했듯, EKF의 상태 공간이 24차원에 달하고(심지어 멀티로터의 하위 상태까지 합치면 그 이상) 비선형 삼각함수와 쿼터니언이 뒤얽혀 있는 상황에서, 상태 전이 야코비안(F)이나 관측 야코비안(H)을 사람의 손으로 미분하여 C++ 코드로 타이핑하는 것은 ’자살 행위’나 마찬가지다.

과거 초창기 비행 제어기 개발 시절에는 대학원생들이 화이트보드에 수식을 쓰며 며칠 밤을 새워 코드를 짰고, 부호(+, -) 하나가 틀려 드론이 추락하는 일이 비일비재했다. 이를 근본적으로 해결하기 위해 도입된 현대 PX4 ECL의 혁신적인 파이프라인이 바로 파이썬 SymPy 기반의 C++ 자동 코드 생성(Auto-generation) 툴체인이다.

본 절에서는 그 마법 같은 변환 과정의 설계 원리를 단계별로 파헤쳐 본다.


1. 기호 연산(Symbolic Computation) 철학과 SymPy

일반적인 컴퓨터 프로그램(예: C, Java)은 a = 5, b = 2 처럼 메모리에 할당된 ’숫자’들을 연산한다. 하지만 기호 연산(Symbolic Computation) 패러다임은 x, y, \theta, \Delta t 처럼 값이 정해지지 않은 대수학 ‘문자(Symbol)’ 자체를 조작하고 다항식을 전개하거나 미적분학적 융합을 수행한다.

파이썬의 SymPy는 이러한 기호 연산을 완벽하게 지원하는 오픈소스 라이브러리다. PX4 개발팀은 src/lib/ecl/EKF/python/ 디렉터리에 EKF의 모든 물리 법칙을 SymPy 언어로 정의해 놓은 설계도 스크립트들을 구축해 두었다.


2. 야코비안 코드 자동 생성의 4단계 파이프라인

야코비안 행렬이 도출되어 .cpp 소스 코드로 떨어지기까지의 과정은 대략 다음과 같은 4단계의 자동화 과정을 거친다.

2.1 단계: 심볼(Symbol) 및 상태 벡터 선언

가장 먼저 시간 성분(dt), 기체의 상태 변수 24개, 센서 입력 노이즈 등의 모든 물리적 인자를 추상적인 기호로 선언한다.

# python 스크립트 의사코드 (e.g. ekf_derivation.py)
import sympy as sp

# 심볼 정의
dt = sp.Symbol('dt')
q0, q1, q2, q3 = sp.symbols('q0 q1 q2 q3')  # 쿼터니언 변수
vx, vy, vz = sp.symbols('vx vy vz')        # 속도 변수
# ... 총 24개의 상태 심볼 생성

2.2 단계: 비선형 물리 방정식(Dynamics)의 기하학적 전개

선언된 문자들을 가지고 앞 절에서 다룬 기구학적(Kinematic) 운동 방정식을 파이썬 코드로 서술한다. 회전 행렬을 곱하고, 자이로스코프 바이어스를 빼고, 속도를 적분하는 등의 과정이 순수 수학 공식 형태로 맵핑된다.

# 비선형 방정식 f(x, u)의 심볼릭 정의
# 쿼터니언을 이용한 회전 행렬 R 도출 (문자 단위의 행렬식 생성)
R = calculate_dcm_from_quaternion(q0, q1, q2, q3)

# 속도 업데이트 공식: 다음 순간의 속도 = 현재 속도 + (회전된 가속도 - 중력) * dt
v_next = v_current + (R * accel_measured - gravity) * dt

2.3 단계: .jacobian() 함수를 통한 편미분 폭격

방정식 f 가 거대한 기호 다항식으로 완성되면, 개발자는 단순히 SymPy가 제공하는 .jacobian() 메서드를 호출한다. 컴퓨터 프로세서가 체인 룰(Chain Rule)을 적용하여 24차원에 대한 576개의 편미분 결과를 순식간에 토해낸다.

# 상태 벡터 state_vec = [q0..q3, vx..vz, ...]
# 야코비안 행렬 F 산출 (단 한 줄의 코드로 576개의 다항식 미분 완료)
F_matrix = f_equations.jacobian(state_vec)

2.4 단계: CSE(공통 부분식 제거) 최적화 및 C++ 방출

마지막 단계가 가장 중요하다. 앞서 얻은 576개의 미분 결과식들 속에는 중복되는 삼각함수 연산(예: \sin(\theta)\cos(\phi))이 무수히 많다. 이를 그대로 마이크로컨트롤러(MCU)에 밀어 넣으면 연산 부하로 시스템이 다운된다.

SymPy는 CSE (Common Subexpression Elimination, 공통 부분식 제거) 알고리즘을 제공한다. 중복되는 연산을 tmp1, tmp2 같은 임시 변수로 묶어내어 전체 연산량을 획기적으로 압축한다. 그 후, 최종 압축된 수식 트리를 ccode 스위치를 통해 문법상 완벽한 C++ 소스 코드 문자열로 번역해 낸다.

# C++ 코드 방출 (Export)
cpp_code = sp.ccode(F_matrix_optimized)
with open('ekf_jacobian.cpp', 'w') as f:
    f.write(cpp_code)

3. 요약: 수학과 엔지니어링의 완벽한 분업

이 야코비안 자동 생성 체계의 도입은 오픈소스 자율비행 제어기 역사에 큰 획을 그었다.

  1. 무오류성(Error-free): 사람의 타이핑 실수나 편미분 스위칭 오류가 원천 개입할 수 없다. 코드가 생성되었다는 것은 수학적으로 100\% 완벽한 미분 행렬이라는 보증 수표와 같다.
  2. 유지보수 극대화: 만약 드론의 기체 모델을 바꾸거나 지구 자기장 모델 방정식을 수정해야 할 일이 생기면, 유지보수자는 1만 줄짜리 C++ EKF 소스 코드를 건드리는 대신, 100줄짜리 파이썬 스크립트 수학 공식만 수정(Tweak)한 뒤 엔터 키 하나만 누르면 된다. 수정된 공식이 반영된 수천 줄의 for 문 C++ 코드는 스크립트가 밤새 다시 짜서 .cpp 파일로 대령하기 때문이다.

이렇듯 PX4 ECL 아키텍처는 EKF라는 난해한 비선형 수학 이론을, SymPy라는 현대적인 파이썬 툴체인을 통해 가공함으로써, 복잡성을 숨기고(Abstractions) 확장성을 쟁취해 낸 모범적인 엔지니어링 사례로 평가받는다.