Files
DCU_DesktopController/docs/reports/ECAT_RATE_TRADEOFF.html
T
cbb beeae8a382 chore(hygiene): P3 报告归档 docs/reports + scripts 收敛 + lab 清理 + CSS/README 约定
正式 scripts 仅保留 README 自测清单;根目录报告迁入 docs/reports;
lab 采样 dump 出库;CSS 注明 btn/toast 所有权并 bump ?v=。
2026-09-21 02:26:42 +08:00

70 lines
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>EtherCAT 周期速度 × 故障率 × CPU 占用 调研</title>
<style>
:root{--fg:#111827;--mut:#6b7280;--bd:#e5e7eb;--bg:#f8fafc;--acc:#1d4ed8;--warn:#b45309;--bad:#b91c1c}
*{box-sizing:border-box}
body{margin:0;background:#fff;color:var(--fg);
font:15.5px/1.72 -apple-system,"Segoe UI","Microsoft YaHei",system-ui,sans-serif}
main{max-width:1120px;margin:0 auto;padding:40px 28px 90px}
h1{font-size:29px;line-height:1.3;margin:0 0 6px;letter-spacing:-.2px}
h2{font-size:20px;margin:44px 0 12px;padding-bottom:7px;border-bottom:2px solid var(--bd)}
h3{font-size:16px;margin:26px 0 8px;color:#374151}
p,li{margin:8px 0}
.meta{color:var(--mut);font-size:13.5px;margin-bottom:26px}
.card{background:var(--bg);border:1px solid var(--bd);border-left:4px solid var(--acc);
border-radius:8px;padding:16px 20px;margin:18px 0}
.card.warn{border-left-color:var(--warn);background:#fffbeb}
.card.bad{border-left-color:var(--bad);background:#fef2f2}
.card h3{margin:0 0 8px;font-size:15px;color:inherit}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(430px,1fr));gap:18px;margin:18px 0}
.fig{border:1px solid var(--bd);border-radius:8px;padding:12px 10px 8px;background:#fff}
.fig > .cap{font-size:12.5px;font-weight:600;color:#374151;margin:0 0 4px 8px}
.fig > .sub{font-size:11.5px;color:var(--mut);margin:0 0 4px 8px}
table{border-collapse:collapse;width:100%;font-size:13px;margin:14px 0}
th,td{border:1px solid var(--bd);padding:6px 9px;text-align:right}
th{background:#f1f5f9;font-weight:600;text-align:center}
td:first-child,th:first-child{text-align:left}
tr.best td{background:#ecfdf5;font-weight:600}
tr.dead td{background:#fef2f2;color:#7f1d1d}
code{background:#f1f5f9;padding:1.5px 5px;border-radius:4px;font-size:12.5px;
font-family:ui-monospace,"Cascadia Mono",Consolas,monospace}
.kpi{display:flex;gap:14px;flex-wrap:wrap;margin:22px 0 8px}
.kpi div{flex:1 1 168px;border:1px solid var(--bd);border-radius:8px;padding:13px 15px;background:#fff}
.kpi b{display:block;font-size:23px;line-height:1.25;color:var(--acc)}
.kpi span{font-size:12px;color:var(--mut)}
ul{padding-left:22px}
.excl{font-size:12.5px;color:var(--bad);background:#fef2f2;border:1px dashed #fca5a5;
border-radius:6px;padding:9px 13px;margin:12px 0}
.foot{margin-top:44px;padding-top:16px;border-top:1px solid var(--bd);
font-size:12.5px;color:var(--mut)}
</style></head><body><main>
<h1>EtherCAT 周期速度 × 故障率 × CPU 占用 调研</h1>
<div class="meta">调研日期 2026-09-08 · 本机 I210 + 1 个 GD32E508 从站 · 两轮扫描:带 CAN / 拔掉全部 CAN · 数据 <code>lab/ecat_rate_sweep_*.csv</code> · 生成器 <code>scripts/build_ecat_report_html.py</code></div>
<div class="kpi"><div><b>0.5ms</b><span>实测可用上限(2kHz,带 CAN 工况)</span></div><div><b>≈9.0pp</b><span>CAN 每拍恒定负担(3 档配对,饱和档除外)</span></div><div><b>4000 帧/s</b><span>电机 STATUS 实测刷新(1/0.5ms)</span></div><div><b>≈8.2kHz</b><span>纯 ECAT 实测硬上限(设 10/12.5/16kHz 实测均不涨)</span></div></div>
<div class="card"><h3>结论</h3><ul><li><b>带 CAN 工况的可用上限在 0.5ms,瓶颈在从站 GD32 不在主站。</b>实测可用到 0.5ms;0.25ms 起电机数据刷新率从 4000 帧/s 掉到 88 帧/s(带 CAN 那轮当场确认 <code>online=True</code>,是真失效)。可用上限只夹在 (0.25ms, 0.5ms] 内,<b>具体位置没测到</b>。</li><li><b>纯 ECAT 硬上限 ≈8.2kHz,这次测到了墙本身。</b>断电重启后无 CAN 补测:0.25/0.125ms 满速通过(99.7% / 98.0%);再往下设 0.1 / 0.08 / 0.0625ms,实测循环率全部顶在 8196–8238Hz(达成 82.3% / 65.9% / 51.2%),wkc 全程 3/3、从站始终应答。墙的来历:主站单拍硬耗时 <code>cyc p50</code> 各档恒 117–126µs,1/121µs ≈ 8.2kHz —— 是"每拍必须花的往返+处理时间",不是主机 CPU 不够(顶墙时主机 CPU 反而降到 ~85%)。原「3.5kHz 外推」<b>被证伪</b>;首轮无 CAN 0.25ms 停报为残状态偶发,不复现。注意"跑得快"≠"能用":带 CAN 的可用上限仍由电机数据刷新决定(下一条)。</li><li><b>拔 CAN 对照解开了混淆</b>:未饱和三档 Δ 稳定 8.7–9.3pp,不随频率张开 → 快档塌陷不是 CAN 挤出来的;饱和两档 Δ 收窄到 ≤0.5pp,正是读数被夹紧的特征。</li><li><b>主机 native CPU 恒约 100% 单核、与周期无关</b>(自旋恒转,<code>/api/motor/spin</code> 已是空操作)。唯一的例外是带 CAN 轮的 0.125ms 档降到 87.5% —— 因为从站已停答。无 CAN 补测里从站活着,同档就回到 99.7%。<b>主机 CPU 掉下来那一刻,正是从站死掉那一刻。</b></li><li>建议:<b>要吃到余量就停在 0.5ms</b>。0.25ms 不是"更快",是功能损坏。</li></ul></div>
<h2>一、曲线</h2>
<div class="grid">
<div class="fig"><div class="cap">① 循环率:设定 vs 实测(主站侧)</div><svg viewBox="0 0 560 320" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="循环率:设定 vs 实测"><line x1="64" y1="271.2" x2="544" y2="271.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="274.7" text-anchor="end" font-size="10.5" fill="#6b7280">200</text><line x1="64" y1="224.2" x2="544" y2="224.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="227.7" text-anchor="end" font-size="10.5" fill="#6b7280">500</text><line x1="64" y1="188.7" x2="544" y2="188.7" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="192.2" text-anchor="end" font-size="10.5" fill="#6b7280">1,000</text><line x1="64" y1="153.2" x2="544" y2="153.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="156.7" text-anchor="end" font-size="10.5" fill="#6b7280">2,000</text><line x1="64" y1="106.3" x2="544" y2="106.3" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="109.8" text-anchor="end" font-size="10.5" fill="#6b7280">5,000</text><line x1="64" y1="70.8" x2="544" y2="70.8" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="74.3" text-anchor="end" font-size="10.5" fill="#6b7280">10,000</text><line x1="64" y1="35.3" x2="544" y2="35.3" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="38.8" text-anchor="end" font-size="10.5" fill="#6b7280">20,000</text><line x1="77.0" y1="26" x2="77.0" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="77.0" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">200</text><line x1="166.4" y1="26" x2="166.4" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="166.4" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">500</text><line x1="234.0" y1="26" x2="234.0" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="234.0" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">1,000</text><line x1="301.6" y1="26" x2="301.6" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="301.6" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">2,000</text><line x1="391.0" y1="26" x2="391.0" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="391.0" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">5,000</text><line x1="458.6" y1="26" x2="458.6" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="458.6" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">10,000</text><line x1="526.2" y1="26" x2="526.2" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="526.2" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">20,000</text><path d="M64.0,278.0 L544.0,26.0" fill="none" stroke="#6b7280" stroke-width="2.4" stroke-dasharray="5,4" stroke-linejoin="round"/><circle cx="64.0" cy="278.0" r="4.2" fill="#6b7280" stroke="#fff" stroke-width="1.4"/><circle cx="544.0" cy="26.0" r="4.2" fill="#6b7280" stroke="#fff" stroke-width="1.4"/><path d="M98.8,259.9 L166.4,224.4 L234.0,188.8 L301.6,153.3 L369.2,117.9 L436.8,83.7" fill="none" stroke="#dc2626" stroke-width="2.4" stroke-linejoin="round"/><circle cx="98.8" cy="259.9" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="166.4" cy="224.4" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="234.0" cy="188.8" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="301.6" cy="153.3" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="369.2" cy="117.9" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="436.8" cy="83.7" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><path d="M166.4,224.4 L234.0,188.8 L301.6,153.3 L369.2,117.9 L436.8,83.3 L504.5,81.0 L458.6,80.8 L480.4,80.8" fill="none" stroke="#2563eb" stroke-width="2.4" stroke-linejoin="round"/><rect x="162.2" y="220.2" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="229.8" y="184.6" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="297.4" y="149.1" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="365.0" y="113.7" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="432.6" y="79.1" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="500.3" y="76.8" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="454.4" y="76.6" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="476.2" y="76.6" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><text x="436.8" y="100.5" text-anchor="middle" font-size="9.5" font-weight="400" fill="#1e40af">97.2%</text><text x="436.8" y="100.1" text-anchor="middle" font-size="9.5" font-weight="400" fill="#1e40af">98.0%</text><text x="504.5" y="97.8" text-anchor="middle" font-size="9.5" font-weight="400" fill="#1e40af">51.2%</text><text x="458.6" y="97.6" text-anchor="middle" font-size="9.5" font-weight="400" fill="#1e40af">82.3%</text><text x="480.4" y="97.6" text-anchor="middle" font-size="9.5" font-weight="400" fill="#1e40af">65.9%</text><line x1="76" y1="72" x2="98" y2="72" stroke="#6b7280" stroke-width="2.6" stroke-dasharray="5,4"/><circle cx="87" cy="72" r="3.2" fill="#6b7280"/><text x="105" y="75.6" font-size="11" fill="#374151">理想 1:1(设定率)</text><line x1="76" y1="89" x2="98" y2="89" stroke="#dc2626" stroke-width="2.6"/><circle cx="87" cy="89" r="3.2" fill="#dc2626"/><text x="105" y="92.6" font-size="11" fill="#374151">实测循环率 · 带 CAN</text><line x1="76" y1="106" x2="98" y2="106" stroke="#2563eb" stroke-width="2.6"/><circle cx="87" cy="106" r="3.2" fill="#2563eb"/><text x="105" y="109.6" font-size="11" fill="#374151">实测循环率 · 无 CAN</text><text x="70" y="270" text-anchor="start" font-size="10.5" fill="#6b7280">标注为达成率%(&lt;99.5% 才标)。无 CAN 设定 &gt;8kHz 后实测全顶在 ≈8.2kHz —— 硬上限</text><line x1="64" y1="278" x2="544" y2="278" stroke="#9aa3af" stroke-width="1.2"/><line x1="64" y1="26" x2="64" y2="278" stroke="#9aa3af" stroke-width="1.2"/><text x="304" y="314" text-anchor="middle" font-size="11.5" fill="#374151">设定循环率 (Hz,对数)</text><text transform="rotate(-90 14 152)" x="14" y="152" text-anchor="middle" font-size="11.5" fill="#374151">实测循环率 (Hz,对数)</text></svg></div>
<div class="fig"><div class="cap">② 从站每拍负担:带 CAN vs 无 CAN</div><svg viewBox="0 0 620 350" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="从站每拍负担"><line x1="64" y1="308.0" x2="604" y2="308.0" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="311.5" text-anchor="end" font-size="10.5" fill="#6b7280">0</text><line x1="64" y1="245.1" x2="604" y2="245.1" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="248.6" text-anchor="end" font-size="10.5" fill="#6b7280">25.0</text><line x1="64" y1="182.1" x2="604" y2="182.1" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="185.6" text-anchor="end" font-size="10.5" fill="#6b7280">50.0</text><line x1="64" y1="119.2" x2="604" y2="119.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="122.7" text-anchor="end" font-size="10.5" fill="#6b7280">75.0</text><line x1="64" y1="56.2" x2="604" y2="56.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="59.7" text-anchor="end" font-size="10.5" fill="#6b7280">100</text><line x1="73.0" y1="26" x2="73.0" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="73.0" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">200</text><line x1="194.0" y1="26" x2="194.0" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="194.0" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">500</text><line x1="285.7" y1="26" x2="285.7" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="285.7" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">1,000</text><line x1="377.3" y1="26" x2="377.3" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="377.3" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">2,000</text><line x1="498.4" y1="26" x2="498.4" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="498.4" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">5,000</text><line x1="590.0" y1="26" x2="590.0" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="590.0" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">10,000</text><line x1="64" y1="56.2" x2="604" y2="56.2" stroke="#6b7280" stroke-width="1.2" stroke-dasharray="2,4"/><text x="600" y="51.2" text-anchor="end" font-size="10" fill="#6b7280">100%</text><path d="M102.0,257.1 L193.7,236.7 L285.4,196.0 L377.2,114.9 L468.5,57.0 L556.8,58.0" fill="none" stroke="#dc2626" stroke-width="2.4" stroke-linejoin="round"/><circle cx="102.0" cy="257.1" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="193.7" cy="236.7" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="285.4" cy="196.0" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="377.2" cy="114.9" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="468.5" cy="57.0" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="556.8" cy="58.0" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><path d="M193.7,260.2 L285.4,218.9 L377.2,136.8 L468.5,57.7 L557.8,59.2 L563.7,58.7 L564.2,59.0 L564.3,59.0" fill="none" stroke="#2563eb" stroke-width="2.4" stroke-linejoin="round"/><rect x="189.5" y="256.0" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="281.2" y="214.7" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="373.0" y="132.6" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="464.3" y="53.5" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="553.6" y="55.0" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="559.5" y="54.5" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="560.0" y="54.8" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="560.1" y="54.8" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><text x="193.7" y="248.5" text-anchor="middle" font-size="10" font-weight="600" fill="#7c3aed">Δ9.3pp</text><text x="285.4" y="207.4" text-anchor="middle" font-size="10" font-weight="600" fill="#7c3aed">Δ9.1pp</text><text x="377.2" y="125.8" text-anchor="middle" font-size="10" font-weight="600" fill="#7c3aed">Δ8.7pp</text><line x1="76" y1="38" x2="98" y2="38" stroke="#dc2626" stroke-width="2.6"/><circle cx="87" cy="38" r="3.2" fill="#dc2626"/><text x="105" y="41.6" font-size="11" fill="#374151">带 CAN(电机在报 STATUS/CONFIG)</text><line x1="76" y1="55" x2="98" y2="55" stroke="#2563eb" stroke-width="2.6"/><circle cx="87" cy="55" r="3.2" fill="#2563eb"/><text x="105" y="58.6" font-size="11" fill="#374151">拔掉全部 CAN 设备</text><text x="70" y="300" text-anchor="start" font-size="10.5" fill="#6b7280">纵轴是固件 load_perm(只计 ISR+非延迟段,排除 SSC 轮询)—— 不是整机 CPU 占用率</text><text x="70" y="286" text-anchor="start" font-size="10.5" fill="#b45309">无 CAN 补测:0.25/0.125ms 满速;设定再快实测全顶在 ≈8.2kHz。≥4kHz 的负载读数全是饱和值,不能定位拐点</text><text x="70" y="272" text-anchor="start" font-size="10.5" fill="#b45309">带 CAN 的 0.25/0.125ms 两点同理停在 ~99.x% —— 饱和读数不等于&quot;已测到上限&quot;</text><line x1="64" y1="308" x2="604" y2="308" stroke="#9aa3af" stroke-width="1.2"/><line x1="64" y1="26" x2="64" y2="308" stroke="#9aa3af" stroke-width="1.2"/><text x="334" y="344" text-anchor="middle" font-size="11.5" fill="#374151">实测循环率 (Hz,对数)</text><text transform="rotate(-90 14 167)" x="14" y="167" text-anchor="middle" font-size="11.5" fill="#374151">从站 load_perm (%)</text></svg></div>
<div class="fig"><div class="cap">③ CAN 流量分层:STATUS 刷新与 CONFIG 事件流</div><svg viewBox="0 0 620 350" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="CAN 流量分层"><line x1="64" y1="308.0" x2="604" y2="308.0" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="311.5" text-anchor="end" font-size="10.5" fill="#6b7280">10.0</text><line x1="64" y1="282.3" x2="604" y2="282.3" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="285.8" text-anchor="end" font-size="10.5" fill="#6b7280">20.0</text><line x1="64" y1="248.3" x2="604" y2="248.3" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="251.8" text-anchor="end" font-size="10.5" fill="#6b7280">50.0</text><line x1="64" y1="222.6" x2="604" y2="222.6" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="226.1" text-anchor="end" font-size="10.5" fill="#6b7280">100</text><line x1="64" y1="196.9" x2="604" y2="196.9" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="200.4" text-anchor="end" font-size="10.5" fill="#6b7280">200</text><line x1="64" y1="162.9" x2="604" y2="162.9" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="166.4" text-anchor="end" font-size="10.5" fill="#6b7280">500</text><line x1="64" y1="137.1" x2="604" y2="137.1" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="140.6" text-anchor="end" font-size="10.5" fill="#6b7280">1,000</text><line x1="64" y1="111.4" x2="604" y2="111.4" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="114.9" text-anchor="end" font-size="10.5" fill="#6b7280">2,000</text><line x1="64" y1="77.4" x2="604" y2="77.4" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="80.9" text-anchor="end" font-size="10.5" fill="#6b7280">5,000</text><line x1="64" y1="51.7" x2="604" y2="51.7" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="55.2" text-anchor="end" font-size="10.5" fill="#6b7280">10,000</text><line x1="64" y1="26.0" x2="604" y2="26.0" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="29.5" text-anchor="end" font-size="10.5" fill="#6b7280">20,000</text><line x1="73.1" y1="26" x2="73.1" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="73.1" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">200</text><line x1="195.9" y1="26" x2="195.9" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="195.9" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">500</text><line x1="288.8" y1="26" x2="288.8" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="288.8" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">1,000</text><line x1="381.7" y1="26" x2="381.7" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="381.7" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">2,000</text><line x1="504.5" y1="26" x2="504.5" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="504.5" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">5,000</text><line x1="597.4" y1="26" x2="597.4" y2="308" stroke="#eef1f5" stroke-width="1"/><text x="597.4" y="324" text-anchor="middle" font-size="10.5" fill="#6b7280">10,000</text><path d="M102.6,85.8 L195.5,85.8 L288.5,85.8 L381.7,85.8 L474.2,205.3 L563.8,198.9" fill="none" stroke="#16a34a" stroke-width="2.4" stroke-linejoin="round"/><circle cx="102.6" cy="85.8" r="4.2" fill="#16a34a" stroke="#fff" stroke-width="1.4"/><circle cx="195.5" cy="85.8" r="4.2" fill="#16a34a" stroke="#fff" stroke-width="1.4"/><circle cx="288.5" cy="85.8" r="4.2" fill="#16a34a" stroke="#fff" stroke-width="1.4"/><circle cx="381.7" cy="85.8" r="4.2" fill="#16a34a" stroke="#fff" stroke-width="1.4"/><circle cx="474.2" cy="205.3" r="4.2" fill="#16a34a" stroke="#fff" stroke-width="1.4"/><circle cx="563.8" cy="198.9" r="4.2" fill="#16a34a" stroke="#fff" stroke-width="1.4"/><rect x="411.6" y="26" width="171.7" height="282" fill="#ef4444" opacity="0.07"/><text x="333.9" y="74.6" text-anchor="middle" font-size="10" font-weight="400" fill="#166534">带 CAN 轮:STATUS 全流量</text><text x="481.2" y="207.5" text-anchor="middle" font-size="11" font-weight="700" fill="#b91c1c">塌陷</text><line x1="76" y1="38" x2="98" y2="38" stroke="#16a34a" stroke-width="2.6"/><circle cx="87" cy="38" r="3.2" fill="#16a34a"/><text x="105" y="41.6" font-size="11" fill="#374151">CAN 总接收 rx_count ≡ STATUS 刷新 gseq(实测同为 ~4000/s)</text><text x="70" y="300" text-anchor="start" font-size="10.5" fill="#6b7280">CONFIG 事件流独立实测仅约 92 帧/s(去重后),不随周期放大</text><text x="70" y="286" text-anchor="start" font-size="10.5" fill="#b45309">&gt;2kHz 处 STATUS 与 CONFIG 一同塌到 ~150/s</text><line x1="64" y1="308" x2="604" y2="308" stroke="#9aa3af" stroke-width="1.2"/><line x1="64" y1="26" x2="64" y2="308" stroke="#9aa3af" stroke-width="1.2"/><text x="334" y="344" text-anchor="middle" font-size="11.5" fill="#374151">实测循环率 (Hz,对数)</text><text transform="rotate(-90 14 167)" x="14" y="167" text-anchor="middle" font-size="11.5" fill="#374151">帧/s(对数)</text></svg></div>
<div class="fig"><div class="cap">④ 主站错拍率</div><svg viewBox="0 0 560 320" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="主站错拍率"><line x1="64" y1="273.7" x2="544" y2="273.7" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="277.2" text-anchor="end" font-size="10.5" fill="#6b7280">0.10</text><line x1="64" y1="260.2" x2="544" y2="260.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="263.7" text-anchor="end" font-size="10.5" fill="#6b7280">0.20</text><line x1="64" y1="242.4" x2="544" y2="242.4" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="245.9" text-anchor="end" font-size="10.5" fill="#6b7280">0.50</text><line x1="64" y1="229.0" x2="544" y2="229.0" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="232.5" text-anchor="end" font-size="10.5" fill="#6b7280">1</text><line x1="64" y1="215.5" x2="544" y2="215.5" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="219.0" text-anchor="end" font-size="10.5" fill="#6b7280">2</text><line x1="64" y1="197.7" x2="544" y2="197.7" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="201.2" text-anchor="end" font-size="10.5" fill="#6b7280">5</text><line x1="64" y1="184.2" x2="544" y2="184.2" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="187.7" text-anchor="end" font-size="10.5" fill="#6b7280">10.0</text><line x1="64" y1="170.8" x2="544" y2="170.8" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="174.3" text-anchor="end" font-size="10.5" fill="#6b7280">20.0</text><line x1="64" y1="153.0" x2="544" y2="153.0" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="156.5" text-anchor="end" font-size="10.5" fill="#6b7280">50.0</text><line x1="64" y1="139.5" x2="544" y2="139.5" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="143.0" text-anchor="end" font-size="10.5" fill="#6b7280">100</text><line x1="64" y1="126.1" x2="544" y2="126.1" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="129.6" text-anchor="end" font-size="10.5" fill="#6b7280">200</text><line x1="64" y1="108.3" x2="544" y2="108.3" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="111.8" text-anchor="end" font-size="10.5" fill="#6b7280">500</text><line x1="64" y1="94.8" x2="544" y2="94.8" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="98.3" text-anchor="end" font-size="10.5" fill="#6b7280">1,000</text><line x1="64" y1="81.4" x2="544" y2="81.4" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="84.9" text-anchor="end" font-size="10.5" fill="#6b7280">2,000</text><line x1="64" y1="63.6" x2="544" y2="63.6" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="67.1" text-anchor="end" font-size="10.5" fill="#6b7280">5,000</text><line x1="64" y1="50.1" x2="544" y2="50.1" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="53.6" text-anchor="end" font-size="10.5" fill="#6b7280">10,000</text><line x1="64" y1="36.7" x2="544" y2="36.7" stroke="#e8ebf0" stroke-width="1"/><text x="56" y="40.2" text-anchor="end" font-size="10.5" fill="#6b7280">20,000</text><line x1="105.1" y1="20" x2="105.1" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="105.1" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">500</text><line x1="203.2" y1="20" x2="203.2" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="203.2" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">1,000</text><line x1="301.2" y1="20" x2="301.2" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="301.2" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">2,000</text><line x1="430.9" y1="20" x2="430.9" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="430.9" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">5,000</text><line x1="529.0" y1="20" x2="529.0" y2="278" stroke="#eef1f5" stroke-width="1"/><text x="529.0" y="294" text-anchor="middle" font-size="10.5" fill="#6b7280">10,000</text><path d="M104.7,278.0 L202.9,227.1 L301.2,180.9 L398.9,139.8 L493.4,63.2" fill="none" stroke="#dc2626" stroke-width="2.4" stroke-linejoin="round"/><circle cx="104.7" cy="278.0" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="202.9" cy="227.1" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="301.2" cy="180.9" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="398.9" cy="139.8" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><circle cx="493.4" cy="63.2" r="4.2" fill="#dc2626" stroke="#fff" stroke-width="1.4"/><path d="M104.7,278.0 L202.9,239.5 L301.2,173.9 L398.9,157.5 L494.5,64.9 L500.8,41.3 L501.4,50.0 L501.5,46.1" fill="none" stroke="#2563eb" stroke-width="2.4" stroke-linejoin="round"/><rect x="100.5" y="273.8" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="198.7" y="235.3" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="297.0" y="169.7" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="394.7" y="153.3" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="490.3" y="60.7" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="496.6" y="37.1" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="497.2" y="45.8" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><rect x="497.3" y="41.9" width="8.4" height="8.4" fill="#2563eb" stroke="#fff" stroke-width="1.4"/><path d="M2.5,290.0 L6.5,282.0 L10.5,290.0" fill="none" stroke="#dc2626" stroke-width="2"/><line x1="76" y1="32" x2="98" y2="32" stroke="#dc2626" stroke-width="2.6"/><circle cx="87" cy="32" r="3.2" fill="#dc2626"/><text x="105" y="35.6" font-size="11" fill="#374151">带 CAN</text><line x1="76" y1="49" x2="98" y2="49" stroke="#2563eb" stroke-width="2.6"/><circle cx="87" cy="49" r="3.2" fill="#2563eb"/><text x="105" y="52.6" font-size="11" fill="#374151">无 CAN</text><line x1="76" y1="66" x2="98" y2="66" stroke="#9ca3af" stroke-width="2.6"/><circle cx="87" cy="66" r="3.2" fill="#9ca3af"/><text x="105" y="69.6" font-size="11" fill="#374151">▽ = skip ≤0.05 次/s(真 0 档,不在对数刻度上)</text><text x="70" y="268" text-anchor="start" font-size="10.5" fill="#6b7280">skip=错过的网格拍。0.0625ms 设定档 15720 次/s:实测率被钉在 8.2kHz,错拍数随设定率线性涨</text><line x1="64" y1="278" x2="544" y2="278" stroke="#9aa3af" stroke-width="1.2"/><line x1="64" y1="20" x2="64" y2="278" stroke="#9aa3af" stroke-width="1.2"/><text x="304" y="314" text-anchor="middle" font-size="11.5" fill="#374151">实测循环率 (Hz,对数)</text><text transform="rotate(-90 14 149)" x="14" y="149" text-anchor="middle" font-size="11.5" fill="#374151">主站错拍 skip_total (次/s,对数)</text></svg></div>
</div>
<div class="card"><h3>名词解释(表里这几个计数器到底是什么)</h3><ul><li><b>WKC(working counter,工作计数器)</b>:EtherCAT 报文自带一个计数器,每有一个从站硬件处理了该报文就 +1。主站知道自己发出了几个报文,这个应得值就是 <code>expected_wkc</code>(本台子 1 个从站、每拍 3 个报文 → 期望 3)。所以 <code>wkc 3/3</code> = 从站每拍都完整处理了;<code>wkc -1</code> = 整帧没回来(从站停答/掉 OP);<code>wr(watchdog reset)0→1</code> = 看门狗把总线重拉过一次。</li><li><b>主站错拍 skip</b>:主站按周期给自己排了一个"节拍网格"(<code>ecat_native.c:776-791</code>)。每拍做完 EtherCAT 收发后,若发现已经错过了下一个节拍点(甚至错过多个),就把错过的个数累进 <code>skip_total</code>。<b>它量的是"主机软件迟到",不是从站故障</b> —— 1ms 档 1.1 次/s 只是偶发 OS 调度抖动;0.125ms 档 5107 次/s 说明单拍耗时已超过两个周期,主机也在勉强。它不区分"从站慢"和"主机慢"。</li><li><b>在线</b>:电机槽位的 <code>online</code> 标志(槽位数据在超时窗内持续刷新才为 true)。带 CAN 轮显示"未记录"是因为当时脚本还没有这列,<b>不是电机掉线</b>;该轮的电机在线状况另有 8s/档定点实测佐证。</li></ul></div>
<h2>二、数据全表</h2>
<h3>带 CAN(主结论轮)</h3><table><tr><th>周期</th><th>实测Hz</th><th>达成率</th><th>从站load</th><th>CAN接收/s</th><th>skip/s</th><th>wkc</th><th>在线</th></tr><tr><td>4ms</td><td>249</td><td>99.7%</td><td>20.2%</td><td>3,987</td><td>0.02</td><td>3/3</td><td>未记录*</td></tr><tr><td>2ms</td><td>499</td><td>99.7%</td><td>28.3%</td><td>3,990</td><td>0.08</td><td>3/3</td><td>未记录*</td></tr><tr><td>1ms</td><td>998</td><td>99.8%</td><td>44.5%</td><td>3,992</td><td>1.10</td><td>3/3</td><td>未记录*</td></tr><tr class="best"><td>0.5ms</td><td>1,999</td><td>100.0%</td><td>76.7%</td><td>3,995</td><td>11.86</td><td>3/3</td><td>未记录*</td></tr><tr><td>0.25ms</td><td>3,989</td><td>99.7%</td><td>99.7%</td><td>159</td><td>98.61</td><td>3/3</td><td>未记录*</td></tr><tr><td>0.125ms</td><td>7,780</td><td>97.2%</td><td>99.3%</td><td>190</td><td>5,106.62</td><td>3/3</td><td>未记录*</td></tr></table>
<h3>拔掉全部 CAN 设备(补测轮)</h3><table><tr><th>周期</th><th>实测Hz</th><th>达成率</th><th>从站load</th><th>CAN接收/s</th><th>skip/s</th><th>wkc</th><th>在线</th></tr><tr><td>2ms</td><td>499</td><td>99.7%</td><td>19.0%</td><td>0</td><td>0.08</td><td>3/3</td><td>0.00</td></tr><tr><td>1ms</td><td>998</td><td>99.8%</td><td>35.4%</td><td>0</td><td>0.58</td><td>3/3</td><td>0.00</td></tr><tr class="best"><td>0.5ms</td><td>2,000</td><td>100.0%</td><td>68.0%</td><td>0</td><td>17.08</td><td>3/3</td><td>0.00</td></tr><tr><td>0.25ms</td><td>3,988</td><td>99.7%</td><td>99.4%</td><td>0</td><td>39.72</td><td>3/3</td><td>0.00</td></tr><tr><td>0.125ms</td><td>7,839</td><td>98.0%</td><td>98.8%</td><td>0</td><td>4,672.07</td><td>3/3</td><td>0.00</td></tr><tr><td>0.0625ms</td><td>8,196</td><td>51.2%</td><td>99.0%</td><td>0</td><td>15,720.46</td><td>3/3</td><td>0.00</td></tr><tr><td>0.1ms</td><td>8,232</td><td>82.3%</td><td>98.9%</td><td>0</td><td>10,039.19</td><td>3/3</td><td>0.00</td></tr><tr><td>0.08ms</td><td>8,238</td><td>65.9%</td><td>98.9%</td><td>0</td><td>12,282.87</td><td>3/3</td><td>0.00</td></tr></table>
<p class="meta"><b>*</b> 「在线」列是扫描脚本后来才加的(<code>motors_online</code>/<code>online_frac</code>),带 CAN 那轮跑在加列<b>之前</b>,逐档数据没采 —— <b>不是全部掉线</b>。该轮电机在线另有 8s/档定点实测(「电机数据刷新率」表)佐证。</p>
<h3>电机数据刷新率(带 CAN 轮,8s/档定点实测)</h3><table><tr><th>周期</th><th>刷新率 帧/s</th><th>判定</th></tr><tr><td>1ms</td><td>4,000.2</td><td>正常</td></tr><tr><td>0.5ms</td><td>4,000.2</td><td>正常</td></tr><tr><td>0.25ms</td><td>87.9</td><td>塌陷</td></tr><tr><td>0.125ms</td><td>147.5</td><td>塌陷</td></tr></table><p class="meta">这是唯一直接回答"用户还能不能用"的指标 —— λ 与 drop 都是中间量。塌陷两档当场确认 <code>online=True</code>,故为真失效而非掉线。</p>
<h2>三、机理与上限推算</h2>
<div class="card"><h3>上限已实测:≈8.2kHz,墙是单拍 ≈121µs 的硬耗时</h3><p><b>证据链</b>:无 CAN 设定 0.25 → 0.0625ms 五档,实测循环率在 ≤0.125ms (8kHz)前跟随设定,再快就被钉死在 8196–8238Hz;与此同时主站单拍耗时 <code>cyc p50</code> 在<b>所有档位</b>(含 2ms 慢档)恒为 117–126µs,1/121µs ≈ 8.2kHz,与顶墙实测严丝合缝。即:每拍有一段不可压缩的「发送→从站处理→回读+主站处理」往返时间,周期设定小于它时就堵在这里。</p><p><b>排除项</b>:不是主机 CPU 不够 —— 顶墙档主机 CPU 只有 ~85%(自旋等待占比变小);不是从站拒答 —— wkc 全程 3/3。<code>load_perm</code> 在 ≥4kHz 全饱和 99.x%,既定位不了拐点也喂不准模型,早先「两项模型 load=F/T+R → 2.7/3.5kHz」的外推已被满速补测证伪,仅留档。</p><p><b>未闭合的一处</b>:121µs 里主站协议栈与从站 ESC/固件各占多少,本轮数据分不开 —— 需给固件 <code>fillRxWindow</code> 加直接计时(固件改动,需批准)或抓总线帧时序才能归因。</p></div>
<h2>四、判据口径与踩过的坑</h2>
<div class="card warn"><h3>仪表陷阱(每条都实际踩过)</h3><ul><li><b>【本次真正翻车处】把两个同速计数器相除当成比率</b> —— <code>drop</code>/<code>rx_count</code> 都约 4000/s,相除恒得 100%,看着像"全丢",其实只是<b>同速量之比</b>。判丢帧必须有<b>独立</b>的分子与分母:本次真正的独立证据是「STATUS 实测 4001 帧/s 正常刷新」+「CONFIG 事件流去重后仅约 92 帧/s」,两者一起否掉了 100% 丢帧。<b>任何"A/B 比率"指标,先问 A 与 B 是否独立计数。</b></li><li><b>从站停报后 <code>load_perm</code> 保留残值</b> —— 实测 <code>age_ms=214338</code> 时仍报 99.2%。任何取 load_perm 的脚本必须先过 <code>age_ms</code> 闸。<b>扫描脚本已加该闸</b>并新增 <code>gd32_load_samples</code>/<code>gd32_load_stale</code> 两列。</li><li><b><code>load_perm</code> 不是整机 CPU 占用率</b> —— 固件 <code>sys/cpu_load.h</code> 定义收窄为"中断+非延迟处理段",<b>排除</b> SSC MainLoop 轮询;当前 free-run(<code>dc=0</code>)下 PDO 应用走主循环轮询路径、<b>不计入</b>。所以不能把"load→100%"读成"CPU 耗尽"。</li><li><b><code>OVF</code> 每拍被 <code>s_rxWinOvf=0</code> 清零</b> —— GD32 侧没有可用的累计丢帧计数。读它恒 0 <b>不能</b>当"无丢帧"证据(我据此误判 <code>bridge.drop</code> 是死字段,结论已收回)。</li><li><b><code>/api/can/cadence</code> 只存最近 512 拍</b> —— 0.25ms 档 =128ms、0.125ms=64ms,环没装满时取到的 <code>count</code>/<code>lost</code> 是<b>行数</b>不是每拍帧数。对应 CSV 列已从结论排除。</li><li><b>u16 回绕</b>:<code>drop</code> 在 4000/s 下 16 秒绕一圈 → 10Hz 逐次累加 + 取模,单次增量&gt;32768 记为作废。<b>本次作废点数=0</b>。</li><li><b>「seq 值域 − distinct」不是丢帧率</b>:报 99.686%,方向与 drop≈λ 一致但分母含 STATUS 全流量,口径不干净 → 只作旁证。</li><li><b>周期可被 localStorage 劫持</b>(<code>transport-ecat.js:227-228</code>)→ 每档下发后回读校验。本次六档 <code>hijacked=no</code>、native PID 全程 29284 未变。</li><li><b><code>cyc_us.late</code>/<code>lost</code> 恒 0</b>(遗留占位,未接线),未使用。</li></ul></div>
<h2>五、可信度边界</h2>
<div class="card bad"><h3>这份数据不能证明什么</h3><ul><li><b>板载固件版本无法确认</b>:烧写台账 <code>201832b5a8e258d6…</code> 与在盘 .hex 展平哈希(63d6ab9b…、e6a6e75f…)<b>均不匹配</b>,且产物时间戳晚于台账。→ 本报告不复用任何历史固件结论。</li><li>主站在测量期间又重编过(源码 02:39 / exe 02:40,PID 起于 02:32),无法证明运行中的进程就是盘上那份。</li><li><b><code>rx_torn</code> 与 <code>pdo_reentry</code> 整段恒零 = 无检出功效</b>,不是"无撕裂"。二者分别需固件 1.6.6/1.6.7+,版本未知 → 无法区分"没发生"与"字段根本没实现、恒读 0"。</li><li>λ≈3993/s 是本次 CAN 工况。<b>λ 变则负担变</b>,0.5ms 这个数不可外搬到别流量。</li><li>单台单次,未做重复性与温漂验证。</li></ul></div>
<h2>六、下一步</h2>
<div class="card"><h3>按优先级</h3><ul><li><b>查明 <code>drop</code> 口径(当前最高优先,唯一未决的承重项)</b>。必须用<b>一对独立可比</b>的计数,不能再拿同速量相除:从 WiFi 侧读固件 u32 <code>rx_drop_count</code>(<code>app_spi_cmd_can_feedback.cpp:99</code>)对速率,同时用 CAN 监控页统计<b>实收</b> CONFIG 帧数作分母。只有「独立到达计数 − 独立交付计数」才是丢帧数。</li><li><b>台子现状</b>:断电重启后重新 open+start 成功(OP、wkc=3),无 CAN 的 0.25→0.0625ms 五档补测完成,周期已自动恢复 1ms。<b>CAN 设备当前处于拔除状态</b>,电机数据相关指标要插回 CAN 才能再测。</li><li>插回 CAN 后补测 <b>0.35 / 0.4 / 0.5ms</b> 三档的<b>电机数据刷新率</b>,把带 CAN 工况的可用上限定位出来。load_perm 已被证明在快档饱和,<b>不能再用它定位拐点</b>;扫描脚本的 <code>motors_online</code>/<code>online_frac</code>/<code>motor_refresh_per_s</code> 三列才是可用性判据。</li><li>给 <code>fillRxWindow</code> 加直接计时,把 121µs 硬耗时里的主/从占比拆开(属固件改动,需批准)。</li><li>0.5ms 档实跑电机页完整命令序列 —— 本调研只测了计数器,没测界面实际可用性。</li></ul></div>
<div class="foot">本报告由 <code>scripts/build_ecat_report_html.py</code> 从 <code>lab/*.csv</code> 与 <code>lab/ecat_calib.json</code> 现场渲染,图中每个数值均从原始数据计算,未手抄。native 实时:op=1 loop=1 wkc=3 period=1.0ms。Markdown 版(含同源结论):<code>ECAT_RATE_TRADEOFF.md</code>。</div>
</main></body></html>