circuitikz는 2007년, 한 대학 교원이 겪던 아주 현실적인 문제에서 태어난 LaTeX 패키지입니다. 당시 밀라노 공과대학의 연구 조교였던 Massimo Redaelli가 연습 문제와 시험지에 넣을 회로도를 조판할 도구가 필요해서 쓰기 시작한 것입니다. 문법은 놀랄 만큼 솔직합니다. 배선을 하나의 경로로 쓰고 그 중간에 to[R, l=$R_1$]을 끼워 넣으면 저항이 하나 놓입니다. 그런데 이 페이지에서 가장 길게 다루는 것은 문법이 아닙니다. 저항 기호는 나라마다 다르다는 사실, 곧 지그재그냐 직사각형이냐 하는 문제와, circuitikz의 기본값이 아마 여러분의 예상과 다르다는 이야기입니다.
\usepackage{circuitikz}는 실제로 무엇을 읽어 들이는가
\usepackage{circuitikz} 한 줄이면 TikZ가 자동으로 읽히고, 여기에 TikZ 라이브러리 calc, arrows.meta, bending, fpu가 따라옵니다. 즉 circuitikz는 TikZ의 대체품이 아니라, TikZ 위에 전기 기호의 어휘를 덧붙인 것입니다. 경로와 좌표의 사고방식은 TikZ 페이지에 맡기고, 여기서 붙잡아야 할 것은 “circuitikz의 명령은 결국 전부 TikZ 명령이다”라는 한 가지입니다. pdfLaTeX, LuaLaTeX, XeLaTeX에서는 그대로 동작하며, pLaTeX나 upLaTeX처럼 DVI를 거칠 때만 TikZ와 똑같이 드라이버(보통 dvipdfmx)를 클래스 옵션으로 지정합니다.
\documentclass{article} % one schematic only: \documentclass[border=3pt]{standalone}
\usepackage{circuitikz}
\begin{document}
\begin{circuitikz}
\draw (0,0) to[R, l=$R_1$] (2,0);
\end{circuitikz}
\end{document}“TikZ와 같다”는 말은 여기서 비유가 아닙니다. circuitikz.sty 안에서 circuitikz 환경은 글자 그대로 한 줄, \newenvironment{circuitikz}{\begin{tikzpicture}}{\end{tikzpicture}}로 정의되어 있습니다. 속이 빈 별칭인 셈입니다. 그래서 \tikz \draw (0,0) to[R=$R_1$] (2,0);처럼 tikzpicture 쪽에서 써도 똑같은 그림이 나옵니다. 그리고 이 사실은 실무에서 제대로 물어뜯습니다. TikZ의 \tikzexternalize(각 그림을 개별 PDF로 캐시하는 장치)는 모든 그림이 \end{tikzpicture}로 끝난다고 전제하므로, circuitikz 환경을 쓰는 문서는 ! Emergency stop.으로 멈춥니다. 매뉴얼의 답은 아주 직설적입니다. circuitikz를 전부 tikzpicture로 바꾸라, 어차피 거의 같은 것이니. 회로도 한 장만 이미지로 내보내고 싶다면 standalone 클래스가 간편합니다.
to[R, l=$R_1$] 읽는 법: 배선 중간에 부품을 떨어뜨리기
관용구 하나로 circuitikz의 거의 전부를 설명할 수 있습니다. TikZ의 경로 연산 to의 대괄호에 부품 키를 쓰면, 두 점을 잇는 배선 중간에 그 부품 하나가 삽입됩니다. \draw (0,0) to[R, l=$R_1$] (2,0);는 “(0,0)에서 (2,0)으로 가되 저항 R₁을 거친다”로 읽습니다. 여기서 l=은 라벨 키인데, to[R=$R_1$]도 결과가 같으며 이는 to[R, l=$R_1$]의 축약형입니다. 두 표기를 나란히 보고 혼란스러워하는 사람이 많지만, 완전히 같은 것입니다. 긴 형태는 나중에 i=나 v=를 덧붙이기 쉬우므로, 익숙해지면 to[R, l=…]을 기본으로 두는 편이 편합니다.
\begin{circuitikz}
\draw (0,0) to[R, l=$R_1$] (2,0) % long form
to[C=$C_1$] (2,-2) % shorthand for the same thing
to[short, -*] (0,-2); % bare wire, connection dot at the end
\end{circuitikz}결과는 ㄷ자 모양의 배선입니다. 부품 없이 도선만 필요한 곳에는 to[short]를 씁니다. 이는 “아무것도 아닌 두 단자 부품”으로, 배선을 계속 to의 연쇄로 쓸 수 있게 해 주는 도구입니다. 끝의 -*는 TikZ의 화살촉 표기를 응용해 경로 끝점에 접속점(검은 점)을 찍습니다. 양끝에 찍으려면 *-*입니다. 좌표는 TikZ 그대로여서 절대 좌표 (2,0)(기본 단위 센티미터)도, 상대 좌표 ++(2,0)(현재 위치에서 오른쪽으로 2 cm)도 됩니다. 직각으로 꺾을 때는 (a -| b)(a의 x 좌표와 b의 y 좌표가 만나는 점)나 경로 연산자 -|가 유용합니다. 부품의 방향은 경로가 진행하는 방향에 자동으로 맞으므로, 세로로 그으면 기호도 세로가 됩니다.
부품 키를 잘못 입력했을 때의 오류는 처음 보면 circuitikz와 잘 연결되지 않는 모습으로 나옵니다. to[resistorX]라고 쓰면 ! Package pgfkeys Error: I do not know the key '/tikz/resistorX' and I am going to ignore it.가 뜹니다. 부품 키의 정체가 TikZ 키이므로, 모르는 키라며 불평하는 쪽은 pgfkeys입니다. 메시지 안에 입력한 이름이 그대로 인용되어 있으니, 그것을 실마리로 철자를 확인하면 됩니다.
두 단자 부품의 부품 키: R, C, L, D부터 전원까지
to[…]에 놓을 수 있는 것은 단자가 두 개인 부품, 곧 바이폴(bipole)입니다. 대부분의 키는 기억하기 쉬운 머리글자(저항 R, 커패시터 C, 인덕터 L, 다이오드 D)이며, 전원처럼 종류가 많은 계열에는 vsource, isource 같은 풀어 쓴 별칭도 마련되어 있습니다. 짧은 형태는 입력이 빠르고, 풀어 쓴 형태는 몇 달 뒤 코드를 다시 읽을 때 친절합니다. 여럿이 함께 쓰는 문서라면 풀어 쓴 이름 쪽으로 맞춰 두는 편이 나중에 편합니다.
| 부품 키 | 부품 | 표기 |
|---|---|---|
R | 저항 | to[R, l=$R_1$] |
C | 커패시터 | to[C, l=$C_1$] |
L | 인덕터(코일) | to[L, l=$L_1$] |
D | 다이오드. leD(LED), zD(제너) 등도 같은 계열 | to[D] |
V / vsource | 범용 전압원 | to[V, l=$U_q$] |
I / isource | 범용 전류원 | to[I, l=$I_0$] |
sV | 사인파 전압원(교류) | to[sV, l=$v_s$] |
battery1 / battery | 전지(단일 셀 / 여러 셀) | to[battery1] |
short / open | 그냥 도선 / 개방(양끝 사이에 아무것도 없음) | to[short] |
closing switch / opening switch | 스위치. 닫히는 방향과 열리는 방향의 기호가 다름 | to[closing switch] |
전원만큼은 잠깐 생각해 볼 값어치가 있습니다. V는 원으로 그려지는 범용 전압원, sV는 그 안에 사인파를 넣은 교류 전원, battery1은 긴 선과 짧은 선이라는 전지 고유의 기호입니다. 직류 공급을 원으로 그릴지 전지 기호로 그릴지는 분야의 관례 문제이므로, 독자가 이미 갖고 있는 교과서에 맞추는 편이 무난합니다. 스위치가 closing switch와 opening switch로 나뉘는 것도 같은 이유입니다. 기호는 지금 열려 있는지가 아니라, 그 스위치가 어느 쪽으로 움직이는 종류인지를 기록합니다.
american과 european: 저항은 지그재그인가 직사각형인가
저항은 미국식에서는 지그재그로, IEC(유럽식)에서는 속이 빈 직사각형으로 그립니다. 같은 부품, 같은 회로인데 그림이 다릅니다. circuitikz는 이 차이를 패키지 옵션으로 드러냅니다. \usepackage[american]{circuitikz}와 \usepackage[european]{circuitikz}는 계열 전체를 한꺼번에 바꿉니다. 저항뿐 아니라 인덕터, 논리 게이트, 전압과 전류 화살표까지 함께입니다. 독자가 익숙하지 않은 기호로 그린 회로도는 실제로 읽기 어려우므로, 이것은 그리기 시작하기 전에 정해 두어야 할 설정입니다.
여기서부터가 본론입니다. 아무것도 지정하지 않았을 때의 기본값은 어느 한쪽이 아니라 혼합입니다. circuitikz.sty의 기본 옵션 목록을 보면 저항과 논리 게이트는 미국식(americanresistors, americanports), 전압과 전류 화살표는 유럽식(europeanvoltages, europeancurrents), 인덕터는 아예 제3의 방식인 cuteinductors로 되어 있습니다. 그 결과, 설정하지 않은 회로도는 미국 독자에게도 유럽 독자에게도 “내 교과서와는 조금 다른” 그림이 됩니다. 게다가 차이가 눈에 띕니다. 유럽식 전압은 부품을 가로지르는 굽은 화살표이고, 미국식 전압은 양단에 놓인 +와 −여서 완전히 다른 그림입니다.
설정할 자리는 세 곳이고, 여기에 작은 함정이 있습니다. 패키지 옵션은 공백 없이(\usepackage[europeanresistors]{circuitikz}), 환경 옵션과 \ctikzset은 공백을 넣어(\begin{circuitikz}[european resistors]) 씁니다. 이름이 딱 한 글자 다릅니다. 더 세밀하게 지정하고 싶으면 키를 씁니다. \ctikzset{resistor=european}, \ctikzset{voltage=american} 같은 식입니다. 깔끔한 분담은 문서 전체를 하나로 통일할 때는 프리앰블에서 [european]이나 [american]을 한 번 주고, 특정 그림만 예외로 둘 때 환경 옵션을 쓰는 것입니다.
% whole document in IEC style (note: no space in package options)
\usepackage[european]{circuitikz}
% ... but this one figure keeps the American zigzag
\begin{circuitikz}[american resistors]
\draw (0,0) to[R, l=$R_1$] (2,0);
\end{circuitikz}라벨 l=, 전압 v=, 전류 i=, 주석 a=
부품에 글자를 붙이는 키는 넷이고, 역할이 깔끔하게 나뉩니다. l=은 이름(R₁ 등)이고, a=는 주석으로 이름의 반대편에 또 한 단의 정보(대개 실제 값)를 둡니다. v=는 부품 양단에 걸리는 전압을, i=는 흐르는 전류를 각각 방향을 나타내는 화살표와 함께 그립니다. 이들 키는 모두 끝에 밑줄을 붙이면 반대쪽·반대 방향이 됩니다. l_=은 라벨을 선의 반대쪽으로 옮기고, i_=과 v_=은 전류와 전압 화살표를 뒤집습니다. 위 첨자 형태인 l^=도 있습니다. 배선이 가로냐 세로냐에 따라 “위/아래”의 뜻이 바뀌므로, l과 l_의 선택은 외워야 할 규칙이 아니라 마지막에 눈으로 정하는 일이라고 생각하면 편합니다.
\begin{circuitikz}
\draw (0,0) to[V, l=$U_q$] (0,2)
to[short] (2,2)
to[R, l=$R_1$, a=$4.7\,\mathrm{k}\Omega$, i=$i_1$, v=$u_1$] (2,0)
to[short] (0,0);
\end{circuitikz}완성되는 것은 한 바퀴의 폐회로입니다. 왼쪽 변에 전압원 Uq, 위와 아래 변은 to[short]의 그냥 도선, 오른쪽 변의 저항에는 이름 R₁과 실제 값 4.7 kΩ이 선의 양쪽에 나뉘어 붙고, 여기에 전류 i₁과 전압 u₁의 화살표가 더해집니다. 여기서 앞 절이 효력을 발휘합니다. v=$u_1$이 어떻게 그려지는지는 지금 american voltages인지 european voltages인지에 전적으로 달려 있습니다. 아무것도 지정하지 않으면 기본값이 유럽식이므로, 부품을 가로지르는 굽은 화살표가 나옵니다.
값을 단위와 함께 쓰고 싶다면 \usepackage[siunitx]{circuitikz}로 읽어 들입니다. 그러면 l=5<\ohm>이나 a=3<\micro\farad> 같은 circuitikz 고유의 숫자<\단위> 표기를 쓸 수 있고, 나머지는 siunitx가 맡아 “5 Ω”, “3 µF”로 올바르게 조판합니다. 숫자와 단위 사이의 공백이나 µ의 자형을 직접 신경 쓰지 않아도 되므로, 실제 값을 적어 넣는 회로도라면 처음부터 켜 둘 값어치가 있습니다.
트랜지스터, 오피앰프, 접지는 \node[…]로 놓습니다
단자가 셋 이상인 부품은 to[…]에 들어가지 않습니다. to는 “두 점 사이”를 채우는 연산이라 세 번째 다리가 나올 자리가 없기 때문입니다. 트랜지스터, 오피앰프, 접지 같은 부품은 대신 TikZ의 노드로 \node[부품명] (이름) at (좌표) {}; 형태로 놓습니다. 내용이 비어 있어도 중괄호 {}는 반드시 필요하며, 이를 빠뜨리는 것은 초심자가 흔히 막히는 지점입니다. 배치된 노드는 단자마다 앵커를 가지며, 노드이름.단자이름 형태((oa.out))로 참조해 배선을 연결합니다.
- 접지 —
\node[ground] at (0,0) {};. 전원 레일에는 전용 기호가 있습니다. 양극 쪽은vcc, 음극 쪽은vee입니다. - MOSFET —
\node[nmos] (q1) {};,\node[pmos] {};. 바이폴라 트랜지스터는npn/pnp입니다. 단자는q1.gate,q1.drain,q1.source등으로 참조합니다. - 오피앰프 —
\node[op amp] (oa) {};이며 단자는oa.+(비반전 입력),oa.-(반전 입력),oa.out(출력)입니다. - 경로 중간에 놓기 — 좌표 바로 뒤에
node[ground]{}라고 쓰면 배선을 끊지 않고 노드를 끼워 넣을 수 있습니다.
\begin{circuitikz}
\draw (0,0) node[op amp] (oa) {};
\draw (oa.-) to[R, l=$R_f$] ++(0,2) -| (oa.out); % feedback around the amp
\draw (oa.+) to[short] ++(-1,0) node[ground] {};
\end{circuitikz}앵커의 진가가 드러나는 장면입니다. 오피앰프를 하나 놓고, 반전 입력 oa.-에서 위로 귀환 저항 R_f를 끌어올린 뒤 -|로 오른쪽으로 꺾어 출력 oa.out에 떨어뜨리면 귀환 루프가 닫힙니다. 좌표를 하나도 손으로 세지 않았다는 점에 주목하십시오. 오피앰프 기호의 크기가 바뀌어도 앵커로 쓴 배선은 그대로 따라갑니다. 비반전 입력 oa.+는 왼쪽으로 조금 끌어내 접지했습니다.
\ctikzset으로 그림 전체를 맞추고 TikZ와 섞기
회로도 전체의 모양을 한꺼번에 정하는 것이 \ctikzset{…}입니다. TikZ의 \tikzset에 대응하는 circuitikz 쪽 설정 명령으로, 프리앰블에도 그림 중간에도 쓸 수 있습니다. 실무에서 가장 잘 듣는 것은 \ctikzset{bipoles/length=1cm}, 곧 모든 두 단자 부품의 길이를 맞추는 지정입니다. 기본값 그대로면 부품마다 그려지는 길이가 조금씩 달라 배선 간격이 들쭉날쭉해 보이는데, 길이를 고정하는 것만으로 그림이 단번에 정돈되곤 합니다. 앞 절의 resistor=american이나 voltage=european도 같은 \ctikzset 일가입니다.
마지막으로 처음 이야기로 돌아갑니다. circuitikz는 TikZ 위에 놓여 있습니다. 좌표 계산의 calc, 상대 배치의 positioning, 설명 글용 일반 \node, 색·선 종류·스타일 정의까지, TikZ로 할 수 있는 일은 그대로 쓸 수 있습니다. 회로가 복잡할수록 레이아웃은 TikZ 방식으로 짜고 부품만 circuitikz에 맡기는 분담이 잘 통합니다. 그림이 늘어 컴파일이 무거워지면 TikZ와 마찬가지로 external 라이브러리로 캐시할 수 있는데, 앞서 말한 대로 circuitikz 환경을 tikzpicture로 고쳐 쓰는 것을 잊지 마십시오.