Trace the notches of an unused branch line
한국어 원문으로 표시합니다.
목표
개방 분기의 주기적 노치를 찾고, 정합했을 때의 신호 감소까지 실제 AC 응답으로 비교합니다. 선수 지식은 앞 신호 무결성·핀 부하 실습, Python 함수·복소수·JSON·파일 처리입니다. 예상 85분입니다. 기본 60분이 끝나기 전에 +시간으로 연장하세요(최대 180분). 세션 종료 시 파일이 사라지므로 소스와 보고서를 별도로 보관하세요.
왜 중요한가
배선의 길이와 종단은 주파수마다 다른 부하를 만듭니다. 노치를 지웠다고 신호 크기까지 보존한 것은 아닙니다. 가장 깊은 한 점만 보고 주기를 추측하거나 범위 밖 공진을 관측한 것처럼 보고하지 않는 법을 배웁니다. 이상적 단일 모드 무손실 분기 선로이며 실물 측정·기생 성분·손실·실제 버스 인증을 대신하지 않습니다.
단계
- 모든 구현은 /root/stub-notch/analyze.py에 저장합니다. predict(config,hz)는 이론 H를 complex로 반환합니다. config는 delay_ns=0.2/0.35/0.5/1, termination=open/matched인 정확히 두 키의 dict입니다. delay_ns는 bool 아닌 int/float만 받습니다. hz는 bool 아닌 유한 양수 int/float입니다. 그 외 입력은 ValueError입니다. 원본은 변경하지 않습니다. open은 H=0.5/(1+0.5j*tan(2πfTD)), matched는 1/3입니다. TD는 ns에서 초로 바꿉니다.
- relative_response(rows)는 유효한 (Hz,실수부,허수부) 튜플 목록을 받아 (Hz,상대dB) 튜플 목록을 반환합니다. 상대 dB는 20log10(2*복소수 절댓값)입니다. 분기 없는 H=0.5가 고정 기준입니다. 크기 0은 ValueError이고 모든 표본과 순서를 보존합니다.
- notches(points,threshold_db=-15)는 주파수 엄격 증가인 유효 (Hz,dB) 목록에서 내부 국소 최솟값을 찾아 hz, db 객체 목록으로 반환합니다. 양쪽 이웃보다 낮고 문턱 이하인 바닥만 포함하며 끝점은 제외합니다. 같은 dB의 연속 평탄 바닥은 양쪽 바깥 이웃보다 낮을 때 하나로 세고 첫 주파수를 고릅니다. 결과는 주파수 오름차순입니다.
- infer_delay(found)는 유효한 주파수 오름차순 노치 목록을 받습니다. 두 개 미만이면 None입니다. 그 외에는 인접 Hz 간격들의 중앙값 spacing_hz, 1e9/(2*spacing_hz)인 delay_ns, 모든 간격의 abs(간격−중앙값)/중앙값 중 최대 max_relative_error를 반환합니다. 입력 설정이나 첫 노치 절대 위치로 대신 계산하지 않습니다.
- band_min(points,low_hz,high_hz)는 유효 (Hz,dB) 표의 닫힌 관심 구간에서 가장 낮은 dB와 그 위치를 hz, db 객체로 반환합니다. 구간 안 모든 표본과 양 경계의 Hz 대 dB 선형 보간 값을 비교하세요. 정확히 동률이면 낮은 주파수입니다. 표 범위를 벗어나거나 low>=high이면 ValueError입니다. 내부 표본이 없어도 경계 둘을 비교합니다.
- analyze(folder)는 config.json과 제공 simulator.read_response로 읽은 response.tsv를 분석합니다. 아래 참고의 객체를 반환하세요. 노치·주기·10~200MHz 최악값은 관측 표에서 계산합니다. 모든 표본의 복소 H와 predict 결과 차이 절댓값의 최대를 구해 1e-8 이하인지 판정합니다. 설정만 바뀌어 불일치해도 원래 관측을 남기고 원시 파일을 바꾸지 않습니다.
- campaign(values,folder)는 중복 없는 1~8개 설정 list 전체를 먼저 검증하고 새 폴더를 만듭니다. 제공 simulator.capture(config,folder/case-NN)를 실행해 analyze합니다. NN은 순서대로 00부터이며 관측 config가 요청과 다르면 ValueError입니다. results 목록, 모든 passed의 논리곱 all_pass, model=lossless_parallel_stub, measured=False를 반환하고 같은 객체를 report.json에 저장합니다. 실패 조건과 원본 네 파일을 보존하고 기존 폴더는 비어 있어도 거절합니다. 설정 오류에는 폴더도 만들지 않습니다.
참고
코드는 /root/stub-notch/analyze.py, 제공 도우미는 /opt/lab/fixtures/stub_notch/simulator.py입니다. 추가 설치·인터넷·장비는 필요 없습니다. capture(config,새폴더)는 Path를 반환하며 config.json, circuit.cir, response.tsv, ngspice.log를 남깁니다. read_response(path)는 전체 1991표본의 헤더·유한 수치·10MHz~2GHz·1MHz 간격을 검사하고 (Hz,실수부,허수부) 목록을 반환합니다. 깨진 표는 ValueError입니다. open의 먼 끝은 1조Ω 저항으로 근사하며 모든 선로·본선·소스는 50Ω입니다. 도우미가 계산하는 것은 회로와 원시 응답뿐이며 노치·규격 판정은 학습자가 구현합니다.
6단계 반환 키는 config, notches, periodic, band, max_complex_error, consistent, meets_spec, passed, measured입니다. notches는 기본 −15dB 검출 결과, periodic는 infer_delay 결과, band는 band_min(points,1e7,2e8) 결과입니다. consistent는 max_complex_error<=1e-8, meets_spec은 band.db>=−1, passed는 둘 다 True인지이며 measured=False입니다. 이는 학습 규격이지 보드 인증이 아닙니다. 한 개 이하 노치의 periodic는 None입니다. 설정 지연을 대신 쓰거나 관측을 삭제하지 않습니다.
마지막 단계 구현 뒤 실제 여섯 조건을 다음처럼 실행하세요. 모두 통과하는 목록이 아니므로 정상 보고서의 all_pass=False입니다. 재실행은 run-02처럼 새 이름을 사용하세요.
cd /root/stub-notch
PYTHONPATH=/opt/lab/fixtures/stub_notch python3 - <<'PY'
from analyze import campaign
conditions = [dict(delay_ns=t, termination=m) for t in (0.2,0.5,1) for m in ('open','matched')]
print(campaign(conditions, '/root/stub-notch/run-01'))
PY
소스는 64KiB 이하 일반 파일이고 import 시 무출력이어야 합니다. 채점은 별도 작은 표본과 실제 엔진 조건을 사용합니다. 일반 수치 허용차는 상대·절대 1e-8, 노치 주파수는 보간 없이 선택한 표본의 Hz입니다. 규칙이 유효한 수치 표를 받는다고 명시한 함수는 추가 파서를 만들 필요 없습니다. 채점 프로세스는 CPU 12초·파일 8MiB·전체 35초 제한입니다. 수강 시간과는 다릅니다.
분기 부하를 복소수로 계산한다
모든 구현은 /root/stub-notch/analyze.py에 저장합니다. predict(config,hz)는 이론 H를 complex로 반환합니다. config는 delay_ns=0.2/0.35/0.5/1, termination=open/matched인 정확히 두 키의 dict입니다. delay_ns는 bool 아닌 int/float만 받습니다. hz는 bool 아닌 유한 양수 int/float입니다. 그 외 입력은 ValueError입니다. 원본은 변경하지 않습니다. open은 H=0.5/(1+0.5j*tan(2πfTD)), matched는 1/3입니다. TD는 ns에서 초로 바꿉니다.
소스 50Ω에서 본 부하는 본선 50Ω와 분기 입력의 병렬입니다. 정합해도 분기 부하가 없어지지는 않습니다.
모든 조건에 같은 기준을 쓴다
relative_response(rows)는 유효한 (Hz,실수부,허수부) 튜플 목록을 받아 (Hz,상대dB) 튜플 목록을 반환합니다. 상대 dB는 20log10(2*복소수 절댓값)입니다. 분기 없는 H=0.5가 고정 기준입니다. 크기 0은 ValueError이고 모든 표본과 순서를 보존합니다.
각 응답의 최댓값으로 나누면 정합 분기의 신호 감소가 사라집니다. 실수부만으로 크기를 계산하지 않습니다.
골짜기를 하나씩 검출한다
notches(points,threshold_db=-15)는 주파수 엄격 증가인 유효 (Hz,dB) 목록에서 내부 국소 최솟값을 찾아 hz, db 객체 목록으로 반환합니다. 양쪽 이웃보다 낮고 문턱 이하인 바닥만 포함하며 끝점은 제외합니다. 같은 dB의 연속 평탄 바닥은 양쪽 바깥 이웃보다 낮을 때 하나로 세고 첫 주파수를 고릅니다. 결과는 주파수 오름차순입니다.
가장 깊은 한 점만 고르지 마세요. −15dB도 문턱에 포함하며 양끝이 낮은 것은 관측된 내부 노치가 아닙니다.
노치 간격에서 지연을 구한다
infer_delay(found)는 유효한 주파수 오름차순 노치 목록을 받습니다. 두 개 미만이면 None입니다. 그 외에는 인접 Hz 간격들의 중앙값 spacing_hz, 1e9/(2*spacing_hz)인 delay_ns, 모든 간격의 abs(간격−중앙값)/중앙값 중 최대 max_relative_error를 반환합니다. 입력 설정이나 첫 노치 절대 위치로 대신 계산하지 않습니다.
첫 노치의 1/(4TD)와 반복 간격의 1/(2TD)를 구별하세요. 불규칙한 간격의 편차도 남깁니다.
관심 대역의 가장 약한 곳을 찾는다
band_min(points,low_hz,high_hz)는 유효 (Hz,dB) 표의 닫힌 관심 구간에서 가장 낮은 dB와 그 위치를 hz, db 객체로 반환합니다. 구간 안 모든 표본과 양 경계의 Hz 대 dB 선형 보간 값을 비교하세요. 정확히 동률이면 낮은 주파수입니다. 표 범위를 벗어나거나 low>=high이면 ValueError입니다. 내부 표본이 없어도 경계 둘을 비교합니다.
이번 격자는 선형 주파수입니다. 직전 RC 실습의 로그 축 보간을 그대로 복사하면 다른 결과가 됩니다.
노치 없음과 규격 통과를 구별한다
analyze(folder)는 config.json과 제공 simulator.read_response로 읽은 response.tsv를 분석합니다. 아래 참고의 객체를 반환하세요. 노치·주기·10~200MHz 최악값은 관측 표에서 계산합니다. 모든 표본의 복소 H와 predict 결과 차이 절댓값의 최대를 구해 1e-8 이하인지 판정합니다. 설정만 바뀌어 불일치해도 원래 관측을 남기고 원시 파일을 바꾸지 않습니다.
정합 분기는 노치가 없지만 관심 대역의 고정 기준 이득을 따로 검사해야 합니다. 복소 모델과 규격은 별도 조건입니다.
길이와 종단 조건을 비교한다
campaign(values,folder)는 중복 없는 1~8개 설정 list 전체를 먼저 검증하고 새 폴더를 만듭니다. 제공 simulator.capture(config,folder/case-NN)를 실행해 analyze합니다. NN은 순서대로 00부터이며 관측 config가 요청과 다르면 ValueError입니다. results 목록, 모든 passed의 논리곱 all_pass, model=lossless_parallel_stub, measured=False를 반환하고 같은 객체를 report.json에 저장합니다. 실패 조건과 원본 네 파일을 보존하고 기존 폴더는 비어 있어도 거절합니다. 설정 오류에는 폴더도 만들지 않습니다.
노치가 깊은 조건을 결과에서 빼거나 정합을 무조건 성공 처리하지 않습니다. 서로 다른 실행 결과를 같은 폴더에 덮지 마세요.