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%,可据此在真实总线上预留余量后设定采样点。

采样点优化流程 设定总线长度 扫描采样点 计算稳定时刻 settle_ns 统计误码率 BER 选 BER=0 的最小采样点 作为该长度最优值