간단한 OFDM 체험기
순번1 : 다중경로 페이딩과 극복기술
순번2 : 대역확산스펙트럼 기술들(DSSS, FHSS)
순번1 에서 언급한 WIFI, 5G 등 기술의 기초가 되는 OFDM 을 이어서 더 살펴보겠습니다.
이번에는 간단히 OFDM을 구현한 소스코드를 가지고, 이 기술에 대해 좀 더 (몸으로 체험하고) 이해하는 포스팅을 쓰려고 해요!
아래 소개될 소스코드<참고자료1>는 짧되 핵심기술을 두루 잘 구현하고 베이직하면서 좋은 예제임은 틀림없습니다. 이 자리를 빌어 아래 배움자료를 공개해주신 저자에게 깊은 감사에 마음을 전합니다. 꾸벅!
그런데 결과적으로 말씀드리면,,, 원문에 설명이 충분히 자세히 되어있어, 여기서는 핵심적면서 애매한 부분을 연결짓고 부연하고, 주요 다이어그램을 요약하는 식으로 글을 쓸수 밖에 없는 점 미리 알려드리며 시작하겠습니다. 좋게 보면, 놓치지 말아야할 코어를 먹기좋게 발라드린다고 할까요...
OFDM(Orthogonal Frequency Division Multiplexing)은 LTE, WiMAX, DVB-T 및 DAB와 같은 광범위한 무선 전송 시스템에 적용되는 다중 반송파 시스템입니다.
다중반송파의 이점은 첫째, 긴 심볼 지속시간은 다중경로페이딩에 강합니다. 둘째, 주파수 선택성으로 인해 딥 페이드 발생 시 일부 부반송파의 데이터만 손실됩니다. 셋째, 다수의 부반송파를 다중 가입자에 나누어 할당하여 리소스를 쉽게 제공할 수 있습니다.

위 다이어그램의 각 블록을 살펴보면 낯선 프로세스가 보이고 의문이 들겁니다.
도대체 CP(cyclic prefix)는 뭐고 왜 하나요??
심볼의 끝을 반복하여, 주파수 선택적 다중 경로 채널의 선형 컨볼루션(linear convolution)을 원형 컨볼루션 (circular convolution) 으로 모델링할 수 있으며, 이 접근 방식으로 채널 추정 및 이퀄라이제이션과 같은 프로세싱을 수월하게 합니다.
이 말은 <참고자료5>와 아래 예제를 보면 감이 조금 옵니다.
<결과> y_circular = [ 3.3 3. 3.5 4.8 6.1 7.4 8.7 10. ]
Y_inv = [ 3.3 3. 3.5 4.8 6.1 7.4 8.7 10. ]
즉 시간 영역에서 두 신호의 원형 컨벌루션은 주파수 영역에서 두 신호의 DFT곱과 같음을 보여줍니다.
따라서 OFDM에서 심볼의 끝을 가져와 앞에 추가함(CP)으로써 심볼은 원형 컨벌루션 계산과 같게 되고 single-tap equalizer를 사용할 수 있는 것입니다.
또 CP는 후속 OFDM 심볼 간 ISI를 막는 이점도 있습니다.
CP는 채널 임펄스 응답(h) 보다 긴 경우( N ≥ L+P-1 , N은 심벌 길이) 올바르게 동작(선형=원형 컨벌루션)합니다.
그럼, 이제 다중경로 무선채널을 임의의 주파수 응답 H 으로 어떻게 설계할까요?

보다시피 2,3탭의 주파수 응답은 주파수 선택적이고, 다중경로 채널 특성을 보입니다. ok 굳! 여기서는 2탭을 선택합니다.
저는 H_exact 가 제일 헷갈리고 헤맸는데,,, ㅠ.ㅠ
이것은 무선채널의 임펄스 응답 h를 DFT하여 주파수응답을 표시한 것입니다.
결국 나중에 파일럿신호로 부터 얻은 추정값(H_est)을 H_exact에 나누어 채널응답 등화기를 수행할 것입니다.
그럼 이제 주요 프로세스를 요약해서 살펴보면,,,
먼저 OFDM 송신 심벌을 만들기 위해,
총 부반송파 수 k=64, pilot 9개, data 55 개를 아래와 같이 가지는 allCarriers 만들어 시작합니다.

랜덤 비트를 생성하고, 4bit묶음을 복소수값의 성상도 기호 16-QAM로 아래처럼 매핑된 값으로 data 부반송파에 할당합니다.

파일럿 신호도 pilot 부반송파에 할당하여 → OFDM_data : [64]
IDFT 연산을 통해 시간 영역으로 변환하여 → OFDM_time : [64]
CP를 추가하여 → OFDM_withCP : [80] 만듭니다.
이제 중요한 다음 각 단계로,,,
무선채널응답을 구하기 위해 아래처럼 컨벌루션을 하고,
여기서 channelResponse : 임펄스 응답 [2]

수신신호에서 CP를 제거한 후 16-QAM을 복조하고,
복조신호의 복소수 파일럿에서 채널응답 추정치를 계산하고,
여기서 (미리정해서 이미 알고 있는) pilotValue = 3+3j

복조신호에 보간한 추정값들을 나누어 이퀄라이즈를 수행하면,
그 다음 파일럿 캐리어는 채널 추정에 사용되었기 때문에 버리고 데이터 캐리어를 추출합니다.
이제 성상도를 다시 얻었으므로 복잡한 값을 디매퍼로 보내 성상도 점을 bit묶음으로 변환 합니다.
마지막으로 비트 그룹은 병렬에서 직렬 스트림으로 변환하고 비트 오류율을 계산합니다.
작업한 전체 소스코드는 곧 첨부합니다.
도움되셨다면, 가벼운 인사 한번 부탁드립니다!
<참고자료>
1. Python OFDM Example - DSPIllustrations.com
2. The Cyclic Prefix (CP) in OFDM - DSPIllustrations.com
5. 선형 컨볼루션 (Linear convolution)과 원형 컨볼루션 (Circular convolution)