샘플링: 칸 간격과 에일리어싱

샘플링 정리: 나이퀴스트 주파수보다 느린 물결만 있으면 되살린다

빠른 물결은 샘플링 레이트 fs의 정수배만큼 다른 느린 물결로 둔갑했다(에일리어싱). 이제 거꾸로 물어보자. 신호에 섞인 물결이 모두 샘플링 레이트의 절반인 나이퀴스트 주파수 fs/2보다 느리면, 샘플에서 읽은 주파수는 참 주파수와 같다. 그렇다면 샘플만 가지고 칸 사이의 값까지 하나도 틀리지 않게 되살릴 수 있을까, 이웃한 두 샘플을 곧은 선으로 이어 칸 사이를 메우면 될까?

역사: 네 사람이 저마다 닿은 정리

샘플로 신호를 되살리는 정리에는 주인이 여럿이다. 1915년 영국의 수학자 휘태커(Edmund Taylor Whittaker)는 『에든버러 왕립학회지』에 낸 논문에서 숫자 표의 값 사이를 메우는 보간(값 사이 채우기) 문제를 다루었다. 같은 값들을 지나는 함수는 끝없이 많다. 휘태커는 그 가운데 물결로 나누었을 때 빠른 출렁임이 없는 함수 하나를 골랐고, 이 함수는 「으뜸 함수(cardinal function)」라는 이름으로 불린다. 지금 보면 샘플링 정리의 되살리는 식이지만, 휘태커의 관심은 숫자 표였고 증명에는 엉성한 곳이 있었다. 1920년 일본의 오구라(K. Ogura)가 이 내용을 증명한 것을 첫 증명으로 꼽는 사람도 있다.

1928년 미국 벨 연구소의 나이퀴스트(Harry Nyquist)는 「전신 전송 이론의 몇 가지 주제」에서 전혀 다른 물음을 풀었다. 주파수 폭이 정해진 전신선으로 부호를 1초에 몇 개까지 보내야 받는 사람이 하나하나 가를 수 있는가. 이 논문에 「두 배보다 촘촘히 재면 되살린다」는 문장은 없다. 그러나 폭 W인 선로로 1초에 약 2W개의 값이 오간다는 그의 셈은 같은 수 2W를 가리켰다. 같은 해 나이퀴스트는 저항기의 열잡음을 설명하는 논문도 냈는데, 이 열잡음은 「존슨–나이퀴스트 잡음」이라 불린다. 나이퀴스트 주파수의 나이퀴스트와 같은 사람의 다른 업적이다.

1933년 소련의 젊은 통신 기술자 코텔니코프(Vladimir Kotelnikov)는 소련의 한 통신 학술 회의 자료집에 실린 글 「전기 통신에서 『에테르』와 전선의 전송 용량에 관하여」에서 통신 기술의 문제로서 정리를 수학적으로 정확하게 적었다. 이 글은 서방에 오랫동안 거의 알려지지 않았고, 1999년 독일의 에두아르트 라인 재단은 코텔니코프가 정리를 처음 정확하게 적어 발표했다며 기초연구상을 주었다.

이름이 가장 널리 붙은 사람은 섀넌(Claude Shannon)이다. 1949년 1월 『무선 기술자 협회지』에 실린 「노이즈 속의 통신」은 첫 정리로 이것을 적었다. 「함수 f(t)에 W Hz보다 높은 주파수가 없으면, 1/2W초 간격의 점에서 값을 주는 것만으로 함수가 완전히 정해진다.」 바로 다음 문장은 「이것은 통신 분야에서 널리 알려진 사실이다」였다. 섀넌은 수학자들이 다른 꼴로 이미 내놓았다며 휘태커의 아들(J. M. Whittaker)의 책을 인용하고, 그 간격 1/2W를 「나이퀴스트 간격」이라 부르자고 했다. 논문 첫 쪽의 주석에 따르면 원고가 학회에 처음 들어간 날은 1940년 7월 23일이다.

같은 정리에 닿은 사람들과 그들이 풀던 문제. 숫자 표의 보간, 전신 부호를 1초에 몇 개 보내나, 통신 용량, 노이즈 속의 통신(1915–1949)
같은 정리에 닿은 사람들과 그들이 풀던 문제. 숫자 표의 보간, 전신 부호를 1초에 몇 개 보내나, 통신 용량, 노이즈 속의 통신(1915–1949)

