한국어 · English
3GPP NR 스택(PHY 에서 RRC 까지)을 규격 원문에 대조해 검증하는 참조 구현과 도구 모음. 예전 이름은 lls-kit - 링크레벨 시뮬레이터 작업 키트로 시작했다.
핸드북(조사 문서)에서 "코드가 있으면 바로 할 수 있다"고 적었던 네 가지를 실제로 돌아가는 형태로 만든 것이다:
| 도구 | 역할 | 핸드북 대응 |
|---|---|---|
specmap.py |
규격 조항 → 모듈 추적 (연쇄 영향 포함) | 04절 2단계 |
golden.py |
골든 벡터 추출/대조 | 04절 3·5(a)단계 |
campaign.py |
SNR 스윕 실행, 블록에러 기준 정지, Wilson CI | 05절 |
regress.py |
두 결과의 신뢰구간 기반 회귀 판정 | 04절 5(b)단계 |
loop.py |
결함 대장 ↔ 게이트 대조 (자기개선 루프) | — |
bgtool.py |
규격 표 추출(3GPP .docx)·검증 | — |
nrlls/ 는 이 도구들이 물릴 대상이 되는 참조 PDSCH 체인이다.
의존성: numpy, pyyaml.
python check.py # 전체 게이트 - 무엇이든 주장하기 전에 통과시킬 것
python server.py # 로컬 대시보드 http://127.0.0.1:8765, 설치할 것 없음전체 명령은 아래 사용법 참조.
로컬 대시보드(python server.py)를 영어 UI로 전환해 캡처했습니다.
![]() |
![]() |
| PHY 캠페인 — 캠페인 선택·실행, 동작점 검사와 함께 BLER 곡선을 겹쳐 본다. | 적합성 판정 — TS 38.523-1(RRC, RLC)·TS 38.101-4(PHY) 기준의 PASS / FAIL / 판정불가. |
![]() |
|
| 계층 화면 — RRC~PHY 각 계층이 하는 일, 입출력, 핵심 개념, 게이트 상태. |
사내 LLS가 MATLAB 5G Toolbox 기반으로 확인됐다. 어댑터는 matlab/ 에 있고,
도구 4종은 시뮬레이터 언어와 무관하게 그대로 쓴다.
python specmap.py --map matlab trace 38.214 # 5G Toolbox 함수로 추적
python golden.py diff before/ after/ --map matlab # MATLAB 덤프 대조
python regress.py results/a.json results/b.json # 동일MATLAB 쪽은 llskit.runSweep / llskit.writeResult / llskit.captureGolden 세 개를
기존 스크립트에 끼워 넣으면 된다. 자세한 건 matlab/README.md.
단, matlab/ 의 .m 파일은 이 환경에 MATLAB이 없어 실행 검증되지 않았다 —
해당 문서의 "검증되지 않은 부분" 절을 먼저 읽을 것.
nrlls/ 는 이제 비교·학습용 참조 구현이다. 규격 해석이 갈릴 때
"다른 독립 구현은 이렇게 한다"는 두 번째 의견으로 쓰면 된다.
이 구분이 이 저장소에서 가장 중요하다. 전문은
docs/compliance.md (PDSCH 체인)과
docs/phy-channels.md (그 밖의 채널·신호) —
보고용 결과를 내기 전에 반드시 읽을 것.
요약:
| 영역 | 상태 |
|---|---|
| PDSCH 송신 경로 (38.211/212/214) | 규격대로 구현 |
| SSB 전체 + 2단계 셀 탐색 · 시간동기 · 버스트 집합 | 구현 — 수식은 문서에 OLE 라 검증 필요, 성질로 게이트 |
| Polar 부호 (CA-SCL) | 구현 — 표 둘 다 원문에서 기계 추출, 순열로 검증 |
| PDCCH (DCI/RNTI/탐색공간/CORESET 매핑) | 구현 |
| PRACH (Zadoff-Chu + 시간영역 파형 + 검출) | 구현 — N_CP 값은 설정으로 받는다 |
| PUSCH 상향 고유부 (DFT-s-OFDM, 저-PAPR 수열) | 구현 — PAPR 저감을 게이트가 잰다 |
| PUCCH (포맷0~4 + UCI 부호화·다중화·호핑) | 구현 |
| CSI-RS · SRS(호핑·안테나 스위칭) · PT-RS | 구현 |
| 위상잡음 모델 | 구현 — PT-RS 가 무엇을 고치는지 잴 수 있다 |
| 실제 38.212 LDPC | 구현됨 (sim.fec: ldpc). 표는 3GPP 원문에서 bgtool.py docx 로 직접 추출 |
| 기본 FEC | genie 추상화(GMI) — 빠르지만 실제 복호기의 상한이다 |
| HARQ, TDL-D/E(LOS), MIMO (최대 24 레이어) | 구현됨 — 13 이상은 Rel-18 dmrs_type_enh, 포트 표는 원문 대조 |
| CP 초과 지연 ISI | 시간영역 경로로 곡선에 반영 가능 (time_domain: true). 기본 경로에선 크기만 잰다 |
| PDCP 절차·보안·EHC·UDC·ROHC(프로파일 0) | 구현 — docs/pdcp.md. 헤더 비트 배치 검증 필요, ZUC 없음 |
| RLC TM/UM/AM, MAC PDU·CE | 구현 — docs/rlc.md, docs/mac.md. 헤더는 OCUDU 벡터와 대조 |
| RRC 절차 + UPER + 키 유도 + RLM | 구현 — docs/rrc.md. 측정(A3)·핸드오버 포함 |
| 25 레이어 이상 | 미지원 (규격 DM-RS 포트가 24 개다) |
| 규격 표 12종 (LDPC/polar/MCS/TBS/TDL/CSI-RS/DM-RS…) | 원문에서 기계 추출·대조 완료 (Rel-18) |
| RV 계수, PSS/SSS 다항식, c_init, PRACH N_CP | 검증 필요 — 수식이 OLE 라 복원한 것 |
위의 "규격 준수인가"는 누가 값을 정하는가를 묻는다. 실장을 앞두면 어디에 실장되는가가 붙는다. 직교하는 두 축이고 레지스트리가 둘 다 든다.
python specmap.py realm # 실장 영역별 구분 (hw/sw/boundary/sim_only)교차점 구현 자유 × (hw | boundary) 가 codesign 의사결정이 사는 곳이다 —
현재 4개(채널 추정·등화·LLR 디매핑·LDPC 복호). 여기서 나온 곡선이 곧 면적·지연·
비트폭의 근거가 된다. docs/codesign.md 참조.
의존성: numpy, pyyaml.
# 규격 변경이 어느 모듈에 걸리는지 (연쇄 포함)
python specmap.py trace 38.214
python specmap.py trace dmrs
python specmap.py check # 레지스트리와 코드 정합성
# 수정 '전에' 골든 벡터부터
python golden.py capture campaigns/baseline.yaml -o golden/baseline.npz
# ... 코드 수정 ...
# 규격 고정 경로가 안 깨졌는지
python golden.py verify campaigns/baseline.yaml golden/baseline.npz
# 성능 곡선
python campaign.py campaigns/baseline.yaml -o results/baseline.json --jobs 4
# 회귀 판정
python regress.py results/baseline.json results/modified.json
# 보고서 - 곡선 + KPI + 게이트 + 규격 출처를 한 장의 HTML 로
python report.py results/baseline.json results/perfect-ce.json -o report.html
# PDSCH 외 물리채널 곡선 (PDCCH / PBCH / PUCCH / PRACH)
python chancamp.py campaigns/pdcch.yaml -o results/pdcch.json --jobs 4
# 적합성 시험 - 규격 한계 대비 PASS / FAIL / 판정불가
python testplan.py list
python testplan.py run --clause 5.3.2 --jobs 4 -o results/conformance.json
# 자기개선 루프 - 결함마다 재발을 막는 게이트가 있는가
python loop.py status
# 전체 게이트 - 무엇이든 주장하기 전에 통과시킬 것
python check.pychancamp.py 는 PDSCH 외 물리채널 곡선을 뽑고,
testplan.py 는 곡선이 아니라 판정을 낸다 — TS 38.101-4 5.3절의 PDCCH 복조
최소성능을 원문에서 기계로 뽑아(시험 44개) 그 조건대로 돌리고 한계와 비교한다.
판정은 PASS / FAIL / 판정불가 셋이다. 자세한 것은
docs/measurement.md 참조 — 판정이 규격 적합성 인증이
아닌 이유도 거기 있다.
report.py 는 결과 JSON 으로 보고서 HTML 을 만든다. 곡선만 있는 보고서는
틀리기 쉬워서, 곡선 옆에 이 숫자의 조건을 같이 싣는다 —
목표 BLER 에 필요한 SNR(보간만, 외삽 금지), baseline 과 다른 설정, check.py
결과 전문, 규격 표의 출처와 아직 검증 필요인 항목, genie FEC · CP 초과 SINR
상한 같은 주의. 곡선은 인라인 SVG 다.
check.py 는 단위 테스트 · 레지스트리 정합성 · 입력 크기 · 골든 벡터 ·
동작점(Ês/Noc) · 채널추정 순서 · 결함 대장 일곱 가지를 한 번에 돌리고 종료 코드로 판정한다. 에이전트에게 작업을 맡길 때의
합격선이기도 하다 — AGENTS.md 참조.
Git Bash 기본 코드페이지에서 한글 출력이 깨진다. PYTHONUTF8=1 을 붙이거나
chcp 65001 을 먼저 실행할 것. 출력 내용 자체는 정상이다.
campaigns/*.yaml 한 파일이 실험 하나다. 한 번에 축 하나만 바꾸고
새 이름으로 저장한다. regress.py 가 설정 차이를 평평하게 나열하고,
축을 둘 이상 바꿨으면 경고한다.
기본 baseline.yaml 은 "빠르게 한 바퀴" 크기(target_block_errors: 100,
max_slots: 2000)다. 보고용 곡선은 200~1000 / 20000 이상으로 올릴 것.
현재 속도는 약 13 ms/슬롯이다.
python server.py 로 로컬 웹앱이 뜬다 (http://127.0.0.1:8765). 설치할 것이 없다 —
백엔드는 표준 라이브러리, 프론트엔드는 빌드 없는 ES 모듈이다.
- 사이드바: 검증 상태(게이트 요약, 늘 보인다) · 계층 RRC~PHY(계층별 테스트 통과 수) · 도구(패킷 여정, 블록 지도) · 검증(적합성 판정, PHY 캠페인, 결과 관리).
- 검증은 작업으로 돈다. 기동 때 한 번, 이후 '다시 검사' 로 계층별 테스트와
check.py를 백그라운드로 돌려results/에 캐시한다. 요청은 기다리지 않는다 (--no-verify로 기동 때 검사를 끈다).
화면과 API: docs/dashboard.md.
3GPP는 "SNR"을 직접 정의하지 않는다. RAN4 성능 요구사항이 쓰는 양은 둘이다.
| 양 | 정의 | 함정 |
|---|---|---|
| Noc | 백색 잡음원의 PSD, SCS로 정규화된 RE당 전력 | 대역/파워클래스마다 다르다. 하나를 재사용하면 안 된다 |
| Ês | RE당 수신 에너지, 심볼의 useful part 기준(CP 제외) | 시간영역에서 CP 포함해 더하면 normal CP에서 약 0.29 dB 치우친다 |
지켜야 할 규칙 둘:
- 프리코딩 이득을 접어 넣지 않는다. 규격의 SNR 정의는 RE가 프리코딩되지 않았다고 가정한다.
- 수신 안테나 수로 나누지 않는다. Noc는 안테나 1개 기준이고, 수신 다이버시티 이득은 등화 결과로 나타나야 한다.
구현은 nrlls/rf.py, MATLAB 쪽은 matlab/+llskit/verifyOperatingPoint.m.
최소 Noc 유도식(REFSENS - 10log10(12·SCS·nPRB) + D - SNR_REFSENS + Δthermal)도
들어 있다.
N0 계산은 FFT 정규화·CP 보정·안테나 수·프리코딩 네 군데서 틀릴 수 있고,
틀려도 곡선은 그럴듯하게 나온다 — 통째로 평행이동해 있을 뿐이다.
campaign.py 는 곡선을 뽑기 전에 실제 생성된 신호/잡음 RE로 Ês/Noc를
되재서 요청값과 대조한다.
페이딩 채널에서 Ês는 앙상블 평균이라 유한 표본에서 흔들린다. 계통 오차와 표본 부족을 가르는 법: 표본을 늘려가며 재본다. 오차가 줄면 표본 부족, 한 곳에 붙어 있으면 정의가 틀린 것이다. 캠페인 러너가 이 판정을 자동으로 한다.
도구가 실제로 잡은 결함은 defects.json 대장에, 서술은
docs/defects.md 에 있다. python loop.py status 는 결함별로 '무엇이
잡았나'와 '무엇이 재발을 막나'를, python loop.py gates 는 그 역방향을 보여준다.
재발을 막는 게이트가 없는 결함이 남아 있으면 check.py 가 실패한다.
nrlls/
spec38211.py 심볼/자원격자 레벨 [규격 고정]
spec38212.py 비트 레벨 [규격 고정]
spec38214.py 파라미터 공급 [규격 고정]
spec38901.py TDL 채널 모델 [규격 고정]
fec.py 부호화 계층 [파라미터는 규격, 동작은 교체 가능]
receiver.py 수신 알고리즘 [규격 없음 - 구현 자유]
link.py 슬롯 루프
config.py 설정 구조체
specmap.json 규격 -> 모듈 레지스트리
campaigns/ 실험 설정
results/ 캠페인 결과 (설정·시드·커밋해시 포함)
golden/ 골든 벡터
tests/ 규격 단위 테스트
golden_tap 이 붙은 블록은 link.py 의 _tap() 지점에서 중간 출력을 남긴다.
새 탭을 추가하려면 _tap(taps, "이름", 값) 한 줄과 specmap.json 항목을 추가하면 된다.
MIT — LICENSE 참고.


