4. CAN FD采样点位置优化与通信误码率测试
任务说明
CAN FD 的采样点(Sample Point)决定位时间内采样时刻。总线越长,信号传播与收发器延迟越大,采样点过前会采到未稳定的位电平,导致误码。本案例用一段可运行的 Python 仿真,扫描采样点位置与总线长度,统计误码率(BER),找出不同总线长度下的最优采样点。
模型与依赖
仅需 Python 3,无第三方库。模型:位时间按 CAN FD 数据段 1 Mbps(1 µs)计算,采样点 SP 表示采样时刻占位时间的百分比。信号往返延迟 = 2 × 总线长度 × 传播速度(约 5 ns/m),加上收发器环路延迟。若采样时刻早于信号稳定时刻,则判定该位误码。误码率 = 误码位数 / 总位数。
核心代码
import random
BIT_TIME_NS = 1000.0 # 1 Mbps 数据段位时间
PROP_NS_PER_M = 5.0 # 线缆传播延迟
TRANSCEIVER_LOOP_NS = 120.0 # 收发器环路延迟
TOTAL_BITS = 200000 # 每个组合测试的位数
def ber_for(sp_percent, length_m, jitter_ns=40.0, seed=0):
"""返回给定采样点与总线长度下的误码率。"""
rng = random.Random(seed)
sample_ns = BIT_TIME_NS * sp_percent / 100.0
# 信号从发送端到最远端再返回的稳定时刻
settle_ns = 2 * length_m * PROP_NS_PER_M + TRANSCEIVER_LOOP_NS
errors = 0
for _ in range(TOTAL_BITS):
jitter = rng.gauss(0, jitter_ns)
if sample_ns + jitter < settle_ns:
errors += 1
return errors / TOTAL_BITS
def sweep(lengths, sp_list):
best = {}
for L in lengths:
row = [(sp, ber_for(sp, L)) for sp in sp_list]
ok = [r for r in row if r[1] == 0.0]
best[L] = min(ok, key=lambda r: r[0]) if ok else min(row, key=lambda r: r[1])
print(f"长度 {L:>4} m: " + " ".join(f"{sp}%->{ber:.2e}" for sp, ber in row))
print(f" 最优采样点: {best[L][0]}% BER={best[L][1]:.2e}")
return best
if __name__ == "__main__":
lengths = [10, 20, 40, 80]
sp_list = [60, 65, 70, 75, 80, 85, 90]
sweep(lengths, sp_list)
运行与验证
运行 python canfd_sp.py。程序对每个总线长度打印各采样点的 BER,并给出该长度下 BER 为 0 的最小采样点作为最优值。判定通过条件:短总线(10 m)在较低采样点即可零误码;总线越长,零误码所需采样点越大,最优采样点随长度单调后移。若某长度下所有采样点均非零,则输出该长度下 BER 最小的采样点。
结果解读
稳定时刻 settle_ns 随长度线性增长,采样时刻 sample_ns 随采样点百分比增大。当采样时刻晚于稳定时刻时误码为 0。因此最优采样点 ≈ settle_ns / BIT_TIME_NS × 100%,可据此在真实总线上预留余量后设定采样点。