REMI Lab강의 노트

Wireless Embedded Systems E02

2장 복습: 복소수와 이산 신호

실수 표본과 복소 표본

SDR은 왜 표본마다 실수 하나가 아니라 I와 Q 두 값을 넘겨줄까?

ADC 하나로 받은 실수 표본에서는 +f+f와 −f-f가 같은 수열이다. cos⁡(2πfn/fs)=cos⁡(−2πfn/fs)\cos(2\pi fn/f_s)=\cos(-2\pi fn/f_s)이기 때문이다. 그래서 DFT의 선이 ±f\pm f 두 칸에 절반씩 서고, X[N−k]=X[k]‾X[N-k]=\overline{X[k]}라서 −fs/2…0-f_s/2\ldots0은 0…fs/20\ldots f_s/2를 비춘 거울상이다. 표본화율 fsf_s로 구별하는 범위는 0≤f≤fs/20\le f\le f_s/2, 폭 fs/2f_s/2이다.

ADC 두 개로 I와 Q를 함께 받은 복소 표본 z[n]=I[n]+jQ[n]z[n]=I[n]+jQ[n]에서는 ej2πfn/fse^{j2\pi fn/f_s}와 e−j2πfn/fse^{-j2\pi fn/f_s}가 다른 수열이다. 도는 방향이 반대이기 때문이다. 선은 ff 한 칸에만 서고, −fs/2≤f<fs/2-f_s/2\le f<f_s/2 전체, 폭 fsf_s를 구별한다. 같은 fsf_s에서 구별하는 대역폭이 두 배이다.

어느 쪽이든 ff와 f+mfsf+mf_s는 같은 표본을 만든다. 복소 표본이 더 구별하는 것은 부호뿐이다. ∣f∣=fs/2|f|=f_s/2에서는 복소 표본도 ejπn=e−jπn=(−1)ne^{j\pi n}=e^{-j\pi n}=(-1)^n이 되어 +fs/2+f_s/2와 −fs/2-f_s/2를 가르지 못한다. 구간의 한쪽 끝만 들어가는 까닭이다.

아래 그림은 실수 cos 표본을 서로 반대로 도는 두 벡터의 합으로 그린다. ▶로 한 단계씩 넘기며 먼저 두 허수 성분이 상쇄되는 것을 보고, 그다음 그 합이 시간축에 표본으로 찍히는 것을 본다. 복소 톤으로 바꾸어 벡터 하나의 회전과 마지막 DFT의 선을 비교한다.

합성 데이터이다. fₛ = 1 MHz, N = 20이고 f는 DFT 칸 간격 50 kHz의 정수배이다. 실수 cos는 길이 ½인 두 반대 회전의 합, 복소 톤은 길이 1인 회전 하나이다. 마지막 표본에서 그리는 스펙트럼의 세로축은 |X[k]|/N이다. 아래 numpy 예제의 원래 DFT 크기는 이 값의 N배이다. 직류와 Nyquist 주파수에서는 실수 신호의 두 선이 같은 칸에 겹쳐 높이가 1이 된다.

해 보기

  1. 실수 cos의 두 번째 표본을 본다.
    관찰

    두 벡터의 세로 성분은 반대이고, 더한 벡터는 실수축 위에 놓인다.

  2. 실수 cos를 끝까지 받는다.
    관찰

    ±200 kHz에 높이 ½인 선이 하나씩 선다. 부호를 바꾸어도 표본과 두 선은 같다.

  3. 복소 톤을 −200 kHz로 바꿔 끝까지 받는다.
    관찰

    벡터 하나가 시계 방향으로 돈다. 선은 −200 kHz에 높이 1로 하나만 선다.

같은 계산을 numpy로 하면 다음과 같다. fftshift는 칸을 −fs/2-f_s/2부터 늘어놓는다.

fs, N = 1e6, 20
n = np.arange(N)
x = np.cos(2 * np.pi * 200e3 * n / fs)           # 실수 표본
z = np.exp(2j * np.pi * 200e3 * n / fs)          # 복소 표본 I + jQ
f = np.fft.fftshift(np.fft.fftfreq(N, 1 / fs))   # −500 kHz … 450 kHz
X = np.fft.fftshift(np.fft.fft(x))               # ±200 kHz에 10씩
Z = np.fft.fftshift(np.fft.fft(z))               # +200 kHz에 20 하나

실수 표본이 +f+f와 −f-f를 가르지 못한다는 이 성질이, 수신기가 I와 Q 두 값을 함께 받는 까닭이다. 수신기 안에서 I와 Q가 어떻게 만들어지는지는 4장 '주파수 변환' 절에서 본다.