一次采样到一次输出,延迟到底花在哪一段?

周期 100 µs 时,异步采样的平均延迟是 57.02 µs,其中 50 µs 花在「等下一次采样」;换成同步锁相后只剩 7.02 µs。五段分解里,最容易被忽略的那段往往占八成以上。

延迟不是一个数,是五段之和:等待采样的相位 + 转换 + 计算 + 输出锁存 + 执行器响应。以 100 µs 周期、1.5 µs 转换、5 µs 计算为例,固定段合计只有 7.02 µs,但异步采样时平均还要再等 50 µs——等待项占 87.7%,而它通常不出现在任何"延迟"数字里。

现象

很多方案在介绍延迟时,报的是链路上最短的那一段:"输出锁存只要 20 ns"、"计算只要 5 µs"。这些数字本身没错,但它们回答的是"我这一段有多快",不是"从采样到输出要多久"。

两者能差一个数量级。同一个系统,按不同口径可以报出:

口径 数值 说的是什么
只算锁存 0.02 µs DMA 搬运一次
算到计算结束 6.52 µs 转换 + 计算
算上采样等待 57.02 µs 从"该采样"到"输出生效"的平均值

控制工程师关心的是第三种。

原因

五段里只有四段是"执行时间",第一段是"相位等待",性质完全不同:

总延迟 = φ + t_转换 + t_计算 + t_锁存 + t_执行器 ,   φ ~ U(0, T)

如果采样是自由运行、与输出不同步,那么"物理量发生变化的那一刻"落在采样栅格之间的位置是随机的,平均要等 T/2。这一项跟 CPU 多快、代码多短毫无关系——它只取决于周期与相位关系。

E[φ] = T/2            (均匀分布)
P90(φ) = 0.9T
max(φ) = T

所以把周期缩小一半,等待项也减半;但把代码优化一半,等待项一点不变。这就是为什么"优化计算"对端到端延迟的收益常常令人失望。

怎么做

第一步:把五段分开列,每段单独给数。 不要只写总延迟。

段 典型来源 怎么测
采样相位等待 采样与 PWM/输出是否同源 同时看触发信号与采样信号的时间差
转换 ADC 采样保持 + 转换时间 看转换完成中断/标志,或读数据手册的转换周期
计算 ISR 执行时间 在 ISR 入口/出口各翻一个 GPIO,示波器量
输出锁存 影子寄存器 → 引脚 同上,看最后一跳
执行器响应 驱动芯片、机械时间常数 只能实测,手册通常只给上限

第二步:判断等待项是否可消。 如果采样由同一个定时器触发(与输出同源),φ 就变成常数而不是随机量:

import random

T = 100e-6
adc, comp, latch, act = 1.5e-6, 5.0e-6, 0.02e-6, 0.5e-6
fixed = adc + comp + latch + act

random.seed(7)
samples = sorted(random.uniform(0, T) + fixed for _ in range(200000))

print("固定段       %.2f us" % (fixed * 1e6))
print("异步均值     %.2f us" % (sum(samples) / len(samples) * 1e6))
print("异步 P90     %.2f us" % (samples[int(0.9 * len(samples))] * 1e6))
print("异步最坏     %.2f us" % (samples[-1] * 1e6))
print("同步(锁相) %.2f us" % (fixed * 1e6))

第三步:把"可消"的那部分消掉。 让采样与 PWM 载波同步(在固定相位点采样),等待项从 T/2 直接变成 0——这是"同步采样"在时序预算上的真正价值,比"提高采样率"划算得多。

验证

用上面的参数做 20 万次抽样(相位均匀分布),与解析值对照:

量 解析值 仿真值
固定段合计 7.02 µs 7.02 µs
异步平均延迟 50 + 7.02 = 57.02 µs 56.98 µs
异步 P90 90 + 7.02 = 97.02 µs 97.03 µs
异步最坏 100 + 7.02 = 107.02 µs 107.02 µs
同步(锁相) 7.02 µs —

结论落在两个数上:等待项占异步均值的 87.7%,同步与异步的均值相差 8.12 倍。

延迟构成:异步采样多出一段 50 µs 的等待

改前只算固定段 7.02 µs → 改后算上等待 57.02 µs,同一套硬件、同一个程序,端到端延迟差了 8 倍——差别不在代码里,在采样与输出的相位关系里。

边界

  • 等待项按均匀分布算,前提是采样自由运行且与输出不同源。若两者同源锁相,φ 是常数,应按实际相位差取值,而不是取 T/2。
  • 本文数值是数值实验(参数为示例值),不是硬件实测;换一台设备,转换时间与执行器延迟会变,但"等待项占大头"的结构通常不变。
  • 执行器响应常被漏掉,而它可能是最大的一项(电磁阀 5–20 ms、机械传动更长)。只测到引脚为止的延迟,不代表闭环延迟。
  • 周期远小于对象时间常数时,等待项会被对象滤波"平均掉"一部分,但它仍是纯延迟,会吃掉相位裕度,不能当作不存在。
  • 若采样前有模拟前端滤波,那段时间也要计入;它常被算在"传感器精度"里,而在时序上属于延迟。

最后验证于 2026-10-29 · 数值实验(Python 3.13,20 万次抽样)· 示例参数:T=100 µs、转换 1.5 µs、计算 5 µs、锁存 0.02 µs、执行器 0.5 µs

一次采样到一次输出,延迟到底花在哪一段?

作者 JimmyZ,嵌入式 / 确定性控制方向。GitHub · 掘金