TT Lab
开始
学习 学习路径 课程

电缆也有回声

追踪闲置支路线产生的陷波

在 TT Lab 中继续学习

目标

找出开路分支的周期性陷波,并用真实的 AC 响应比较匹配之后的信号减小。

先修知识是前面的信号完整性和引脚负载实验,以及 Python 函数、复数、JSON、文件处理。预计需要 85 分钟。请在默认的 60 分钟结束之前,用“+时间”延长(最多 180 分钟)。会话结束时文件会消失,所以请另行保存源代码和报告。

为什么重要

走线的长度与端接,会使不同的频率产生不同的负载。消除了陷波,并不等于保留了信号幅度。学习如何做到:不只看最深的一个点来猜测周期,也不把范围之外的谐振汇报得像是观测到的一样。这是理想的单模无损分支线路,不能代替实物测量、寄生成分、损耗和真实总线认证。

步骤

  1. 所有实现都保存到 /root/stub-notch/analyze.py 中。predict(config,hz) 以 complex 返回理论 H。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 换算成秒。
  2. relative_response(rows) 接收有效的 (Hz,实部,虚部) 元组列表,返回 (Hz,相对dB) 元组列表。相对 dB 是 20log10(2*复数绝对值)。没有分支时的 H=0.5 是固定基准。幅度为 0 是 ValueError,并保留所有采样点及其顺序。
  3. notches(points,threshold_db=-15) 在频率严格递增的有效 (Hz,dB) 列表中,找出内部的局部最小值,以 hz、db 对象列表返回。只包含比两侧相邻点更低、且不高于阈值的谷底,并排除端点。dB 相同的连续平坦谷底,在低于两侧外部相邻点时算作一个,并选取第一个频率。结果按频率升序排列。
  4. infer_delay(found) 接收有效的按频率升序排列的陷波列表。少于两个则为 None。否则返回:相邻 Hz 间隔的中位数 spacing_hz,等于 1e9/(2*spacing_hz) 的 delay_ns,以及所有间隔中 abs(间隔−中位数)/中位数 的最大值 max_relative_error。不要用输入配置或第一个陷波的绝对位置来代替计算。
  5. band_min(points,low_hz,high_hz) 在有效 (Hz,dB) 表的闭合关注区间内,以 hz、db 对象返回最低的 dB 及其位置。请比较区间内所有采样点,以及两个边界处 Hz 与 dB 的线性插值。恰好并列时取较低的频率。超出表的范围,或 low>=high,则为 ValueError。即使没有内部采样点,也要比较两个边界。
  6. analyze(folder) 分析由 config.json 和提供的 simulator.read_response 读取的 response.tsv。请返回下面参考中的对象。陷波、周期、10–200MHz 的最差值要从观测表中计算。求出所有采样点的复数 H 与 predict 结果之差绝对值的最大值,并判断是否在 1e-8 以下。即使只是配置被改变而导致不一致,也要保留原来的观测,且不修改原始文件。
  7. 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) 以 complex 返回理论 H。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) 表的闭合关注区间内,以 hz、db 对象返回最低的 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。保留失败的条件和原始的四个文件,已有的文件夹即使为空也要拒绝。配置错误时也不创建文件夹。

不要把陷波很深的条件从结果中去掉,也不要把匹配无条件当作成功。不要把不同的运行结果覆盖到同一个文件夹中。