그래서 이 정리에는 이름이 여럿이다. 영어권에서는 「나이퀴스트–섀넌 샘플링 정리」가 흔하고, 러시아에서는 「코텔니코프 정리」, 세 사람을 묶어 「휘태커–코텔니코프–섀넌 정리」라고도 한다. 누가 먼저냐의 다툼에서 남는 것은, 숫자 표, 전신선, 통신 용량이라는 서로 다른 고민이 같은 수 「두 배」에 닿았다는 한 가지다.

펄스를 세워 칸 사이를 메우기

1초에 8번 잰 신호 x(t) = cos(2π·3t) + 0.5 sin(2π·1t)를 되살려 보자. 가장 빠른 물결이 3 Hz로, 나이퀴스트 주파수 4 Hz보다 느리다. n = 0부터 8까지의 샘플은 1, −0.354, 0.5, 1.061, −1, 0.354, −0.5, −1.061, 1이다. 재지 않은 시각 t = 1/16초(샘플 0과 1의 한가운데)의 참값은 0.5740이다.

이웃한 두 샘플을 곧은 선으로 이으면 가운데 값은 두 값의 평균 (1 − 0.354)/2 = 0.3232다. 참값과 0.25쯤 어긋난다. 곧은 선은 칸 사이에서 신호가 꺾이지 않는다고 가정하는데, 3 Hz 물결은 1/8초 사이에도 크게 휜다.

섀넌이 적은 방법은 샘플 하나마다 펄스 하나를 세우는 것이다. 펄스 sinc(u) = sin(πu)/(πu)는 u = 0에서 1이고, u = ±1, ±2, …에서 0이다. 샘플 n의 자리에 x[n]배 한 펄스를 세우면, 그 펄스는 자기 자리에서 x[n]을 내고 다른 모든 샘플 자리에서는 0이라 다른 샘플을 건드리지 않는다. 그래서 펄스를 모두 더하면 샘플을 모두 지나는 곡선이 된다. t = 1/16에서 가장 가까운 두 샘플(n = 0, 1)의 펄스는 각자 자기 샘플 값에 sinc(1/2) = 0.6366을 곱한 만큼을 더하고, 그다음 이웃(n = −1, 2)은 sinc(3/2) = −0.2122를, 그다음은 sinc(5/2) = 0.1273을 곱한 만큼을 더한다. t = 1/16 양쪽으로 m개씩 더하면 다음과 같다.

양쪽 m개씩 1 2 4 16 64 256 1024
되살린 값 0.4115 0.5305 0.6607 0.5502 0.5680 0.5725 0.5736
참값 0.5740 과의 차 −0.1625 −0.0435 +0.0867 −0.0238 −0.0060 −0.0015 −0.0004

더하는 펄스가 늘수록 위아래로 오가며 참값 0.5740에 다가가므로, 샘플의 개수가 끝없이 많으면 칸 사이의 값도 틀림없이 되살아난다.

위: 샘플마다 세운 펄스 x[n]·sinc((t − nΔ)/Δ). 펄스마다 자기 샘플 자리에서 x[n], 다른 샘플 자리에서 0 이다. 아래: 펄스를 모두 더한 곡선(점선)이 참 신호(굵은 초록)와 겹친다(s2_theorem.py, figs.py)
위: 샘플마다 세운 펄스 x[n]·sinc((t − nΔ)/Δ). 펄스마다 자기 샘플 자리에서 x[n], 다른 샘플 자리에서 0 이다. 아래: 펄스를 모두 더한 곡선(점선)이 참 신호(굵은 초록)와 겹친다(s2_theorem.py, figs.py)

나이퀴스트 주파수 4 Hz를 넘는 5 Hz 물결을 같은 간격으로 재면 어떻게 될까? 펄스를 끝없이 더해도 t = 1/16에서 +0.3827이 나오는데, 5 Hz의 참값은 −0.3827이고 3 Hz 코사인의 값이 +0.3827이다. 펄스 합은 늘 나이퀴스트 주파수 아래의 물결을 그린다. 그 아래에 원래 물결이 있으면 그것이 그대로 되살아나고, 원래 물결이 나이퀴스트 주파수 위에 있으면 둔갑한 물결이 그려진다.

