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

电缆也有回声

电缆也有回声:波形验证实验室

在 TT Lab 中继续学习

目标

用 ngspice 运行真实的传输线模型,并用 Python 分析到达时刻、反射、端接、公差和数值差异。这不是实物测量,也不是 PCB 认证过程。

为什么重要

快速的边沿可能产生比电源更高的瞬时电压。电阻的位置、输入单位、采样时刻一旦改变,看似合理的图表也会变成对另一个问题的回答。要把电路条件、波形、分析代码和验证范围连在一起,做出可以重新确认的产出物。需要具备 shell、Python 函数/列表/字典以及分压的基础。预计需要 75 分钟,所以请在默认的 60 分钟结束之前,用“+时间”延长(最多 180 分钟)。结束后文件会消失,所以请另行保存。

步骤

  1. 发送了 3.3V,却收到了 5.5V — 在 baseline.json 中保存 volts=3.3、driver_ohm=10、series_ohm=0、z0_ohm=50、load_ohm=1000000000、delay_ns=2、rise_ns=0.2、step_ns=0.02、stop_ns=14。所有文件都位于 /root/signal-integrity 之下。运行 experiment.py --model /root/signal-integrity/baseline.json --out /root/signal-integrity/baseline,生成 model.cir、trace.csv、run.json,并确认输入/TX/RX 列。
  2. 读取电缆的时钟 — 在 arrival.py 中实现 first_crossing_ns(rows, threshold_v)。rows 是 [time_s, drive_v, tx_v, rx_v] 按时间升序排列的列表。对 RX 第一次触及阈值的时刻做线性插值,并以 ns 返回。如果从第一个点起就不低于阈值,则返回第一个时刻,直到最后都没有则返回 None。同时检查 baseline 波形和另一个小的采样表。
  3. 预测回声返回的电压 — 让 reflections.py 中的 predict(vs, source_ohm, z0_ohm, load_ohm) 返回包含 launch_v、gamma_source、gamma_load、rx_first_v、rx_second_v 的对象。source_ohm 是驱动器与额外串联电阻之和。输入是正的有限数,负载是有限电阻而不是无穷大。第二个接收平台是在第一个值上再加上下一次往返的变化。
  4. 用一个电阻减弱回声 — 在 baseline.json 的条件下,创建只把 series_ohm 改为 40 的 series.json,并用 --out /root/signal-integrity/series 运行。保留基准文件。包含 driver_ohm=10 在内的总源电阻是 50Ω。请确认在生成的波形中,第一次发送电压与第一次接收电压为什么不同。
  5. 同样是 50Ω,位置不同 — 在 baseline.json 的条件下,创建只把 load_ohm 改为 50 的 parallel.json,并用 --out /root/signal-integrity/parallel 运行(series_ohm 为 0)。tradeoff.py 中的 load_power(vs, source_ohm, load_ohm) 返回经过足够长时间后的 DC 状态下的 current_a 和 load_w。输入电压 V 和电阻 Ω,以 A 和 W 返回,并检查有限正数的条件。
  6. 比较代表值之外的九条电缆 — 以 --out /root/signal-integrity/corners --corners 运行 series.json。保持额外的 40Ω 不变,生成驱动器 8/10/12Ω × Z0 45/50/55Ω 共 9 个文件夹和 peaks.json。summary.py 中的 summarize(records) 对非空的 [{case: 名称, peak_v: 最大V}, ...],返回 count、min_peak_v、max_peak_v、max_case。最高值并列时,取字典序最靠前的名称。
  7. 按时间而不是采样点序号来对齐 — 以 --out /root/signal-integrity/fine 运行只把 series.json 中的 step_ns 改为 0.01 的 fine.json。convergence.py 中的 max_difference(coarse, fine) 在 coarse 的每个时刻对 fine 做线性插值,返回 TX/RX(col 2,3)电压的最大绝对差 V。表格是 [time_s,drive_v,tx_v,rx_v],至少有两个点,时间严格递增,起点和终点相同。也会检查与真实波形间隔不同的小表。
  8. 把依据绑定起来,并留下局限 — 保留前面步骤的文件,并编写 release.json。model_type=ideal_single_mode_lossless、measured=false、pcb_certified=false、target_verification_required=true。在 release.json 格式示例的 sha256 对象中,只使用提供的相对路径作为键,并填入当前文件内容的 SHA-256 小写 64 位值。前面步骤的波形与分析也会重新验证。备份文件不要放进列表。

参考

请先用 mkdir -p /root/signal-integrity 创建工作文件夹。命令格式是 python3 /opt/lab/signal_integrity/experiment.py --model 输入JSON --out 新输出文件夹。请通过各步骤的文件卡片区分输入和产出物的格式。产出物示例是缩略格式,不能用来代替真实的 solver 输出提交。辅助程序不会覆盖已有的输出文件夹。要重新运行,请把之前的文件夹以另一个名称保存。参考答案会自动完成这件事。Python 分析函数不直接读取文件,而是接收表格/数值作为参数并返回结果,不要加入 print 日志。数值返回的允许误差为相对 1e-6 或绝对 1e-8,JSON 布尔值会检查确切的类型。每个源文件和 JSON 必须是 64KiB 以下、波形 CSV 必须是 2MiB 以下、且不是符号链接的普通文件。函数运行被限制为 CPU 4 秒、墙钟 5 秒、地址空间 256MiB。最终评分会重新确认包括公差子波形在内的前面步骤的资料。不需要安装额外的软件包,不需要联网,也不需要真实设备。