x(t)=∑n=−∞∞x[n]  sinc ⁣(t−nΔΔ),단, x 에 든 모든 물결이 ∣f∣<fs2,sinc(u)=sin⁡πuπu\textcolor{#1b9e77}{x}(\textcolor{#a67a63}{t}) = \sum_{\textcolor{#a67a63}{n}=-\infty}^{\infty} \textcolor{#1b9e77}{x}[\textcolor{#a67a63}{n}]\;\mathrm{sinc}\!\Big(\frac{\textcolor{#a67a63}{t} - \textcolor{#a67a63}{n}\textcolor{#697800}{\Delta}}{\textcolor{#697800}{\Delta}}\Big), \qquad \text{단, } \textcolor{#1b9e77}{x} \text{ 에 든 모든 물결이 } |\textcolor{#0078e1}{f}| < \frac{\textcolor{#697800}{f_s}}{2}, \qquad \mathrm{sinc}(u) = \frac{\sin \pi u}{\pi u}
x(t), x[n]시각 t 의 신호, 시각 nΔ 에서 잰 샘플Δ=1/fs재는 간격 (초)f신호에 든 물결의 주파수 (Hz)sinc(u)u = 0 에서 1, 다른 정수에서 0 인 펄스\begin{array}{ll} \textcolor{#1b9e77}{x}(\textcolor{#a67a63}{t}),\ \textcolor{#1b9e77}{x}[\textcolor{#a67a63}{n}] & \text{시각 } t \text{ 의 신호, 시각 } n\Delta \text{ 에서 잰 샘플} \\ \textcolor{#697800}{\Delta} = 1/\textcolor{#697800}{f_s} & \text{재는 간격 (초)} \\ \textcolor{#0078e1}{f} & \text{신호에 든 물결의 주파수 (Hz)} \\ \mathrm{sinc}(u) & \text{u = 0 에서 1, 다른 정수에서 0 인 펄스} \end{array}

신호에 든 모든 물결이 나이퀴스트 주파수 fs/2보다 느리면 샘플만으로 신호 전체가 하나로 정해지고, 펄스를 세워 더하면 되살아난다는 것을 샘플링 정리 (나이퀴스트 주파수보다 느린 물결만 있으면 샘플로 되살린다 / sampling theorem)라 한다. 이 책에서 「나이퀴스트」는 늘 나이퀴스트 주파수 fs/2를 가리키고, 『ML 입문자를 위한 동역학』에서 만나는 존슨–나이퀴스트 잡음(저항기가 열 때문에 저절로 내는 노이즈 전압)과는 사람만 같다.

정리의 조건은 「보다 느리면」인데, 물결의 주파수가 나이퀴스트 주파수와 같은 경계에서 어떻게 되는지는 아래 문제 4에서 본다.

직접 움직여 보기펄스로 되살리기새 창에서 열기 ↗

ML에서: 신경망이 듣는 소리의 위쪽 끝

음성 신경망의 입력은 샘플이다. OpenAI가 공개한 음성 인식 모델 Whisper의 코드(whisper/audio.py)는 맨 위에 SAMPLE_RATE = 16000 을 박아 두고, 어떤 녹음 파일이든 ffmpeg 프로그램으로 1초에 16000번 잰 샘플로 바꿔 넣는다. 한 번에 듣는 길이는 30초다(CHUNK_LENGTH = 30). 샘플링 레이트를 설계에서 정하면 신경망이 들을 수 있는 가장 빠른 물결도 함께 정해진다. 그 가장 빠른 물결의 주파수와, 샘플링 레이트를 바꿀 때 치르는 값은 아래 문제 6에서 셈한다.

문제 4. 하루에 두 번 재는 기온

어느 날의 기온이 15 + 5 cos(2π(t − 15)/24) °C 이다(t 는 시각, 오후 3시에 가장 덥다). 하루에 한 번 출렁이는 물결이니, 하루 두 번이면 나이퀴스트 주파수와 같다. (가) 오전 9시와 오후 9시에 재면 하루의 출렁임을 얼마로 읽는가? (나) 오전 3시와 오후 3시에 재면? (다) 하루에 두 번 출렁이는 성분 1.5 cos(2π·2(t − 15)/24) 가 더해진 날을 6시간마다(0, 6, 12, 18시) 재면 그 성분이 보이는가?

김민준 M01
김민준

하루에 한 번 출렁이니까 하루 두 번이면 두 배예요. 샘플링 정리를 맞췄으니 문제없어요.

선생님 T01
선생님

9시와 21시에 재면 몇 도가 나오죠?

김민준 M05
김민준

9시는 15 + 5 cos(−90°) = 15도, 21시는 15 + 5 cos 90° = 15도요. 둘 다 15도라 하루 종일 기온이 그대로였던 걸로 보여요. 출렁임 5도가 다 사라졌어요.

이서연 S01
이서연

(나)는 3시에 10도, 15시에 20도라 출렁임 5도를 다 읽어. 같은 하루 두 번인데 어느 시각에 재느냐에 따라 0도도 되고 5도도 돼. 6시와 18시에 재면 11.46도, 18.54도라 3.54도고.

선생님 T02
선생님

정리가 말한 조건을 다시 읽어 볼까요?

이서연 S06
이서연

「나이퀴스트 주파수보다 느리면」이에요. 어, 「같으면」은 안 들어 있네요.

선생님 T01
선생님

같을 때는 샘플이 물결의 어디를 짚죠?

이서연 S08
이서연

꼭대기를 짚을 수도, 0을 지나는 자리만 짚을 수도 있어요. 그래서 크기를 못 정하는 거예요.

김민준 M03
김민준

(다)도 그래?

이서연 S01
이서연

하루 두 번 출렁이는 성분을 하루 네 번 재면 그 성분의 주파수가 나이퀴스트 주파수와 같아. 0, 6, 12, 18시가 마침 그 성분이 0이 되는 시각이라 샘플이 11.46, 11.46, 18.54, 18.54로 그 성분이 없는 날과 똑같아.

김민준 M01
김민준

4시간마다 재 보니까 21.13도 같은 값이 나와서 보여.

김민준 M11
김민준

중간고사랑 기말고사만 보면 학기 중에 성적이 올랐다 내렸다 한 걸 하나도 모르는 거랑 같네요. 시험 두 번이 하루 두 번 잰 기온이고, 학기 중의 오르내림이 하루의 출렁임이에요. 두 번만 재면 마침 같은 점수가 나올 수도 있고요.

문제 5. 상수 1을 펄스로 되살리기

모든 샘플이 1 인 신호(상수 1)를 초당 8번 잰 것으로 보고, t = 1/16 초의 값을 펄스 합으로 되살린다. (가) 양쪽으로 m 개씩, m = 1, 2, 3, 11, 101 일 때 펄스 합은 얼마인가? (나) 곧은 선으로 이으면 얼마인가? (다) 펄스 합이 1 에 얼마나 빨리 다가가는지는 무엇이 정하는가? (위젯 3의 「문제 5 불러오기」로 m 을 바꿔 가며 확인해 보자.)

김민준 M01
김민준

상수면 아무 방법이나 1이죠. 곧은 선으로 이어도 1이고요. 펄스 합은 m = 1이면 sinc(1/2)가 두 개니까 0.6366 × 2 = 1.2732요. 어, 1이 아니네요.

선생님 T01
선생님

m을 늘려 볼래요?

김민준 M01
김민준

m = 2면 0.8488, 3이면 1.1035, 11이면 1.0289, 101이면 1.0032요. 위아래로 번갈아 넘으면서 1에 다가가요. 그런데 101개씩, 펄스 202개를 더해도 0.3%가 남아요.

이서연 S06
이서연

펄스 하나가 더하는 크기를 늘어놓아 볼게. 0.6366, 0.2122, 0.1273, 0.0909…로 줄어.

선생님 T01
선생님

어떤 규칙으로 줄죠?

이서연 S01
이서연

2/(π × 홀수)요. 1/m처럼밖에 안 줄어요. 부호가 번갈아서 서로 지우니까 합은 모이긴 하는데…

김민준 M03
김민준

남는 차이는 얼마나 빨리 줄어?

이서연 S01
이서연

그것도 1/m처럼. 남는 차이는 1/(π × m)쯤이라 101개씩이면 1/(π × 101) ≈ 0.0032로 맞아.

선생님 T13
선생님

그래요. 펄스의 꼬리가 1/m로 천천히 주는 건 펄스의 스펙트럼이 나이퀴스트 주파수에서 칼로 자른 듯 끊기기 때문이에요. 끊긴 데가 있으면 계수가 1/k로 느리게 준다는 것을 도는 화살표로 곡선을 그릴 때 보았죠. 여기서는 시간과 주파수가 자리를 바꿔, 주파수 쪽이 끊기니 시간 쪽 펄스의 꼬리가 1/m로 느리게 줄어요. 그래서 실제로 되살리는 프로그램은 펄스를 그대로 쓰지 않고 꼬리를 부드럽게 줄인 펄스를 써요.

이서연 S11
이서연

해석학 시간에 1 − 1/3 + 1/5 − …가 π/4로 모이긴 하는데 엄청 느리게 모인다고 배웠어. 그 급수가 여기 숨어 있었네.

김민준 M07
김민준

곧은 선이 상수에서는 펄스보다 낫고, 3 Hz 물결에서는 훨씬 못한 거네요. 잘 맞는 방법이 신호마다 다르다는 걸 과제 채점표에도 적어 놔야겠어요.

문제 6. Whisper 가 듣는 소리

Whisper 는 모든 녹음을 1초에 16000번 잰 샘플로 바꿔 30초씩 듣는다. 유선 전화의 디지털 음성은 1초에 8000번 잰다. (가) 각각 담을 수 있는 가장 빠른 물결은 몇 Hz 아래인가? 30초면 샘플이 몇 개인가? (나) 1초에 48000번 잰 녹음에서 세 칸마다 하나씩만 골라 16000번으로 만들면, 녹음에 있던 10000 Hz, 15000 Hz 물결은 어디로 가는가? (다) 12000 Hz 까지 담으려면 30초에 샘플이 몇 개보다 많아야 하는가?

김민준 M01
김민준

(가)는 16000번이면 16000 Hz까지요. 30초면 샘플 480000개고, 전화는 8000 Hz까지에 240000개요.

선생님 T01
선생님

1초에 16000번 재는데 16000 Hz 물결을 재면 샘플이 어떻게 나오죠?

김민준 M04
김민준

잴 때마다 한 바퀴를 다 돌아서 늘 같은 값이에요. 멈춘 바퀴처럼 0 Hz로 보여요. 절반이었죠. Whisper는 8000 Hz 아래, 전화는 4000 Hz 아래요.

이서연 S01
이서연

(나)는 셈하면 10000 − 16000 = −6000이라 6000 Hz로, 15000은 −1000이라 1000 Hz로 보여. 원래 녹음에 없던 낮은 소리가 생기는 거야. 사람 목소리가 있는 낮은 쪽에 끼어들어.

선생님 T02
선생님

그럼 Whisper 코드는 세 칸마다 하나씩 고를까요?

이서연 S08
이서연

아니겠죠. 코드가 ffmpeg에 넘기는 건 「16000으로 바꿔라」는 주문뿐이고, 바꾸는 일은 ffmpeg가 해요.

선생님 T01
선생님

그럼 ffmpeg는 고르기 전에 무엇을 해야 할까요?

이서연 S01
이서연

(나)의 셈을 보면 그냥 고르면 안 되니까, 고르기 전에 8000 Hz 위를 걸러야 할 것 같아요.

선생님 T01
선생님

(다)는 민준 학생이 해 볼래요?

김민준 M01
김민준

이번엔 절반을 안 잊을게요. 12000 Hz의 두 배가 24000이니까 1초에 24000번보다 많이, 30초면 720000개보다 많아야 해요. 지금보다 1.5배예요.

김민준 M07
김민준

문제 4(하루에 두 번 재는 기온)에서 기온을 몇 시간마다 재야 하는지 묻던 거랑 같아요. 하루가 30초로 바뀌었을 뿐이에요.