发送了 3.3V,却收到了 5.5V

在 baseline.json 中保存 volts=3.3、driver_ohm=10、series_ohm=0、z0_ohm=50、load_ohm=1000000000、delay_ns=2、rise_ns=0.2、step_ns=0.02、stop_ns=14。所有文件都位于 /root/signal-integrity 之下。运行 experiment.py --model /root/signal-integrity/baseline.json --out /root/signal-integrity/baseline,生成 model.cir、trace.csv、run.json,并确认输入/TX/RX 列。

辅助程序的完整路径是 /opt/lab/signal_integrity/experiment.py,用 python3 运行。输入时间的单位是 ns,CSV 时间的单位是 s。输出文件夹由辅助程序创建。

读取电缆的时钟

在 arrival.py 中实现 first_crossing_ns(rows, threshold_v)。rows 是 [time_s, drive_v, tx_v, rx_v] 按时间升序排列的列表。对 RX 第一次触及阈值的时刻做线性插值,并以 ns 返回。如果从第一个点起就不低于阈值,则返回第一个时刻,直到最后都没有则返回 None。同时检查 baseline 波形和另一个小的采样表。

在 a.rx < threshold <= b.rx 的第一个区间中,按电压比例移动时间。rows 中的数值已经是 float,这个函数不是用来打开 CSV 的。

预测回声返回的电压

让 reflections.py 中的 predict(vs, source_ohm, z0_ohm, load_ohm) 返回包含 launch_v、gamma_source、gamma_load、rx_first_v、rx_second_v 的对象。source_ohm 是驱动器与额外串联电阻之和。输入是正的有限数,负载是有限电阻而不是无穷大。第二个接收平台是在第一个值上再加上下一次往返的变化。

分别计算前进波 A 以及 ΓL、ΓS,并确认第二次变化是否为 A×(1+ΓL)×ΓS×ΓL。当负载较小或源较大时,也要保持符号。

用一个电阻减弱回声

在 baseline.json 的条件下,创建只把 series_ohm 改为 40 的 series.json,并用 --out /root/signal-integrity/series 运行。保留基准文件。包含 driver_ohm=10 在内的总源电阻是 50Ω。请确认在生成的波形中,第一次发送电压与第一次接收电压为什么不同。

把额外电阻填成 50,会让总源电阻成为 60Ω,这是一个失误。请确认 run.json 中的模型与所用的输入 JSON 是否相同。

同样是 50Ω,位置不同

在 baseline.json 的条件下,创建只把 load_ohm 改为 50 的 parallel.json,并用 --out /root/signal-integrity/parallel 运行(series_ohm 为 0)。tradeoff.py 中的 load_power(vs, source_ohm, load_ohm) 返回经过足够长时间后的 DC 状态下的 current_a 和 load_w。输入电压 V 和电阻 Ω,以 A 和 W 返回,并检查有限正数的条件。

需要做两件事:生成电路文件和实现函数。用总电阻求出电流,负载功率则用该电流的平方乘以负载电阻来计算。

比较代表值之外的九条电缆

以 --out /root/signal-integrity/corners --corners 运行 series.json。保持额外的 40Ω 不变,生成驱动器 8/10/12Ω × Z0 45/50/55Ω 共 9 个文件夹和 peaks.json。summary.py 中的 summarize(records) 对非空的 [{case: 名称, peak_v: 最大V}, ...],返回 count、min_peak_v、max_peak_v、max_case。最高值并列时,取字典序最靠前的名称。

不要亲手写示例列表,而要生成真实的 9 个波形。如果只返回一个最大值,或者按列表顺序选择并列项,在另外的条件下就会失败。

按时间而不是采样点序号来对齐

以 --out /root/signal-integrity/fine 运行只把 series.json 中的 step_ns 改为 0.01 的 fine.json。convergence.py 中的 max_difference(coarse, fine) 在 coarse 的每个时刻对 fine 做线性插值,返回 TX/RX(col 2,3)电压的最大绝对差 V。表格是 [time_s,drive_v,tx_v,rx_v],至少有两个点,时间严格递增,起点和终点相同。也会检查与真实波形间隔不同的小表。

如果用 zip 按行号配对,时刻就会不同。请在 fine 中找出夹住当前 coarse 时刻的两个点,并在这个函数的比较中排除输入电压 col 1。

把依据绑定起来,并留下局限

保留前面步骤的文件,并编写 release.json。model_type=ideal_single_mode_lossless、measured=false、pcb_certified=false、target_verification_required=true。在 release.json 格式示例的 sha256 对象中,只使用提供的相对路径作为键,并填入当前文件内容的 SHA-256 小写 64 位值。前面步骤的波形与分析也会重新验证。备份文件不要放进列表。

如果修改过代码或电路,请先重新运行并验证,最后再生成哈希。文件相同,与实物测量正确,是两种不同的主张。