{"id":577,"date":"2026-10-23T17:23:43","date_gmt":"2026-10-23T09:23:43","guid":{"rendered":"https:\/\/ezblog.cn\/?page_id=577"},"modified":"2026-10-23T17:23:43","modified_gmt":"2026-10-23T09:23:43","slug":"robot-garment-lab%ef%bd%9c%e6%9c%ba%e5%99%a8%e4%ba%ba%e5%85%89%e7%ba%a4%e6%84%9f%e7%9f%a5%e8%a2%96%e5%a5%97%ef%bc%9a%e5%8e%9f%e7%90%86%e4%b8%8e%e7%a1%ac%e4%bb%b6","status":"publish","type":"page","link":"https:\/\/ezblog.cn\/?page_id=577","title":{"rendered":"Robot Garment Lab\uff5c\u673a\u5668\u4eba\u5149\u7ea4\u611f\u77e5\u8896\u5957\uff1a\u539f\u7406\u4e0e\u786c\u4ef6"},"content":{"rendered":"\n<iframe title=\"Robot Garment Lab \u2014 \u673a\u5668\u4eba\u5149\u7ea4\u611f\u77e5\u8896\u5957\uff1a\u539f\u7406\u4e0e\u786c\u4ef6\" sandbox=\"allow-scripts allow-popups allow-popups-to-escape-sandbox\" style=\"display:block;width:100%;height:85vh;min-height:800px;border:1px solid #dce3d6;border-radius:10px;background:#f2f4ed;\" srcdoc=\"&lt;!doctype html&gt;\n&lt;html lang=&quot;zh-CN&quot;&gt;&lt;head&gt;&lt;base href=&quot;about:srcdoc&quot;&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot;&gt;&lt;meta name=&quot;description&quot; content=&quot;\u673a\u5668\u4eba\u5149\u7ea4\u611f\u77e5\u8896\u5957\uff1a\u4fe1\u53f7\u539f\u7406\u3001\u786c\u4ef6\u67b6\u6784\u4e0e\u5173\u952e\u5668\u4ef6\u7684\u9009\u578b\u91cd\u70b9\u3002&quot;&gt;&lt;meta name=&quot;theme-color&quot; content=&quot;#193e3c&quot;&gt;&lt;title&gt;Robot sensing sleeve \u00b7 Principle &amp; Hardware&lt;\/title&gt;&lt;style&gt;:root{--ink:#173b3a;--muted:#6d807a;--green:#19775c;--lime:#dce9bf;--orange:#c37442;--paper:#fffefa;--bg:#f2f4ed;--line:#dce3d6;--blue:#57878e;--mono:Consolas,'SFMono-Regular',monospace}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;color:var(--ink);background:var(--bg);font:14px\/1.65 'Segoe UI','Microsoft YaHei',sans-serif}button,input,select{font:inherit}a{color:inherit;text-decoration:none}button{color:inherit;cursor:pointer}button,a,input,select{touch-action:manipulation}button:focus-visible,a:focus-visible,input:focus-visible,summary:focus-visible,select:focus-visible{outline:3px solid var(--orange);outline-offset:4px}.skip{position:fixed;top:-50px;left:10px;background:#fff;padding:8px 16px;z-index:100}.skip:focus{top:8px}.site-header{height:84px;display:flex;align-items:center;justify-content:space-between;gap:28px;max-width:1280px;margin:auto;padding:0 42px;border-bottom:1px solid var(--line)}.brand{display:flex;align-items:center;gap:12px;font:600 14px\/1.2 var(--mono);letter-spacing:1px;white-space:nowrap}.brand-mark{font:42px\/1 sans-serif;color:var(--green)}.brand small{display:block;font:9px\/1.4 var(--mono);letter-spacing:1.7px;color:#77917c;margin-top:4px}.primary-nav{display:flex;gap:8px;align-items:center}.primary-nav a{padding:10px 17px;border-radius:5px;font-size:12px;color:#75877c}.primary-nav a span{font:9px var(--mono);margin-right:8px;opacity:.7}.primary-nav a.active{background:#e2ebd9;color:#246444;font-weight:600}.primary-nav a:hover{color:var(--green)}.header-download{font:10px var(--mono);color:#68806d;white-space:nowrap}.page{max-width:1196px;padding:34px 0 55px;margin:auto;min-height:calc(100vh - 155px)}.intro{display:flex;align-items:end;justify-content:space-between;gap:24px;margin-bottom:25px}.eyebrow{font:10px var(--mono);color:var(--green);letter-spacing:1.7px;margin:0 0 10px}.intro h1{font-size:32px;line-height:1.3;letter-spacing:-.8px;font-weight:600;margin:0 0 12px}.intro p{font-size:12px;line-height:1.9;max-width:740px;color:var(--muted);margin:0}.badge{display:inline-block;border:1px solid #d7e3cb;border-radius:4px;background:#edf3e5;color:#53784e;font:9px\/1.5 var(--mono);padding:5px 9px;white-space:nowrap}.badge.orange{border-color:#e6d3bf;background:#f9eee1;color:#9a663f}.button{display:inline-flex;justify-content:center;align-items:center;gap:7px;padding:10px 16px;border:1px solid var(--green);background:var(--green);color:white;border-radius:5px;font-size:11px;font-weight:600}.button.secondary{border-color:#c4d3bb;color:#36644b;background:transparent}.button:hover{filter:brightness(.95)}.surface{background:var(--paper);border:1px solid var(--line);border-radius:10px;padding:24px;min-width:0}.surface-head{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:16px}.surface-head h2,.surface-head h3{margin:0;font-size:14px;font-weight:600}.surface-head small{color:#8a9a84;font:9px var(--mono)}.section-head{display:flex;justify-content:space-between;gap:20px;align-items:end;margin:29px 0 15px}.section-head h2{font-size:19px;font-weight:600;margin:0}.section-head p{font-size:11px;color:var(--muted);margin:0}.tabs{display:flex;gap:6px;flex-wrap:wrap}.tabs button{border:1px solid transparent;background:transparent;font:11px var(--mono);padding:8px 14px;border-radius:5px;color:#6c8070}.tabs button.active{border-color:#bed1af;background:#f1f6e8;color:#2f6845}.segmented{display:inline-flex;border-radius:6px;padding:3px;background:#e7eddf;gap:3px}.segmented button{border:0;background:transparent;font:11px var(--mono);padding:8px 14px;border-radius:4px;color:#6c806b}.segmented button.active{background:#fffefa;box-shadow:0 1px 4px #163d2115;color:#276c47}.mechanism-strip{display:flex;gap:12px;align-items:center;flex-wrap:wrap;background:#e9f0df;border:1px solid #d7e3cd;border-radius:7px;padding:14px 20px;margin:20px 0 23px}.mechanism-strip b{font:12px var(--mono);font-weight:600}.mechanism-strip span{color:#97ad83}.mechanism-strip p{margin:0 0 0 auto;font-size:10px;color:#728667}.lab-grid{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);gap:18px}.arm-view{width:100%;display:block;max-height:260px;background:radial-gradient(ellipse at 45% 45%,#edf3e2,#fffefa 74%);border-radius:6px}.arm-view .bone{stroke:#cbd6c6;fill:none;stroke-linecap:round}.arm-view text{font:10px var(--mono);fill:#6e8c72}.arm-view .dotted{stroke:#c6d5bd;stroke-dasharray:4 5;fill:none}.channel-legend{display:flex;flex-wrap:wrap;gap:14px;font:10px var(--mono);color:#6b7f68;margin:6px 0 20px}.channel-legend i{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--green);margin-right:5px}.channel-legend i.bend{background:var(--orange)}.channel-legend i.ref{background:#829a82}.controls{display:grid;grid-template-columns:1fr 1fr;gap:12px 22px}.control label{display:flex;align-items:center;justify-content:space-between;gap:10px;font:11px var(--mono);color:#486e53}.control strong{font-weight:500;white-space:nowrap}.control input[type=range]{width:100%;accent-color:var(--green);margin:10px 0 0;height:18px}.control small{display:block;font-size:10px;color:#8b9a84;line-height:1.6}.presets{display:flex;gap:5px;flex-wrap:wrap;margin:19px 0 0}.presets button{padding:7px 10px;border:1px solid #dce4d3;border-radius:4px;background:#fffefa;font:10px var(--mono)}.presets button.active{border-color:#78a478;background:#edf5e5;color:#286745}.micro-note{font-size:10px;color:#8a9982;line-height:1.9;margin:12px 0 0}.channel-toggle button{padding:5px 10px;font-size:10px}.trace{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:7px;margin-top:15px}.trace-node{min-width:0;text-align:left;border:1px solid #e0e7d9;border-radius:5px;background:#f7f9f1;padding:12px 10px}.trace-node.active{border-color:#78a477;background:#eef5e4}.trace-node small{display:block;color:#839677;font:9px var(--mono)}.trace-node b{display:block;font:19px var(--mono);font-weight:500;color:#386c43;margin:8px 0 3px;overflow-wrap:anywhere}.trace-node em{font:9px var(--mono);font-style:normal;color:#8e9d82}.formula-box{padding:13px 15px;margin-top:13px;border-left:3px solid #b0c79a;background:#f1f6e9;border-radius:0 4px 4px 0}.formula-box code{font:11px\/1.9 var(--mono);color:#396a48;overflow-wrap:anywhere}.formula-box p{margin:5px 0 0;font-size:10px;line-height:1.9;color:#718268}.signal-comparison{margin-top:22px}.signal-comparison h3{font-size:12px;margin:0 0 12px}.bar-row{display:grid;grid-template-columns:94px 1fr 44px;gap:10px;align-items:center;margin:10px 0;font:10px var(--mono);color:#72866d}.bar-track{background:#eff3e8;height:8px;border-radius:3px;overflow:hidden}.bar-track i{display:block;height:100%;background:#6f9971;border-radius:3px;transition:width .15s}.bar-track i.baseline{background:#a5b895}.bar-track i.residual{background:#cc8a51}.bar-row b{font:10px var(--mono);text-align:right}.decision{background:#193e3c;color:#dfebd3;border-radius:7px;padding:15px 18px;margin-top:16px}.decision .decision-top{display:flex;justify-content:space-between;gap:14px;align-items:center}.decision small{font:9px var(--mono);color:#a3c3a7}.decision strong{font:22px var(--mono);color:#d1e6a8;font-weight:500}.decision p{font-size:11px;line-height:1.9;margin:7px 0 0;color:#c0d3bb}.decision.warn{background:#6b512f}.decision.warn strong{color:#f1d8ab}.result-note{font-size:10px;color:#8b9a81;line-height:1.9;margin:10px 0 0}.snapshot-row{display:flex;justify-content:space-between;gap:16px;align-items:center;margin:18px 0 0;border-top:1px solid var(--line);padding-top:15px}.snapshot-row p{margin:0;font-size:11px;color:var(--muted)}.compact-map{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--paper)}.compact-map article{padding:18px 22px;border-right:1px solid var(--line)}.compact-map article:last-child{border:0}.compact-map h3{font:12px var(--mono);font-weight:600;margin:0 0 8px}.compact-map p{font-size:11px;color:var(--muted);line-height:1.9;margin:0}.compact-map code{display:block;font:10px var(--mono);color:#729368;margin-bottom:7px}.details{margin-top:16px;background:#f8faf3;border:1px solid var(--line);border-radius:6px}.details summary{cursor:pointer;padding:14px 18px;font:11px var(--mono);color:#4b7455}.details-body{padding:0 18px 18px;font-size:12px;color:var(--muted)}.details-body p{margin:8px 0;line-height:1.9}.details-body code{font:11px var(--mono);color:#43704c}.details-body a{color:var(--green);text-decoration:underline}.fbg-lab{display:grid;grid-template-columns:290px minmax(0,1fr);gap:25px;align-items:center}.fbg-lab .controls{grid-template-columns:1fr}.spectrum{width:100%;display:block;max-height:160px}.spectrum text{font:10px var(--mono);fill:#839477}.fbg-result{display:flex;gap:12px;align-items:center;flex-wrap:wrap;font:12px var(--mono);margin-top:12px}.fbg-result strong{font-size:18px;color:#376f48}.switch{display:flex;gap:9px;align-items:center;font-size:11px;margin-top:17px}.switch input{accent-color:var(--green)}.build-layout{display:grid;grid-template-columns:minmax(0,1.65fr) minmax(250px,.8fr);gap:18px}.diagram-wrap{min-width:0;overflow:auto}.wiring-svg{width:100%;min-width:650px;display:block}.wiring-svg text{font-family:var(--mono);fill:#426a4b}.wiring-svg .label{font-size:11px}.wiring-svg .minor{font-size:9px;fill:#7f957b}.wiring-svg .box{fill:#f0f6e7;stroke:#c2d4b3}.wiring-svg .module{fill:#fffefa;stroke:#9cbd94}.wiring-svg .wire{stroke:#729b6c;stroke-width:1.6;fill:none}.wiring-svg .power{stroke:#c97f4b;stroke-width:1.6;fill:none}.wiring-svg .digital{stroke:#688e98;stroke-width:1.6;fill:none}.wiring-svg .optical{stroke:#7eac61;stroke-width:3;fill:none;stroke-dasharray:5 4}.wiring-svg .ground{stroke:#77817b;stroke-width:1.2;fill:none}.wiring-svg .highlight{stroke:#bd7e3f;stroke-width:2}.wiring-legend{display:flex;gap:17px;flex-wrap:wrap;font:10px var(--mono);color:var(--muted);margin-top:14px}.wiring-legend i{display:inline-block;width:16px;height:3px;vertical-align:middle;margin-right:6px;background:#729b6c}.wiring-legend .power{background:#c97f4b}.wiring-legend .digital{background:#688e98}.connection-list{display:grid;gap:12px;margin:0}.connection-list dt{font:11px var(--mono);color:#568058;margin-bottom:3px}.connection-list dd{font-size:11px;color:var(--muted);margin:0;line-height:1.85}.notice{background:#eff3e7;border-left:3px solid #a5bf8e;padding:12px 16px;font-size:11px;color:#657c5e;margin-top:16px;border-radius:0 5px 5px 0;line-height:1.9}.notice.orange{border-color:#d69a61;background:#f9eee0;color:#8e6744}.table-wrap{overflow:auto;border:1px solid var(--line);border-radius:7px;background:var(--paper)}table{width:100%;border-collapse:collapse;font-size:11px}th{text-align:left;padding:12px 15px;font:10px var(--mono);font-weight:600;color:#6b8564;background:#eef3e5}td{padding:13px 15px;border-top:1px solid #e4eadb;vertical-align:top;line-height:1.9}td small{display:block;color:#8a9b80;font-size:10px}td a{color:var(--green);text-decoration:underline}td b{font-weight:600}.step-rail{display:grid;gap:8px;margin-bottom:16px}.step-rail button{text-align:left;border:1px solid #dde6d4;background:#f8faf3;border-radius:5px;padding:12px 14px;font-size:12px}.step-rail button.active{border-color:#88a97a;background:#edf5e2}.step-rail span{font:10px var(--mono);color:#79956d;margin-right:10px}.placement{width:100%;display:block;max-height:385px}.placement text{font:11px var(--mono);fill:#4e7551}.assembly-note h3{font-size:14px;margin:10px 0}.assembly-note p{font-size:12px;line-height:1.95;color:var(--muted)}.part-tabs{margin:6px 0 20px}.bom-table{min-width:650px}.calibration-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:18px}.procedure{list-style:none;margin:0;padding:0;counter-reset:procedure}.procedure li{padding:0 0 20px 37px;position:relative;counter-increment:procedure}.procedure li:before{content:counter(procedure,decimal-leading-zero);position:absolute;top:1px;left:0;font:11px var(--mono);color:#7ba064}.procedure h3{font:600 12px var(--mono);margin:0 0 5px}.procedure p{font-size:11px;margin:0;color:var(--muted);line-height:1.9}.cal-equation{background:#183f3b;border-radius:7px;color:#cce0c0;padding:20px}.cal-equation small{font:9px var(--mono);color:#93b494}.cal-equation code{display:block;font:12px\/2 var(--mono);margin-top:9px;overflow-wrap:anywhere}.cal-equation p{font-size:11px;color:#acc8a8;line-height:1.9;margin:11px 0 0}.checks{display:grid;gap:8px;margin-top:17px}.checks label{display:flex;gap:9px;align-items:start;font-size:11px;color:var(--muted);padding:10px 12px;background:#f8faf3;border:1px solid #e2e9d9;border-radius:4px}.checks input{accent-color:var(--green);margin-top:3px}.download-actions{display:flex;gap:9px;flex-wrap:wrap;margin-top:18px}.source-row{display:flex;flex-wrap:wrap;gap:10px 20px;margin-top:12px}.source-row a{font:10px var(--mono);color:#749166;text-decoration:underline;text-underline-offset:3px}.site-footer{max-width:1196px;margin:auto;padding:20px 0;border-top:1px solid var(--line);font:9px var(--mono);color:#8b9c7d;display:flex;align-items:center;justify-content:space-between;gap:16px}.site-footer a{color:#68885d}.toast{position:fixed;bottom:22px;left:50%;transform:translate(-50%,20px);background:#193e3c;color:#e3efda;font-size:12px;padding:11px 18px;border-radius:5px;opacity:0;pointer-events:none;transition:.15s;z-index:99}.toast.visible{opacity:1;transform:translate(-50%,0)}\n@media(max-width:1280px){.page,.site-footer{margin-left:34px;margin-right:34px}.site-header{padding:0 34px}.trace-node b{font-size:17px}.intro h1{font-size:29px}}\n@media(max-width:1000px){.lab-grid{grid-template-columns:1fr 1fr}.surface{padding:19px}.trace{grid-template-columns:repeat(2,minmax(0,1fr))}.arm-view{max-height:240px}.controls{grid-template-columns:1fr}.build-layout,.calibration-grid{grid-template-columns:1fr}.build-layout .step-rail{grid-template-columns:repeat(4,1fr)}.build-layout .step-rail button{font-size:10px;padding:10px}.intro h1{font-size:27px}.header-download{display:none}.primary-nav a{padding:9px 12px}.primary-nav a span{display:none}.fbg-lab{grid-template-columns:220px minmax(0,1fr)}.mechanism-strip p{width:100%;margin:0}.compact-map article{padding:16px}.compact-map h3{font-size:11px}.snapshot-row{align-items:start;flex-direction:column}}\n@media(max-width:700px){.site-header{height:auto;padding:19px 18px 13px;flex-wrap:wrap;gap:17px}.brand{font-size:13px}.brand-mark{font-size:32px}.primary-nav{width:100%;justify-content:space-between;gap:5px}.primary-nav a{flex:1;text-align:center;padding:9px 8px;font-size:11px}.page{padding-top:26px;margin:0 18px}.intro{align-items:start;flex-direction:column;gap:13px;margin-bottom:18px}.intro h1{font-size:26px}.intro p{font-size:11px}.lab-grid{grid-template-columns:1fr}.controls{grid-template-columns:1fr 1fr}.trace{grid-template-columns:repeat(4,minmax(0,1fr))}.mechanism-strip{gap:9px;padding:13px 15px;margin:17px 0}.mechanism-strip b{font-size:10px}.compact-map{grid-template-columns:1fr}.compact-map article{border-right:0;border-bottom:1px solid var(--line);padding:15px 18px}.section-head{align-items:start;flex-direction:column;gap:5px}.section-head h2{font-size:18px}.fbg-lab{grid-template-columns:1fr;gap:18px}.fbg-lab .controls{grid-template-columns:1fr 1fr}.site-footer{margin:0 18px;flex-wrap:wrap;font-size:8px}.build-layout .step-rail{grid-template-columns:1fr 1fr}.surface-head small{font-size:8px}.toast{left:18px;right:18px;transform:translateY(20px);text-align:center}.toast.visible{transform:translateY(0)}}\n@media(max-width:420px){.surface{padding:17px}.trace{grid-template-columns:repeat(2,minmax(0,1fr))}.trace-node b{font-size:20px}.intro h1{font-size:24px}.controls{gap:13px}.control label{font-size:10px}.fbg-lab .controls{grid-template-columns:1fr}.brand{font-size:12px}.primary-nav a{font-size:10px}.decision .decision-top{gap:8px}.decision strong{font-size:20px}.bar-row{grid-template-columns:85px 1fr 40px}}\n@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto;transition:none!important}}\n.build-layout&gt;*{min-width:0}.table-wrap{max-width:100%}.diagram-wrap{max-width:100%}\n.site-header{height:64px}\n.architecture-card{padding:20px 24px}.architecture-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}.architecture-heading h2{font:600 13px var(--mono);margin:0}.signal-key{display:flex;gap:16px;font:9px var(--mono);color:#80917a}.signal-key span:before{content:'';display:inline-block;width:6px;height:6px;border-radius:50%;background:#719289;margin-right:5px}.signal-key span:nth-child(2):before{background:#9aaa68}.signal-key span:nth-child(3):before{background:#7d96aa}.support-branch{display:flex;align-items:center;gap:12px;font:10px var(--mono);color:#8a977c;min-width:0}.support-line{flex:1;border-top:1px dashed #b9c5b0;min-width:15px;position:relative}.support-line:after{content:'\u203a';position:absolute;right:-1px;top:-10px;color:#8ca082}.aux-block{display:flex;align-items:center;gap:8px;flex:none;border:1px solid #d9e2d0;background:#f7f9f1;border-radius:5px;padding:5px 12px;min-height:37px}.aux-block strong{font:600 10px var(--mono);color:#6e8668}.aux-block .block-icon{width:27px;height:22px}.flow-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-template-rows:repeat(2,auto);gap:24px 32px;margin:20px 0}.flow-block{grid-column:var(--col);grid-row:var(--row);position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;border:1px solid #cedccc;background:#f5f8ef;border-radius:7px;min-width:0;min-height:91px;padding:10px 8px}.flow-block.optical{background:#f3f6e8;border-color:#d4dfc0}.flow-block.digital{background:#f0f5f3;border-color:#cfdddd}.flow-block strong{font:600 12px var(--mono);letter-spacing:.2px;color:#41694e}.flow-block small{font:8px var(--mono);color:#91a080}.flow-block.is-selected,.aux-block.is-selected{background:#e5f0da;border-color:#5b9270;box-shadow:0 0 0 2px #5b927015}.flow-block.is-selected strong,.aux-block.is-selected strong{color:#216746}.block-icon{width:46px;height:29px;display:block;fill:none;stroke:#739878;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.block-icon .faint{opacity:.3}.block-icon text{stroke:none;fill:#739878;font:16px var(--mono)}.flow-block.is-selected .block-icon{stroke:#25734c}.flow-link{position:absolute;pointer-events:none;font:19px var(--mono);color:#a2b49a;z-index:1}.flow-link.right{left:100%;width:32px;top:calc(50% - 12px);text-align:center}.flow-link.left{right:100%;width:32px;top:calc(50% - 12px);text-align:center}.flow-link.down{left:calc(50% - 12px);width:24px;top:100%;height:24px;line-height:24px}.aux-row{display:flex;align-items:center;justify-content:space-between;gap:24px}.encoder-branch{flex:1}.control-caption{font:9px var(--mono);color:#8d9e82;white-space:nowrap}.hardware-inspector{margin-top:18px;padding:22px 24px;scroll-margin-top:15px}.inspector-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:17px}.inspector-heading .eyebrow{display:block;font-size:8px;margin-bottom:5px}.inspector-heading h2{margin:0;font:600 19px var(--mono)}.concept-tag{font:8px var(--mono);color:#90a080;letter-spacing:.8px}.io-flow{display:grid;grid-template-columns:minmax(0,1fr) 150px minmax(0,1fr);gap:15px;align-items:center}.io-card{min-width:0;background:#f4f7ed;border:1px solid #e0e8d6;border-radius:6px;padding:12px 13px 3px}.io-card&gt;small{font:8px var(--mono);letter-spacing:.8px;color:#8da47f}.io-card h3{font:500 11px var(--mono);margin:4px 0 0;color:#4c7051}.io-card.output{background:#eff5e7;border-color:#d3e2c4}.conversion-card{text-align:center;color:#56805a;min-width:0}.conversion-card .block-icon{width:47px;height:32px;margin:0 auto 8px}.conversion-card strong{display:block;font:500 10px\/1.6 var(--mono)}.conversion-arrow{display:block;font:24px var(--mono);color:#89a57a;margin:2px 0}.conversion-card code{font:9px\/1.5 var(--mono);color:#8c9e7f;overflow-wrap:anywhere}.wave-plot{width:100%;display:block}.wave-axis{fill:none;stroke:#d4dfc7;stroke-width:1}.wave-grid{fill:none;stroke:#e0e8d7;stroke-width:1;stroke-dasharray:3 5}.wave-line{fill:none;stroke:#367c53;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}.wave-ghost{fill:none;stroke:#bdc9b1;stroke-width:1.3;stroke-dasharray:3 3}.wave-limit{stroke:#bca47c;stroke-width:1;stroke-dasharray:4 3}.wave-label{font:9px var(--mono);fill:#87997b}.wave-limit-label,.ghost-label{font:7.8px var(--mono);fill:#9aa88e}.wave-limit-label{fill:#a9916b}.clipped .wave-line{stroke:#bd7044}.clipped .wave-limit{stroke:#bd7044}.sample-stem{stroke:#93ad7e;stroke-width:.8;opacity:.5}.sample-dot{fill:#3b7852}.effect-row{display:grid;grid-template-columns:170px minmax(80px,1fr) auto 150px;align-items:center;gap:15px;margin:17px 0 18px}.effect-row label{font:11px var(--mono);color:#4a7152}.effect-row label span{display:block;font-size:9px;color:#94a087;margin-top:4px}.effect-row input{accent-color:var(--green);width:100%;margin:0}.reset-effect{font:9px var(--mono);border:1px solid #cfdcc3;border-radius:4px;background:#fffefa;padding:5px 9px}.effect-status{font:9px\/1.6 var(--mono);text-align:right;color:#7c9570}.effect-status.clipping{color:#b47343}.metric-pair{display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--line);border-bottom:1px solid var(--line);gap:18px;padding:13px 0}.metric-pair article{display:flex;gap:12px;align-items:start}.metric-pair article&gt;span{font:9px var(--mono);color:#9ab08b;padding-top:2px}.metric-pair h3{font:600 11px var(--mono);margin:0 0 4px;color:#446e4d}.metric-pair p{font-size:10px;color:#829278;line-height:1.8;margin:0}.hardware-note{font-size:11px;color:#6b8260;margin:12px 0 0;line-height:1.9}.axis-note{font-size:9px;color:#a2ae96;margin:5px 0 0;line-height:1.8}\n@media(max-width:1000px){.io-flow{grid-template-columns:minmax(0,1fr) 108px minmax(0,1fr);gap:12px}.effect-row{grid-template-columns:145px minmax(70px,1fr) auto 128px;gap:12px}.flow-block small{font-size:7px}.architecture-card,.hardware-inspector{padding:18px}.flow-block strong{font-size:11px}}\n@media(max-width:700px){.architecture-heading{align-items:start}.signal-key{font-size:8px;gap:8px}.flow-grid{grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:repeat(4,auto);gap:23px 30px;margin:17px 0}.flow-block:nth-child(1){grid-column:1;grid-row:1}.flow-block:nth-child(2){grid-column:2;grid-row:1}.flow-block:nth-child(3){grid-column:2;grid-row:2}.flow-block:nth-child(4){grid-column:1;grid-row:2}.flow-block:nth-child(5){grid-column:1;grid-row:3}.flow-block:nth-child(6){grid-column:2;grid-row:3}.flow-block:nth-child(7){grid-column:2;grid-row:4}.flow-block:nth-child(8){grid-column:1;grid-row:4}.flow-block{min-height:78px;padding:8px 5px}.flow-block strong{font-size:10px}.flow-block small{font-size:7px}.flow-block:nth-child(2) .flow-link,.flow-block:nth-child(4) .flow-link,.flow-block:nth-child(6) .flow-link{left:calc(50% - 12px);right:auto;top:100%;width:24px;height:23px;line-height:23px;font-size:0}.flow-block:nth-child(2) .flow-link:after,.flow-block:nth-child(4) .flow-link:after,.flow-block:nth-child(6) .flow-link:after{content:'\u2193';font:18px\/23px var(--mono)}.flow-block:nth-child(3) .flow-link{left:auto;right:100%;top:calc(50% - 12px);width:30px;font-size:0}.flow-block:nth-child(3) .flow-link:after{content:'\u2190';font:18px var(--mono)}.flow-block:nth-child(5) .flow-link{right:auto;left:100%;top:calc(50% - 12px);width:30px;font-size:0}.flow-block:nth-child(5) .flow-link:after{content:'\u2192';font:18px var(--mono)}.aux-row{display:block}.control-caption{display:block;margin:12px 0 0;font-size:8px;text-align:right}.support-branch{gap:9px;font-size:8px}.aux-block{padding:4px 8px;min-height:32px}.aux-block strong{font-size:9px}.aux-block .block-icon{width:22px}.io-flow{grid-template-columns:1fr 1fr;gap:10px}.conversion-card{grid-column:1\/-1;grid-row:1;display:flex;align-items:center;justify-content:center;gap:10px;padding-bottom:8px}.conversion-card .block-icon{margin:0;width:32px;height:22px}.conversion-card strong{font-size:9px}.conversion-card code{font-size:8px;max-width:120px}.conversion-arrow{font-size:20px;margin:0}.io-card{padding:10px 9px 3px}.io-card h3{font-size:9px;min-height:28px;line-height:1.5}.inspector-heading h2{font-size:17px}.concept-tag{font-size:7px;max-width:110px;text-align:right}.effect-row{grid-template-columns:1fr auto;gap:9px;margin:14px 0}.effect-row label{grid-column:1;grid-row:1;font-size:10px}.effect-row input{grid-column:1;grid-row:2}.reset-effect{grid-column:2;grid-row:2}.effect-status{grid-column:2;grid-row:1;font-size:8px;max-width:125px}.metric-pair{gap:14px}.metric-pair article{gap:6px}.metric-pair h3{font-size:10px}.metric-pair p{font-size:9px}.hardware-note{font-size:10px}.axis-note{font-size:8px}}\n.priority-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:7px;overflow:hidden}.priority-strip&gt;div{padding:16px 18px;background:#eaf1df;min-width:0}.priority-strip small{display:block;color:#7d9471;font:9px var(--mono);letter-spacing:.5px}.priority-strip b{display:block;font:600 14px var(--mono);margin:7px 0;color:#3c6b49}.priority-strip span{font-size:10px;color:#7d8c75}.selection-layout{display:grid;grid-template-columns:285px minmax(0,1fr);gap:18px;align-items:start}.component-menu{display:grid;gap:6px}.component-menu button{position:relative;text-align:left;border:1px solid var(--line);background:#f9faf5;border-radius:5px;padding:10px 13px;min-width:0}.component-menu button.active{border-color:#679c78;background:#eaf3e1;box-shadow:inset 3px 0 #568f64}.component-menu small{display:block;font:8px var(--mono);color:#8b9c7e;letter-spacing:.8px}.component-menu b{display:block;font:600 11px\/1.5 var(--mono);margin:3px 0;color:#436e4e;overflow-wrap:anywhere}.component-menu span{display:block;font:9px\/1.5 var(--mono);color:#8a977d}.component-detail{position:sticky;top:18px}.component-detail .surface-head h2{font:600 16px\/1.4 var(--mono)}.priority-focus{border-radius:5px;padding:14px 16px;background:#193e3c;color:#d6e7be}.priority-focus small{display:block;font:9px var(--mono);color:#9ebe9f;margin-bottom:7px}.priority-focus strong{font:500 15px\/1.6 var(--mono)}.component-role{font-size:12px;line-height:1.95;margin:17px 0 7px}.component-why{font-size:12px;line-height:1.95;color:#73846b;margin:0 0 19px}.metric-list{gap:15px}.metric-list dt{font-size:12px;font-weight:600}.metric-list dd{font-size:12px}.component-detail .notice{font-size:12px}.component-detail .source-row a{font-size:10px}.bom-table td:last-child{font:10px\/1.9 var(--mono);color:#597b56}\n@media(max-width:1000px){.selection-layout{grid-template-columns:240px minmax(0,1fr)}.priority-strip&gt;div{padding:13px}.priority-strip b{font-size:12px}.component-detail{position:static}.component-detail .surface-head{align-items:start}.component-detail .surface-head h2{font-size:14px}}\n@media(max-width:700px){.priority-strip{grid-template-columns:1fr 1fr}.selection-layout{grid-template-columns:1fr}.component-menu{grid-template-columns:1fr 1fr}.component-menu b{font-size:10px}.component-menu span{font-size:8px}.component-menu button{padding:10px}.priority-strip b{font-size:13px}.component-detail .surface-head h2{font-size:16px}.part-tabs{gap:2px}.part-tabs button{padding:8px 9px;font-size:10px}}\n\/* Signal quality: relative controls and a shared time axis. *\/\n.signal-lab{padding:24px;margin:24px 0 22px}.quality-heading,.quality-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px}.quality-heading h2{font-size:23px;line-height:1.4;margin:0;font-weight:600}.quality-heading .eyebrow{font-size:9px;margin-bottom:6px}.quality-toolbar{margin:20px 0}.quality-scenes button{font-size:10px;padding:7px 13px}.quality-unit{font:8px var(--mono);color:#87967f;letter-spacing:.4px}.quality-grid{display:grid;grid-template-columns:220px minmax(0,1fr);gap:26px}.quality-controls{border-right:1px solid var(--line);padding-right:24px;min-width:0}.quality-control{padding:14px 0 16px;border-bottom:1px solid var(--line)}.quality-control:first-child{padding-top:0}.quality-control-head{display:flex;align-items:center;gap:10px;margin-bottom:11px}.quality-control-head svg{width:36px;height:28px;flex:none;stroke:#76a080;stroke-width:1.5;fill:none;stroke-linecap:round;stroke-linejoin:round}.quality-control-head label{flex:1;min-width:0}.quality-control-head b{display:block;font:600 12px var(--mono)}.quality-control-head label span{display:block;font-size:9px;color:var(--muted);margin-top:3px}.quality-control-head output{font:9px var(--mono);color:#497957;white-space:nowrap}.quality-control input{width:100%;margin:0;accent-color:var(--green);display:block}.quality-range-labels{display:flex;justify-content:space-between;font:8px var(--mono);color:#93a18a;margin-top:5px}.quality-switches{display:grid;gap:13px;padding-top:18px}.quality-switches label{display:flex;gap:8px;align-items:start;font:10px var(--mono);cursor:pointer}.quality-switches input{accent-color:var(--green);margin:1px 0 0}.quality-switches small{display:block;font:9px\/1.6 'Segoe UI','Microsoft YaHei',sans-serif;color:#87967c;margin-top:4px}.quality-display{min-width:0}.quality-flow{display:flex;align-items:center;justify-content:space-between;gap:7px;font:8px\/1.7 var(--mono);color:#6c876c;background:#f0f5e9;padding:8px 10px;border-radius:4px;margin-bottom:17px}.quality-flow i{font-style:normal;color:#a0af91}.quality-plot-head{display:flex;justify-content:space-between;align-items:center;gap:10px}.quality-plot-head h3{font:600 11px var(--mono);margin:0}.quality-plot-head&gt;div{display:flex;flex-wrap:wrap;gap:12px}.quality-key{font:8px var(--mono);color:#84957b;white-space:nowrap}.quality-key:before{content:'';display:inline-block;width:13px;vertical-align:middle;border-top:2px solid #388664;margin-right:5px}.quality-key.ideal:before{border-top:2px dashed #9aaa9c}.quality-key.baseline:before{border-top:2px dotted #759da3}.quality-key.false:before{border-color:#c86b56}.quality-key.miss:before{height:7px;border:0;background:repeating-linear-gradient(-45deg,#f8e6c5 0px,#f8e6c5 2px,#bd8c44 2px,#bd8c44 3px)}.quality-equation{font:8px\/1.6 var(--mono);color:#8c987d;text-align:right}.quality-wave,.quality-decision{width:100%;display:block;overflow:visible}.quality-wave{margin:5px 0 13px}.quality-decision{margin:6px 0 11px}.quality-wave path{fill:none;stroke-linejoin:round;stroke-linecap:round}.quality-axis{stroke:#d6dfcf;stroke-width:1}.quality-grid-line{stroke:#e4e9df;stroke-dasharray:3 5;stroke-width:1}.quality-measured{stroke:#24805e;stroke-width:2.2}.quality-ideal{stroke:#95a497;stroke-dasharray:5 4;stroke-width:1.5}.quality-baseline{stroke:#719da3;stroke-width:1.5;stroke-dasharray:2 4}.quality-residual{stroke:#bf7b47;stroke-width:2}.quality-threshold{stroke:#b99979;stroke-width:1;stroke-dasharray:5 4}.quality-svg-label{font:9px var(--mono);fill:#99a18d}.quality-contact-label{font:9px var(--mono);fill:#7d9a6c}.quality-contact-window{fill:#e8f0dc;opacity:.7}.quality-lane{fill:#eef1e7}.quality-hit{fill:#6e9b72}.quality-false-fill{fill:#c86b56}.quality-miss-fill{fill:url(#quality-miss-hatch)}.quality-verdict{display:flex;gap:20px;align-items:start;min-height:39px}.quality-verdict&gt;span{display:block;min-width:0;padding-left:9px;border-left:2px solid #92ad83}.quality-verdict b{display:block;font:10px var(--mono);color:#577b50}.quality-verdict small{display:block;font-size:9px;color:#90a082;margin-top:3px;line-height:1.5}.quality-verdict .bad{border-color:#c87960}.quality-verdict .bad b{color:#ae6853}.quality-verdict .warn{border-color:#caa069}.quality-verdict .warn b{color:#a7834f}.quality-verdict .neutral{border-color:#b1bca4}.quality-insights{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;border-top:1px solid var(--line);margin-top:24px;padding-top:15px}.quality-insights b{display:block;font:600 10px var(--mono);color:#63865c;margin-bottom:5px}.quality-insights span{font-size:10px;color:#89977f;line-height:1.8}.signal-lab&gt;.axis-note{margin-top:13px}.quality-sources{margin-top:9px}.quality-sources summary{font:9px var(--mono);color:#84947a;cursor:pointer}.quality-sources p{font-size:10px;color:var(--muted);line-height:1.9;max-width:850px}.quality-sources .source-row a{font-size:9px}\n@media(max-width:1000px){.signal-lab{padding:20px}.quality-grid{grid-template-columns:185px minmax(0,1fr);gap:19px}.quality-controls{padding-right:18px}.quality-control-head{gap:7px}.quality-control-head svg{width:28px}.quality-control-head b{font-size:11px}.quality-control-head output{font-size:8px}.quality-heading h2{font-size:21px}.quality-plot-head&gt;div{gap:8px}.quality-key{font-size:7px}.quality-key:before{width:9px;margin-right:3px}.quality-flow{font-size:7px;padding:7px}.quality-insights{gap:12px}.quality-verdict{gap:12px}.quality-verdict b{font-size:9px}.quality-verdict small{font-size:8px}.quality-equation{font-size:7px}}\n@media(max-width:700px){.signal-lab{padding:17px}.quality-heading h2{font-size:19px}.quality-heading .eyebrow{font-size:7px}.quality-toolbar{align-items:start;flex-direction:column;gap:9px;margin:16px 0}.quality-scenes{width:100%;display:flex}.quality-scenes button{flex:1;padding:7px 8px;font-size:9px}.quality-unit{font-size:7px}.quality-grid{grid-template-columns:1fr;gap:20px}.quality-controls{display:grid;grid-template-columns:1fr 1fr;gap:12px 17px;padding-right:0;border-right:0}.quality-control,.quality-control:first-child{padding:0 0 10px}.quality-control-head svg{display:none}.quality-control-head b{font-size:11px}.quality-control-head output{font-size:8px}.quality-control-head label span{font-size:8px}.quality-control input{min-height:18px}.quality-range-labels{font-size:7px}.quality-switches{grid-column:1\/-1;grid-template-columns:1fr 1fr;padding-top:1px;gap:12px}.quality-switches label{font-size:9px;gap:6px}.quality-switches small{font-size:8px}.quality-flow{font-size:6.5px;gap:5px;margin-bottom:13px}.quality-plot-head h3{font-size:10px}.quality-plot-head&gt;div{gap:6px}.quality-key{font-size:6.5px}.quality-equation{font-size:6px}.quality-wave{margin-bottom:12px}.quality-insights{grid-template-columns:1fr 1fr;gap:12px;margin-top:19px;padding-top:13px}.quality-insights span{font-size:9px}.quality-verdict{gap:10px}.quality-verdict&gt;span{padding-left:6px}.quality-verdict b{font-size:8px}.quality-verdict small{font-size:8px}.quality-sources .source-row a{font-size:8px}}\n\/* Keep chart labels legible when the shared time axis scales down. *\/\n.quality-svg-label,.quality-contact-label{font-size:12px}.quality-key{font-size:9px}.quality-flow{font-size:9px}.quality-equation{font-size:9px}.quality-control-head output{font-size:10px}.quality-range-labels{font-size:9px}.quality-verdict b{font-size:11px}.quality-verdict small{font-size:10px}\n@media(max-width:1000px){.quality-key,.quality-flow,.quality-equation{font-size:8px}.quality-control-head output{font-size:9px}.quality-verdict b{font-size:10px}.quality-verdict small{font-size:9px}}\n@media(max-width:700px){.quality-key,.quality-flow,.quality-equation{font-size:8px}.quality-svg-label,.quality-contact-label{font-size:18px}.quality-range-labels{font-size:8px}.quality-verdict b{font-size:9px}.quality-verdict small{font-size:9px}.quality-control-head output{font-size:9px}.quality-plot-head{align-items:start}.quality-plot-head&gt;div{justify-content:flex-end}.quality-flow{line-height:1.9;text-align:center}.quality-verdict{flex-wrap:wrap}}\n\/* Hardware source -&gt; equivalent readout effects. *\/\n.quality-hardware-tabs{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:21px 0 10px}.quality-hardware-tabs button{display:grid;grid-template-columns:32px 1fr;align-items:center;gap:3px 9px;text-align:left;padding:12px;background:#f6f8ef;border:1px solid #dce5d2;border-radius:6px;min-width:0}.quality-hardware-tabs .block-icon{width:30px;height:25px;grid-row:1\/3}.quality-hardware-tabs strong{font:600 11px var(--mono)}.quality-hardware-tabs small{font:8px var(--mono);color:#819775;white-space:nowrap}.quality-hardware-tabs button[aria-pressed=true]{background:#e9f1dd;border-color:#79a16b}.quality-hardware-hint{font-size:10px;color:#8c9c80;margin:8px 0 0}.linked-context{margin-top:16px;border:1px solid #dce6d1;border-radius:7px;background:#f7f9f1;overflow:hidden}.linked-route{display:flex;align-items:center;justify-content:center;gap:15px;font:10px var(--mono);padding:10px 13px;background:#edf3e3;color:#6e8566}.linked-route b{color:#326449;font-size:12px}.linked-route i{font-style:normal;color:#95a981}.linked-body{padding:13px 15px;display:grid;grid-template-columns:1fr 1fr;gap:22px;align-items:center}.linked-label{font:8px var(--mono);color:#8b9d80}.linked-effects{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}.linked-effects button{font:10px var(--mono);border:1px solid #d7e1cd;background:#fffefa;border-radius:4px;padding:5px 8px;color:#85927b}.linked-effects button.primary-impact{color:#4b7653;border-color:#b7cba7}.linked-effects button[aria-pressed=true]{color:white;background:#3c7b56;border-color:#3c7b56}.linked-effects i{font-size:5px;font-style:normal;vertical-align:middle;margin-left:4px}.linked-priorities{display:grid;grid-template-columns:1fr 1fr;gap:16px}.linked-priorities small{display:block;font:7px var(--mono);letter-spacing:.5px;color:#95a783}.linked-priorities b{display:block;font:600 11px\/1.5 var(--mono);margin:3px 0;color:#416b47}.linked-priorities span{display:block;font-size:9px;color:#8b9b7e;line-height:1.7}.linked-explanation{display:flex;align-items:center;gap:14px;padding:10px 15px;background:#eaf1e1;flex-wrap:wrap}.linked-explanation strong{font:600 10px var(--mono);color:#3c704c}.linked-explanation span{font:9px\/1.8 var(--mono);color:#75896b;flex:1}.linked-explanation small{font:7px var(--mono);color:#98a68d;white-space:nowrap}.linked-note{font-size:9px;color:#8c9c7f;margin:0;padding:9px 15px;line-height:1.7}.quality-control.is-priority label b:after{content:'\u25cf';font-size:6px;color:#80a463;vertical-align:middle;margin-left:6px}.linked-hardware-inspector&gt;.signal-lab{margin-top:18px}.linked-hardware-inspector .quality-insights{display:none}.linked-hardware-inspector .signal-lab&gt;.axis-note{margin-top:18px}.block-effects{font:7.5px var(--mono);color:#78996c;font-style:normal;padding:2px 6px;border-radius:3px;background:#eaf1df;margin-top:2px}.aux-block .block-effects{margin:0 0 0 4px}.conversion-detail .details-body{padding:20px}.linked-hardware-inspector{scroll-margin-top:18px}\n@media(max-width:1000px){.quality-hardware-tabs{gap:7px}.quality-hardware-tabs button{padding:9px;grid-template-columns:23px 1fr;gap:3px 6px}.quality-hardware-tabs .block-icon{width:23px}.quality-hardware-tabs strong{font-size:10px}.quality-hardware-tabs small{font-size:7px}.linked-body{gap:15px}.linked-priorities{gap:10px}.linked-priorities b{font-size:10px}.linked-explanation{gap:8px}.linked-explanation span{font-size:8px}}\n@media(max-width:700px){.quality-hardware-tabs{grid-template-columns:1fr 1fr;margin-top:16px}.quality-hardware-tabs button{padding:10px}.quality-hardware-tabs small{font-size:8px}.linked-body{grid-template-columns:1fr;gap:14px;padding:12px}.linked-route{gap:8px;font-size:8px;padding:10px;flex-wrap:wrap}.linked-route b{font-size:11px}.linked-priorities{padding-top:11px;border-top:1px solid #e0e8d8}.linked-priorities b{font-size:11px}.linked-effects button{font-size:10px;padding:6px 9px}.linked-explanation{padding:10px 12px;align-items:start}.linked-explanation strong{width:100%;font-size:10px}.linked-explanation span{font-size:9px}.linked-note{font-size:9px;padding:9px 12px}.block-effects{font-size:7px}.aux-block .block-effects{display:none}.quality-hardware-hint{font-size:9px}}\n&lt;\/style&gt;&lt;style&gt;\/* One gesture, one readout: motion and hardware share the same lab. *\/\n.motion-lab{margin:0 0 24px;padding:22px 24px 16px}\n.motion-heading{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px}\n.motion-heading .eyebrow{display:block;font-size:9px;margin:0 0 5px}\n.motion-heading h2{font-size:23px;line-height:1.3;font-weight:600;letter-spacing:-.4px;margin:0}\n.motion-heading .reset-effect{flex:none;padding:7px 11px;font-size:10px}\n.motion-teaching{font:9px\/1.6 var(--mono);color:#87967e;text-align:right}\n.unified-grid{display:grid;grid-template-columns:minmax(0,.86fr) minmax(0,1.24fr);gap:26px;align-items:start}\n.motion-input,.unified-output{min-width:0}\n.motion-scenes{display:flex;gap:5px;flex-wrap:wrap}\n.motion-scenes button{font:10px var(--mono);padding:7px 9px;background:transparent;border:1px solid #dce4d3;border-radius:4px;color:#71866b;min-height:31px}\n.motion-scenes button.active{color:#246d4e;background:#edf5e5;border-color:#9fb68f}\n.motion-arm{display:block;width:100%;height:auto;margin:3px 0 4px;background:radial-gradient(ellipse at 47% 45%,#eef4e5,#fffefa 75%);border-radius:6px}\n.unified-lab .motion-arm{max-height:208px}\n.motion-arm text{font:10px var(--mono);fill:#7c9474;letter-spacing:.5px;pointer-events:none}\n.motion-arm .motion-arm-note{font:11px 'Segoe UI','Microsoft YaHei',sans-serif;fill:#819576;letter-spacing:0}\n.motion-guide{fill:none;stroke:#dce5d5;stroke-dasharray:4 5}\n.motion-bone{stroke:#cbd7c5;stroke-linecap:round;fill:none}\n.motion-sleeve{fill:#e4edda;stroke:#b7cdaa}\n.motion-joint{fill:#d8e3cf;stroke:#adbea5}\n.motion-leader{stroke:#cbd9c1;stroke-width:1;fill:none}\n.motion-arm [data-motion-drag]{cursor:grab;touch-action:none;outline:none}\n.motion-arm [data-motion-drag]:active{cursor:grabbing}\n.motion-arm [data-motion-drag]:focus-visible .motion-handle,.motion-arm .motion-handle:focus-visible{stroke:#173b3a;stroke-width:3;filter:drop-shadow(0 0 3px #d0aa73)}\n.motion-arm [data-motion-drag]:focus-visible{filter:drop-shadow(0 0 3px #b5834d)}\n.motion-handle{fill:#fffefa;stroke:#438768;stroke-width:2;transition:stroke-width .15s}\n.motion-arm [data-motion-drag]:hover .motion-handle{stroke-width:3}\n.motion-handle.contact,.motion-handle.orange,.motion-handle.contact-handle{stroke:#bf7949;fill:#fcf0e1}\n.motion-controls{display:grid;grid-template-columns:1fr 1fr;gap:15px}\n.motion-controls label{font:10px var(--mono);color:#4b7257;min-width:0}\n.motion-controls label&gt;span{display:flex;justify-content:space-between;gap:8px}\n.motion-controls output{font-size:9px;color:#809477}\n.motion-controls input{display:block;width:100%;margin:8px 0 1px;accent-color:var(--green);height:18px}\n.motion-controls small{font:9px var(--mono);display:flex;justify-content:space-between;color:#8e9d83}\n.motion-controls .inactive{opacity:.45}\n.motion-transport{display:flex;align-items:center;gap:14px;padding-top:12px;margin-top:10px;border-top:1px solid #e8ecdf}\n.motion-transport button{white-space:nowrap;font:10px var(--mono);padding:7px 11px;border:1px solid #bccfb1;background:#f1f6e9;border-radius:4px;color:#396d48;min-width:88px;min-height:32px}\n.motion-transport label{display:flex;align-items:center;gap:9px;width:100%;font:9px var(--mono);color:#7b9072;min-width:0}\n.motion-transport input{width:100%;min-width:0;accent-color:#b67c4d;height:18px}\n.lab-part-label,.lab-hardware-label{display:flex;align-items:center;justify-content:space-between;gap:8px;color:#7c9272;font:9px\/1.5 var(--mono);letter-spacing:.6px}\n.lab-hardware-label{margin:17px 0 7px;padding-top:12px;border-top:1px solid #e4eadc}\n.lab-part-label small,.lab-hardware-label small{font:9px\/1.5 'Segoe UI','Microsoft YaHei',sans-serif;letter-spacing:0;color:#8a9b80}\n.unified-output{padding-left:24px;border-left:1px solid #e4eadc}\n.unified-lab .quality-hardware-tabs{grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin:0 0 8px}\n.unified-lab .quality-hardware-tabs button{grid-template-columns:25px minmax(0,1fr);gap:3px 8px;min-height:52px;padding:8px 10px;background:#f8faf3}\n.unified-lab .quality-hardware-tabs .block-icon{width:25px;height:24px}\n.unified-lab .quality-hardware-tabs strong{font-size:10px;line-height:1.35}\n.unified-lab .quality-hardware-tabs small{font-size:8px;white-space:normal;line-height:1.4}\n.unified-lab .quality-hardware-tabs button[aria-pressed=true]{background:#e8f1dc;border-color:#79a16b;box-shadow:inset 2px 0 #659365}\n.unified-lab .quality-hardware-hint{font-size:10px;line-height:1.7;margin:8px 0}\n.unified-lab .linked-context{margin-top:8px;border-radius:6px}\n.unified-lab .linked-route{gap:9px;font-size:9px;padding:7px 9px;flex-wrap:wrap;line-height:1.5}\n.unified-lab .linked-route b{font-size:11px}\n.unified-lab .linked-body{display:block;padding:9px 11px}\n.unified-lab .linked-label{font-size:8px;line-height:1.6}\n.unified-lab .linked-effects{gap:5px;margin:5px 0 0}\n.unified-lab .linked-effects button{font-size:9px;padding:5px 7px;min-height:28px}\n.unified-lab .linked-priorities{gap:10px;margin-top:9px;padding-top:9px;border-top:1px solid #e0e8d8}\n.unified-lab .linked-priorities small{font-size:7px;line-height:1.4}\n.unified-lab .linked-priorities b{font-size:10px;line-height:1.5;margin:2px 0 0;overflow-wrap:anywhere}\n.unified-lab .linked-priorities span{font-size:9px;line-height:1.5}\n.unified-lab .linked-explanation{gap:5px 9px;padding:8px 11px;align-items:start}\n.unified-lab .linked-explanation strong{font-size:9px;line-height:1.6}\n.unified-lab .linked-explanation span{font-size:9px;line-height:1.7;flex-basis:100%}\n.unified-lab .linked-explanation small{font-size:7px;line-height:1.8;margin-left:auto}\n.unified-lab .linked-note{font-size:9px;line-height:1.65;padding:7px 11px}\n.unified-lab .quality-flow{font-size:9px;gap:7px;line-height:1.6;padding:8px 10px;margin:0 0 11px}\n.unified-lab .quality-plot-head{gap:8px;align-items:center;min-height:19px}\n.unified-lab .quality-plot-head h3{font-size:11px}\n.unified-lab .quality-plot-head&gt;div{gap:7px 10px;justify-content:flex-end}\n.unified-lab .quality-key{font-size:9px}\n.unified-lab .quality-key:before{width:11px;margin-right:4px}\n.unified-lab .quality-key.residual:before{border-color:#bf7b47}\n.unified-lab .quality-equation{font-size:8px;line-height:1.6}\n.unified-lab .quality-wave{margin:3px 0 9px}\n.unified-lab .quality-decision{margin:4px 0 6px}\n.unified-lab .quality-svg-label,.unified-lab .quality-contact-label{font-size:12px}\n.unified-lab .quality-verdict{gap:12px;min-height:34px;margin-top:2px}\n.unified-lab .quality-verdict&gt;span{padding-left:7px}\n.unified-lab .quality-verdict b{font-size:10px;line-height:1.45}\n.unified-lab .quality-verdict small{font-size:9px;line-height:1.5;margin-top:2px}\n.unified-effect-controls{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 10px;border-top:1px solid #e3eadb;padding-top:11px;margin-top:10px}\n.unified-lab .unified-effect-controls .quality-control{border:1px solid #e3e9dc;border-radius:6px;padding:8px 10px 7px;min-width:0;background:#fafbf6;transition:background .15s,border-color .15s,box-shadow .15s}\n.unified-lab .unified-effect-controls .quality-control.is-priority{border-color:#b7cda6;background:#f2f7e9}\n.unified-lab .unified-effect-controls .quality-control.is-focused{border-color:#609271;background:#edf5e4;box-shadow:inset 0 0 0 1px #609271}\n.unified-lab .quality-control-head{gap:7px;margin-bottom:7px}\n.unified-lab .quality-control-head svg{width:27px;height:24px}\n.unified-lab .quality-control-head b{font-size:11px;line-height:1.35}\n.unified-lab .quality-control-head label span{font-size:9px;margin-top:2px;line-height:1.4}\n.unified-lab .quality-control-head output{font-size:9px}\n.unified-lab .quality-control input{height:18px;min-width:0}\n.unified-lab .quality-range-labels{font-size:8px;margin-top:2px;line-height:1.4}\n.unified-lab .quality-switches{grid-column:1\/-1;display:grid;grid-template-columns:1fr 1fr;gap:14px;padding-top:12px}\n.unified-lab .quality-switches label{font-size:10px;line-height:1.5;gap:7px;min-width:0}\n.unified-lab .quality-switches input{margin-top:1px}\n.unified-lab .quality-switches small{font-size:9px;line-height:1.5;margin-top:2px}\n.motion-caption{margin:15px 0 0;border-top:1px solid #e8ecdf;padding-top:10px;font-size:10px;color:#819478;line-height:1.8}\n.motion-caption b{font-weight:500;color:#577950}\n.unified-lab&gt;.axis-note{margin-top:13px;padding-top:10px;border-top:1px solid #e5ebde;font-size:9px;line-height:1.8}\n.unified-lab .quality-sources{margin-top:6px}\n.unified-lab .quality-sources summary{font-size:9px}\n.unified-lab .quality-sources p{font-size:10px}\n.motion-cursor,.quality-time-cursor{stroke:#9cad90;stroke-width:1;stroke-dasharray:3 3;pointer-events:none}\n.motion-dot,.quality-time-dot{stroke:#fffefa;stroke-width:1.5;pointer-events:none}\n.linked-hardware-inspector&gt;.unified-lab{margin-top:18px}\n@media(max-width:1000px){\n .motion-lab{padding:20px 19px 15px}\n .unified-grid{grid-template-columns:minmax(0,.88fr) minmax(0,1.12fr);gap:18px}\n .unified-output{padding-left:18px}\n .motion-heading h2{font-size:21px}\n .motion-scenes button{padding:7px 7px;font-size:9px}\n .motion-controls{gap:12px}\n .motion-controls label{font-size:9px}\n .unified-lab .motion-arm{max-height:196px}\n .unified-lab .quality-flow{font-size:8px;gap:5px;padding:7px 8px}\n .unified-lab .quality-key{font-size:8px}\n .unified-lab .quality-key:before{width:9px}\n .unified-lab .quality-plot-head&gt;div{gap:5px 7px}\n .unified-lab .quality-control-head svg{display:none}\n .unified-lab .linked-route{gap:6px;font-size:8px}\n .unified-lab .linked-priorities b{font-size:9px}\n .unified-lab .linked-explanation strong,.unified-lab .linked-explanation span{font-size:8px}\n .unified-lab .quality-control-head b{font-size:10px}\n .unified-lab .quality-control-head output{font-size:8px}\n .unified-lab .quality-switches label{font-size:9px}\n .unified-lab .quality-verdict b{font-size:9px}\n .unified-lab .quality-verdict small{font-size:8px}\n}\n@media(max-width:700px){\n .motion-lab{padding:18px 15px 14px}\n .motion-heading{align-items:start;gap:12px;margin-bottom:14px}\n .motion-heading h2{font-size:21px;max-width:245px;line-height:1.35}\n .motion-heading .eyebrow{font-size:8px;line-height:1.7;letter-spacing:1px}\n .motion-heading .reset-effect{padding:7px 9px;font-size:9px;white-space:nowrap;margin-top:2px}\n .motion-teaching{max-width:120px;line-height:1.6}\n .unified-grid{grid-template-columns:1fr;gap:20px}\n .motion-scenes button{flex:1;white-space:nowrap;padding:8px 6px;font-size:10px;min-height:34px}\n .unified-lab .motion-arm{max-height:240px;margin:5px 0 7px}\n .motion-arm text{font-size:11px}\n .motion-arm .motion-arm-note{font-size:12px}\n .motion-controls label{font-size:10px}\n .motion-controls output,.motion-controls small{font-size:9px}\n .motion-controls input{height:23px;margin-top:6px}\n .motion-transport{padding-top:11px;margin-top:12px}\n .motion-transport button{min-height:34px}\n .motion-transport label{font-size:10px}\n .motion-transport input{height:22px}\n .lab-hardware-label{margin-top:17px;font-size:9px}\n .unified-lab .quality-hardware-tabs button{padding:10px;min-height:58px}\n .unified-lab .quality-hardware-tabs strong{font-size:11px}\n .unified-lab .quality-hardware-tabs small{font-size:9px}\n .unified-lab .quality-hardware-tabs .block-icon{width:26px}\n .unified-lab .linked-route{font-size:9px;gap:8px;padding:8px 10px}\n .unified-lab .linked-route b{font-size:11px}\n .unified-lab .linked-body{padding:10px 12px}\n .unified-lab .linked-label{font-size:8px}\n .unified-lab .linked-effects{gap:6px;margin-top:6px}\n .unified-lab .linked-effects button{font-size:10px;padding:6px 9px;min-height:31px}\n .unified-lab .linked-priorities{gap:15px;padding-top:10px;margin-top:10px}\n .unified-lab .linked-priorities small{font-size:8px}\n .unified-lab .linked-priorities b{font-size:11px}\n .unified-lab .linked-explanation{padding:9px 12px;gap:5px 10px}\n .unified-lab .linked-explanation strong,.unified-lab .linked-explanation span{font-size:9px}\n .unified-lab .linked-note{font-size:10px;line-height:1.7}\n .unified-output{padding:18px 0 0;border-left:0;border-top:1px solid #e4eadc}\n .unified-lab .quality-flow{font-size:9px;padding:9px 10px;margin-bottom:13px;line-height:1.7;flex-wrap:wrap;justify-content:center}\n .unified-lab .quality-plot-head{align-items:start;gap:6px;flex-wrap:wrap}\n .unified-lab .quality-plot-head h3{font-size:11px;line-height:1.6}\n .unified-lab .quality-plot-head&gt;div{gap:6px 9px;flex-wrap:wrap;margin-left:auto;max-width:100%}\n .unified-lab .quality-key{font-size:9px;line-height:1.8}\n .unified-lab .quality-key:before{width:11px}\n .unified-lab .quality-equation{font-size:8px;line-height:1.8}\n .unified-lab .quality-wave{margin:5px 0 12px}\n .unified-lab .quality-svg-label,.unified-lab .quality-contact-label{font-size:18px}\n .unified-lab .quality-decision{margin:6px 0 9px}\n .unified-lab .quality-verdict{gap:10px 13px;min-height:35px;flex-wrap:wrap}\n .unified-lab .quality-verdict b{font-size:10px}\n .unified-lab .quality-verdict small{font-size:9px}\n .unified-effect-controls{gap:9px;padding-top:13px;margin-top:11px}\n .unified-lab .unified-effect-controls .quality-control{padding:10px 9px 8px}\n .unified-lab .quality-control-head{gap:5px;margin-bottom:6px}\n .unified-lab .quality-control-head b{font-size:11px}\n .unified-lab .quality-control-head label span{font-size:9px}\n .unified-lab .quality-control-head output{font-size:9px}\n .unified-lab .quality-control input{height:23px}\n .unified-lab .quality-range-labels{font-size:9px}\n .unified-lab .quality-switches{padding-top:14px;gap:12px}\n .unified-lab .quality-switches label{font-size:10px;gap:7px}\n .unified-lab .quality-switches small{font-size:9px}\n .motion-caption{font-size:10px;line-height:1.9}\n .unified-lab&gt;.axis-note{font-size:10px}\n .unified-lab .quality-sources summary{font-size:10px;padding:4px 0}\n .unified-lab .quality-sources .source-row a{font-size:9px;line-height:1.8}\n}\n@media(max-width:360px){\n .motion-heading{flex-wrap:wrap}\n .motion-heading h2{max-width:none;font-size:20px}\n .motion-scenes button{font-size:9px;padding:8px 4px}\n .unified-lab .quality-hardware-tabs button{padding:9px 8px;gap:3px 6px}\n .unified-lab .quality-hardware-tabs strong{font-size:10px}\n .unified-lab .quality-hardware-tabs small{font-size:8px}\n .unified-lab .quality-control-head{flex-wrap:wrap}\n .unified-lab .quality-control-head output{margin-left:auto}\n .unified-lab .quality-switches{grid-template-columns:1fr}\n}\n@media(prefers-reduced-motion:reduce){.motion-lab *{transition:none!important;animation:none!important}}\n\n\/* Compact workbench: controls stay beside the shared readout. *\/\nbody[data-page=&quot;principle&quot;] .page{padding-top:12px}\nbody[data-page=&quot;principle&quot;] .intro{margin-bottom:12px;gap:8px;align-items:center}\nbody[data-page=&quot;principle&quot;] .intro .eyebrow,body[data-page=&quot;principle&quot;] .intro p,body[data-page=&quot;principle&quot;] .intro .badge{display:none}\nbody[data-page=&quot;principle&quot;] .intro h1{font-size:19px;margin:0;line-height:1.5}\n.unified-lab{padding:16px 18px 10px;scroll-margin-top:8px}\n.unified-lab .motion-heading{margin-bottom:12px}\n.unified-lab .motion-heading h2{font-size:20px;max-width:none}\n.unified-lab .motion-heading .eyebrow{display:none}\n.unified-grid{grid-template-columns:minmax(210px,.9fr) minmax(240px,1fr) minmax(300px,1.5fr);gap:18px}\n.unified-hardware{min-width:0;border-left:1px solid var(--line);padding-left:16px}\n.unified-output{padding-left:16px}\n.unified-lab .motion-scenes{gap:3px;flex-wrap:nowrap}\n.unified-lab .motion-scenes button{padding:5px;min-height:28px;font-size:9px;flex:1;white-space:nowrap}\n.unified-lab .motion-arm{height:clamp(145px,24vh,200px);max-height:none;margin:6px 0}\n.unified-lab .motion-controls{gap:10px}\n.unified-lab .motion-controls small{display:none}\n.unified-lab .motion-transport{gap:8px;padding-top:10px;margin-top:10px}\n.unified-lab .motion-transport button{min-width:75px;padding:6px 8px}\n.unified-lab .lab-hardware-label{margin:0 0 8px;padding:0;border:0;font-size:10px}\n.unified-lab .quality-hardware-tabs button{min-height:34px;padding:5px 7px;grid-template-columns:20px 1fr}\n.unified-lab .quality-hardware-tabs .block-icon{width:20px;height:20px;grid-row:auto}\n.unified-lab .quality-hardware-tabs small{display:none}\n.unified-lab .linked-context{margin-top:6px;border:0;background:transparent}\n.unified-lab .linked-route,.unified-lab .linked-effects,.unified-lab .linked-explanation{display:none}\n.unified-lab .linked-body{padding:0}\n.unified-lab .linked-priorities{margin:0;padding:0;border:0;gap:8px;min-height:42px}\n.unified-lab .linked-priorities small{font-size:7px}\n.unified-lab .linked-priorities b{font-size:10px;line-height:1.4}\n.unified-lab .linked-priorities span{display:none}\n.unified-lab .unified-effect-controls{gap:6px;margin-top:7px;padding-top:8px}\n.unified-lab .unified-effect-controls .quality-control{padding:7px}\n.unified-lab .quality-control-head{gap:4px;margin-bottom:4px}\n.unified-lab .quality-control-head svg,.unified-lab .quality-control-head label span,.unified-lab .quality-range-labels{display:none}\n.unified-lab .quality-control-head b{font-size:11px}\n.unified-lab .quality-control-head output{font-size:8px}\n.unified-lab .quality-control input{height:22px}\n.unified-lab .quality-switches{grid-template-columns:1fr;gap:7px;padding-top:4px}\n.unified-lab .quality-switches label{font-size:10px;align-items:center}\n.unified-lab .quality-switches small{display:none}\n.unified-lab .quality-flow{display:none}\n.unified-lab .quality-plot-head{min-height:18px;gap:5px;flex-wrap:wrap}\n.unified-lab .quality-key{font-size:9px}\n.unified-lab .quality-plot-head&gt;div{gap:5px}\n.unified-lab .quality-wave{height:clamp(100px,19vh,150px);margin:0 0 6px}\n.unified-lab .quality-decision{height:38px;margin:4px 0}\n.unified-lab .quality-verdict{min-height:17px;gap:10px;flex-wrap:wrap}\n.unified-lab .quality-verdict b{font-size:9px}\n.unified-lab .quality-verdict small{display:none}\n.unified-lab .motion-caption{margin:10px 0 0;padding-top:7px;font:9px\/1.5 var(--mono)}\n.unified-lab .quality-sources{margin-top:5px}\n.unified-lab .quality-sources summary{font-size:9px;padding:0}\n@media(max-width:900px){\n .unified-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px}\n .unified-output{grid-column:1\/-1;padding:9px 0 0;border-left:0;border-top:1px solid var(--line);display:grid;grid-template-columns:1fr 1fr;gap:2px 12px}\n .unified-output&gt;.quality-plot-head:first-of-type{grid-column:1;grid-row:1}\n #quality-signal-plot{grid-column:1;grid-row:2}\n .unified-output&gt;.quality-plot-head:nth-of-type(4){grid-column:2;grid-row:1}\n #quality-residual-plot{grid-column:2;grid-row:2}\n .unified-output&gt;.quality-plot-head:has(+ #quality-residual-plot){grid-column:2;grid-row:1}\n #quality-equation{grid-column:2;grid-row:3}\n #quality-decision-plot{grid-column:1;grid-row:3\/5}\n #quality-verdict{grid-column:2;grid-row:4}\n .unified-lab .quality-wave{height:100px}\n .unified-lab .quality-key{font-size:8px}\n .unified-lab .quality-plot-head&gt;div{margin-left:0}\n .unified-lab .motion-arm{height:155px}\n}\n@media(max-width:500px){\n body[data-page=&quot;principle&quot;] .site-header{padding:8px 12px}\n body[data-page=&quot;principle&quot;] .page{margin:0 10px;padding-top:8px}\n body[data-page=&quot;principle&quot;] .intro h1{font-size:15px}\n .unified-lab{padding:10px}\n .unified-lab .motion-heading{gap:7px;margin-bottom:8px;align-items:center}\n .unified-lab .motion-heading h2{font-size:15px}\n .unified-lab .motion-heading .reset-effect{font-size:8px;padding:5px}\n .unified-grid{gap:8px;grid-template-columns:minmax(0,1fr) minmax(0,1.12fr)}\n .unified-hardware{padding-left:8px}\n .unified-lab .motion-scenes{flex-wrap:wrap;gap:2px}\n .unified-lab .motion-scenes button{min-height:24px;font-size:8px;flex:auto;padding:3px}\n .unified-lab .motion-arm{height:145px}\n .unified-lab .motion-controls{grid-template-columns:1fr;gap:4px}\n .unified-lab .motion-controls input{height:20px;margin-top:2px}\n .unified-lab .motion-transport{flex-wrap:wrap;margin-top:5px;padding-top:5px;gap:4px}\n .unified-lab .motion-transport button{min-height:26px;font-size:9px}\n .unified-lab .motion-transport label{font-size:8px;gap:4px}\n .unified-lab .quality-hardware-tabs{gap:4px}\n .unified-lab .quality-hardware-tabs button{display:block;min-height:30px;padding:4px}\n .unified-lab .quality-hardware-tabs .block-icon{display:none}\n .unified-lab .quality-hardware-tabs strong{font-size:8px}\n .unified-lab .linked-priorities b{font-size:9px}\n .unified-lab .unified-effect-controls{grid-template-columns:1fr;gap:4px;padding-top:5px;margin-top:5px}\n .unified-lab .unified-effect-controls .quality-control{padding:3px 5px}\n .unified-lab .quality-control-head{margin-bottom:0}\n .unified-lab .quality-control-head b{font-size:10px}\n .unified-lab .quality-control input{height:18px}\n .unified-lab .quality-switches{gap:5px}\n .unified-lab .quality-switches label{font-size:8px;gap:4px}\n .unified-lab .quality-plot-head h3{font-size:10px}\n .unified-lab .quality-key{font-size:7px;line-height:1.4}\n .unified-lab .quality-key.baseline{display:none}\n .unified-lab .quality-wave{height:auto}\n .unified-lab .quality-equation{font-size:7px;line-height:1.4}\n .unified-lab .quality-verdict b{font-size:7px}\n .unified-lab .quality-svg-label,.unified-lab .quality-contact-label{font-size:20px}\n .unified-lab .motion-caption{font-size:8px;margin-top:7px}\n}\n\n@media(max-width:500px){\n .unified-output{display:block}\n .unified-lab .motion-arm{height:125px}\n .unified-lab .quality-wave{height:75px;margin-bottom:3px}\n .unified-lab .quality-plot-head{flex-wrap:nowrap}\n .unified-lab .quality-key{font-size:8px}\n .unified-lab .quality-decision{height:29px}\n .unified-lab .quality-verdict{min-height:12px}\n .unified-lab .motion-caption{margin-top:4px;padding-top:4px}\n}\n\n.bend-profile{display:flex;justify-content:space-between;align-items:center;gap:6px;font:9px var(--mono);color:#607e62;margin:2px 0 9px}.bend-profile select{min-width:0;max-width:65%;font:9px var(--mono);color:#326449;background:#f2f6e9;border:1px solid #c9d9ba;border-radius:4px;padding:4px}.evidence-table{min-width:620px}.evidence-table td{font-size:11px;padding:10px;line-height:1.65}.evidence-table th{padding:10px}.evidence-note{font-size:11px;line-height:1.8;color:#728267}.evidence-comparison{width:100%;max-width:560px;display:block}.evidence-status{display:inline-block;background:#e7efdd;padding:2px 5px;border-radius:3px;font:9px var(--mono)}\n&lt;\/style&gt;&lt;\/head&gt;\n&lt;body&gt;&lt;a class=&quot;skip&quot; href=&quot;#main&quot;&gt;\u8df3\u5230\u6b63\u6587&lt;\/a&gt;&lt;header class=&quot;site-header&quot;&gt;&lt;nav class=&quot;primary-nav&quot; aria-label=&quot;\u4e3b\u8981\u5bfc\u822a&quot; id=&quot;nav&quot;&gt;&lt;\/nav&gt;&lt;\/header&gt;&lt;main class=&quot;page&quot; id=&quot;main&quot; tabindex=&quot;-1&quot;&gt;&lt;\/main&gt;&lt;footer class=&quot;site-footer&quot;&gt;&lt;span&gt;OPTICAL FIBER SENSING \u00b7 PRINCIPLE &amp;amp; HARDWARE&lt;\/span&gt;&lt;span&gt;TEACHING MODEL \u00b7 NO LIVE HARDWARE&lt;\/span&gt;&lt;\/footer&gt;&lt;script&gt;(function (root, factory) {\n  'use strict';\n  var api = factory();\n  if (typeof module === 'object' &amp;&amp; module.exports) module.exports = api;\n  root.ArmModel = api;\n})(typeof globalThis !== 'undefined' ? globalThis : this, function () {\n  'use strict';\n\n  \/\/ All mechanical coefficients, offsets and thresholds are teaching assumptions.\n  \/\/ Optical\/electrical unit convention: power in uW; current in uA; voltage in V.\n  var DEFAULT = Object.freeze({ angle: 45, force: 4, mount: 0, encoderAngle: null });\n  var PRESETS = Object.freeze([\n    Object.freeze({ id: 'bend', name: 'Bend only', label: '\u4ec5\u5f2f\u66f2', angle: 60, force: 0, mount: 0, encoderAngle: null }),\n    Object.freeze({ id: 'contact', name: 'Contact only', label: '\u4ec5\u63a5\u89e6', angle: 0, force: 4, mount: 0, encoderAngle: null }),\n    Object.freeze({ id: 'both', name: 'Bend + contact', label: '\u5f2f\u66f2\u4e0e\u63a5\u89e6', angle: 60, force: 4, mount: 0, encoderAngle: null }),\n    Object.freeze({ id: 'mount', name: 'Mount shift', label: '\u7a7f\u88c5\u504f\u79fb', angle: 60, force: 0, mount: 1, encoderAngle: null })\n  ]);\n  var CONSTANTS = Object.freeze({\n    sourcePowerUW: 2,\n    responsivityAperW: 0.45,\n    feedbackOhm: 1000000,\n    supplyV: 3.3,\n    ambientUA: 0.01,\n    offsetV: 0.0075,\n    adcFullScaleV: 2.048,\n    adcLSBV: 0.0000625,\n    adcMinCode: -32768,\n    adcMaxCode: 32767,\n    forceThresholdN: 0.5,\n    fitErrorThreshold: 0.015\n  });\n  var SPECS = [\n    { id: 'B', name: 'Bend', a0: 0.30, bend: 0.80, force: 0.008, mount: 0.08 },\n    { id: 'C', name: 'Contact', a0: 0.35, bend: 0.06, force: 0.070, mount: 0.12 },\n    { id: 'R', name: 'Reference', a0: 0.25, bend: 0, force: 0, mount: 0 }\n  ];\n  var LABELS = Object.freeze({\n    contact: '\u7b26\u5408\u5df2\u6807\u5b9a\u7684\u5355\u63a5\u89e6\u6a21\u578b',\n    no_contact_evidence: '\u6ca1\u6709\u8d85\u8fc7\u793a\u4f8b\u9608\u503c\u7684\u63a5\u89e6\u8bc1\u636e',\n    model_mismatch: '\u53cc\u901a\u9053\u54cd\u5e94\u4e0d\u4e00\u81f4\uff0c\u9700\u590d\u6838\u6216\u91cd\u65b0\u6807\u5b9a',\n    invalid_signal: '\u4fe1\u53f7\u65e0\u6548\uff0c\u4e0d\u80fd\u7ed9\u51fa\u53ef\u4fe1\u529b\u4f30\u8ba1',\n    outside_model_range: '\u8d85\u51fa\u6b64\u6559\u5b66\u6a21\u578b\u7684\u8303\u56f4'\n  });\n  function clamp(x, a, b) { return Math.min(b, Math.max(a, x)); }\n  function number(value, fallback) {\n    return value === undefined || value === null ? fallback : Number(value);\n  }\n  \/\/ Teaching ADC uses signed 16-bit codes; positive inputs use 0..32767.\n  \/\/ Rounding is an ideal quantizer; no noise, nonlinearity or settling is modeled.\n  function adc(voltage) {\n    if (!Number.isFinite(voltage)) return NaN;\n    return clamp(Math.round(voltage \/ CONSTANTS.adcLSBV), -32768, 32767);\n  }\n  function sample(spec, angle, force, mount) {\n    var x = angle \/ 90;\n    var bendLoss = spec.bend * x * x;\n    var contactLoss = spec.force * force;\n    var mountingLoss = spec.mount * mount;\n    var loss = spec.a0 + bendLoss + contactLoss + mountingLoss;\n    var power = CONSTANTS.sourcePowerUW * Math.exp(-loss);\n    var current = CONSTANTS.responsivityAperW * power;\n    var darkV = CONSTANTS.offsetV + CONSTANTS.feedbackOhm * CONSTANTS.ambientUA * 1e-6;\n    var V = darkV + CONSTANTS.feedbackOhm * current * 1e-6;\n    var C_on = adc(V), C_off = adc(darkV), netCode = C_on - C_off;\n    var clipped = V &gt;= CONSTANTS.adcFullScaleV || V &lt;= -CONSTANTS.adcFullScaleV;\n    var valid = Number.isFinite(V) &amp;&amp; !clipped &amp;&amp; netCode &gt; 0;\n    return {\n      id: spec.id, name: spec.name, loss: loss, baseLoss: spec.a0,\n      bendLoss: bendLoss, contactLoss: contactLoss, mountingLoss: mountingLoss,\n      power: power, powerUW: power, current: current, currentUA: current,\n      totalCurrentUA: current + CONSTANTS.ambientUA,\n      V: V, V_on: V, V_off: darkV, darkV: darkV,\n      C_on: C_on, C_off: C_off, netCode: netCode, S: netCode,\n      clipped: clipped, valid: valid\n    };\n  }\n  function compute(input) {\n    input = input || {};\n    var p = {\n      angle: number(input.angle, DEFAULT.angle),\n      force: number(input.force, DEFAULT.force),\n      mount: number(input.mount, DEFAULT.mount),\n      encoderAngle: 0\n    };\n    p.encoderAngle = number(input.encoderAngle, p.angle);\n    var baseline = SPECS.map(function (spec) { return sample(spec, 0, 0, 0); });\n    var channels = SPECS.map(function (spec) { return sample(spec, p.angle, p.force, p.mount); });\n    var ref = channels[2], ref0 = baseline[2];\n    var encoderX = p.encoderAngle \/ 90;\n    channels.forEach(function (ch, index) {\n      var spec = SPECS[index], b = baseline[index];\n      var canNormalize = ch.valid &amp;&amp; ref.valid &amp;&amp; b.valid &amp;&amp; ref0.valid;\n      var ratio = canNormalize ? (ch.S \/ ref.S) \/ (b.S \/ ref0.S) : NaN;\n      var z = ratio &gt; 0 ? -Math.log(ratio) : NaN;\n      var background = spec.bend * encoderX * encoderX;\n      ch.baseline = b;\n      ch.ratio = ratio;\n      ch.z = z;\n      ch.background = background;\n      ch.residual = z - background;\n      ch.valid = canNormalize &amp;&amp; Number.isFinite(z) &amp;&amp; Number.isFinite(background);\n    });\n    var byId = { B: channels[0], C: channels[1], R: channels[2] };\n    var measurementValid = channels.every(function (ch) { return ch.valid; });\n    var withinModelRange = p.angle &gt;= 0 &amp;&amp; p.angle &lt;= 90 &amp;&amp;\n      p.encoderAngle &gt;= 0 &amp;&amp; p.encoderAngle &lt;= 90 &amp;&amp;\n      p.force &gt;= 0 &amp;&amp; p.force &lt;= 10 &amp;&amp; p.mount &gt;= 0 &amp;&amp; p.mount &lt;= 1;\n    var kB = SPECS[0].force, kC = SPECS[1].force;\n    var rB = byId.B.residual, rC = byId.C.residual;\n    var force = measurementValid ? Math.max(0, (kB * rB + kC * rC) \/ (kB * kB + kC * kC)) : NaN;\n    var error = measurementValid ? Math.sqrt((Math.pow(rB - kB * force, 2) + Math.pow(rC - kC * force, 2)) \/ 2) : NaN;\n    var labelcode = !measurementValid ? 'invalid_signal' : !withinModelRange ? 'outside_model_range' :\n      error &gt; CONSTANTS.fitErrorThreshold ? 'model_mismatch' :\n      force &gt;= CONSTANTS.forceThresholdN ? 'contact' : 'no_contact_evidence';\n    var fit = {\n      force: force, error: error, labelcode: labelcode, label: LABELS[labelcode],\n      valid: measurementValid &amp;&amp; withinModelRange &amp;&amp; error &lt;= CONSTANTS.fitErrorThreshold,\n      measurementValid: measurementValid, withinModelRange: withinModelRange,\n      forceThresholdN: CONSTANTS.forceThresholdN,\n      errorThreshold: CONSTANTS.fitErrorThreshold,\n      predictedResidualB: kB * force, predictedResidualC: kC * force,\n      caveat: '\u4e24\u8def\u4e00\u81f4\u4ec5\u8868\u793a\u7b26\u5408\u6807\u5b9a\u6a21\u578b\uff1b\u4e0e\u63a5\u89e6\u6a21\u5f0f\u76f8\u540c\u7684\u5b89\u88c5\u6f02\u79fb\u4ecd\u65e0\u6cd5\u7531\u8fd9\u4e24\u4e2a\u901a\u9053\u552f\u4e00\u6392\u9664\u3002'\n    };\n    return { p: p, input: p, channels: channels, byId: byId, baseline: baseline, fit: fit, constants: CONSTANTS };\n  }\n  return {\n    DEFAULT: DEFAULT, PRESETS: PRESETS, CONSTANTS: CONSTANTS, LABELS: LABELS,\n    compute: compute,\n    units: { power: 'uW', current: 'uA', V: 'V', angle: 'degree', force: 'N', z: 'dimensionless', residual: 'dimensionless' },\n    status: 'Illustrative coefficients and ideal electronics; not measured accuracy.'\n  };\n});\n&lt;\/script&gt;&lt;script&gt;window.ARM_HARDWARE={&quot;title&quot;:&quot;Abstract optical sensing architecture&quot;,&quot;blocks&quot;:[{&quot;id&quot;:&quot;driver&quot;,&quot;name&quot;:&quot;LED DRIVER&quot;,&quot;kind&quot;:&quot;electrical&quot;,&quot;symbol&quot;:&quot;I&quot;,&quot;input&quot;:&quot;Control command&quot;,&quot;inputSymbol&quot;:&quot;u(t)&quot;,&quot;output&quot;:&quot;LED current&quot;,&quot;outputSymbol&quot;:&quot;I_LED(t)&quot;,&quot;action&quot;:&quot;Current regulation&quot;,&quot;formula&quot;:&quot;Command \u2192 controlled current&quot;,&quot;note&quot;:&quot;\u7a33\u5b9a\u7535\u6d41\uff0c\u5e76\u5728\u91c7\u6837\u524d\u5b8c\u6210 Settling\u3002&quot;,&quot;control&quot;:&quot;Response speed&quot;,&quot;low&quot;:&quot;Slow&quot;,&quot;high&quot;:&quot;Fast&quot;,&quot;default&quot;:65,&quot;metrics&quot;:[[&quot;Current noise&quot;,&quot;\u907f\u514d\u7535\u6d41\u6ce2\u52a8\u6df7\u5165\u5149\u4fe1\u53f7\u3002&quot;],[&quot;Settling time&quot;,&quot;\u5f00\u5173\u540e\u591a\u4e45\u80fd\u591f\u7a33\u5b9a\u91c7\u6837\u3002&quot;]]},{&quot;id&quot;:&quot;led&quot;,&quot;name&quot;:&quot;LED&quot;,&quot;kind&quot;:&quot;optical&quot;,&quot;symbol&quot;:&quot;P&quot;,&quot;input&quot;:&quot;LED current&quot;,&quot;inputSymbol&quot;:&quot;I_LED(t)&quot;,&quot;output&quot;:&quot;Optical power&quot;,&quot;outputSymbol&quot;:&quot;P_in(t)&quot;,&quot;action&quot;:&quot;Electro-optical conversion&quot;,&quot;formula&quot;:&quot;Current \u2192 light&quot;,&quot;note&quot;:&quot;\u540c\u6837\u7684\u7535\u6d41\uff0c\u6e29\u5ea6\u53d8\u5316\u4e5f\u4f1a\u6539\u53d8\u5149\u529f\u7387\u3002&quot;,&quot;control&quot;:&quot;Thermal drift&quot;,&quot;low&quot;:&quot;Low&quot;,&quot;high&quot;:&quot;High&quot;,&quot;default&quot;:20,&quot;metrics&quot;:[[&quot;Optical stability&quot;,&quot;\u76f8\u540c\u9a71\u52a8\u4e0b\uff0c\u5149\u529f\u7387\u4fdd\u6301\u7a33\u5b9a\u3002&quot;],[&quot;Spectral match&quot;,&quot;\u5149\u8c31\u5339\u914d Fiber \u4e0e Photodiode\u3002&quot;]]},{&quot;id&quot;:&quot;fiber&quot;,&quot;name&quot;:&quot;FIBER SENSOR&quot;,&quot;kind&quot;:&quot;optical&quot;,&quot;symbol&quot;:&quot;A&quot;,&quot;input&quot;:&quot;Light + deformation&quot;,&quot;inputSymbol&quot;:&quot;P_in(t)&quot;,&quot;output&quot;:&quot;Modulated light&quot;,&quot;outputSymbol&quot;:&quot;P_out(t)&quot;,&quot;action&quot;:&quot;Loss modulation&quot;,&quot;formula&quot;:&quot;P_out = P_in \u00b7 exp(\u2212A)&quot;,&quot;note&quot;:&quot;\u8fd9\u91cc\u6f14\u793a Loss \u968f\u5f62\u53d8\u589e\u5927\u7684\u60c5\u51b5\uff1b\u771f\u5b9e\u54cd\u5e94\u9700\u8981\u6807\u5b9a\u3002&quot;,&quot;control&quot;:&quot;Deformation&quot;,&quot;low&quot;:&quot;Small&quot;,&quot;high&quot;:&quot;Large&quot;,&quot;default&quot;:40,&quot;metrics&quot;:[[&quot;Repeatability&quot;,&quot;\u76f8\u540c\u5f62\u53d8\u5f97\u5230\u76f8\u8fd1\u7684\u54cd\u5e94\u3002&quot;],[&quot;Hysteresis&quot;,&quot;\u52a0\u8f7d\u4e0e\u5378\u8f7d\u7684\u54cd\u5e94\u5dee\u5f02\u8981\u5c0f\u3002&quot;]]},{&quot;id&quot;:&quot;pd&quot;,&quot;name&quot;:&quot;PHOTODIODE&quot;,&quot;kind&quot;:&quot;conversion&quot;,&quot;symbol&quot;:&quot;I&quot;,&quot;input&quot;:&quot;Optical power&quot;,&quot;inputSymbol&quot;:&quot;P(t)&quot;,&quot;output&quot;:&quot;Photocurrent&quot;,&quot;outputSymbol&quot;:&quot;I_PD(t)&quot;,&quot;action&quot;:&quot;Photoelectric conversion&quot;,&quot;formula&quot;:&quot;I_PD = R\u03bb \u00b7 P + I_dark&quot;,&quot;note&quot;:&quot;Dark subtraction \u80fd\u51cf\u5c0f\u57fa\u7ebf\uff0c\u4e0d\u80fd\u6d88\u9664\u968f\u673a\u566a\u58f0\u3002&quot;,&quot;control&quot;:&quot;Light level&quot;,&quot;low&quot;:&quot;Dim&quot;,&quot;high&quot;:&quot;Bright&quot;,&quot;default&quot;:55,&quot;metrics&quot;:[[&quot;Responsivity&quot;,&quot;\u5de5\u4f5c\u6ce2\u957f\u4e0b\uff0c\u5149\u8f6c\u7535\u7684\u7075\u654f\u5ea6\u3002&quot;],[&quot;Dark current&quot;,&quot;\u65e0\u5149\u65f6\u7684\u7535\u6d41\u53ca\u5176\u6e29\u6f02\u3002&quot;]]},{&quot;id&quot;:&quot;tia&quot;,&quot;name&quot;:&quot;TIA&quot;,&quot;kind&quot;:&quot;electrical&quot;,&quot;symbol&quot;:&quot;V&quot;,&quot;input&quot;:&quot;Photocurrent&quot;,&quot;inputSymbol&quot;:&quot;I(t)&quot;,&quot;output&quot;:&quot;Analog voltage&quot;,&quot;outputSymbol&quot;:&quot;V(t)&quot;,&quot;action&quot;:&quot;Current-to-voltage&quot;,&quot;formula&quot;:&quot;\u0394V = \u00b1 Z_T \u00b7 \u0394I&quot;,&quot;note&quot;:&quot;\u6781\u6027\u53d6\u51b3\u4e8e\u8fde\u63a5\uff1b\u672c\u56fe\u793a\u610f\u6b63\u5411\u53d8\u5316\uff0c\u589e\u76ca\u8fc7\u9ad8\u4f1a Clipping\u3002&quot;,&quot;control&quot;:&quot;Transimpedance gain&quot;,&quot;low&quot;:&quot;Low&quot;,&quot;high&quot;:&quot;High&quot;,&quot;default&quot;:35,&quot;metrics&quot;:[[&quot;In-band noise&quot;,&quot;\u5173\u6ce8\u5b9e\u9645\u6d4b\u91cf\u5e26\u5bbd\u5185\u7684\u603b\u566a\u58f0\u3002&quot;],[&quot;Headroom&quot;,&quot;\u4fe1\u53f7\u653e\u5927\u540e\u4ecd\u6709\u8db3\u591f\u8f93\u51fa\u4f59\u91cf\u3002&quot;]]},{&quot;id&quot;:&quot;filter&quot;,&quot;name&quot;:&quot;FILTER&quot;,&quot;kind&quot;:&quot;electrical&quot;,&quot;symbol&quot;:&quot;V&quot;,&quot;input&quot;:&quot;Signal + noise&quot;,&quot;inputSymbol&quot;:&quot;V_raw(t)&quot;,&quot;output&quot;:&quot;Band-limited voltage&quot;,&quot;outputSymbol&quot;:&quot;V_filtered(t)&quot;,&quot;action&quot;:&quot;Band limiting&quot;,&quot;formula&quot;:&quot;Noise \u2193 \u00b7 Delay \u2191&quot;,&quot;note&quot;:&quot;\u66f4\u5f3a\u7684\u5e73\u6ed1\u901a\u5e38\u5e26\u6765\u66f4\u5927\u7684\u5ef6\u8fdf\uff1b\u91c7\u6837\u524d\u8fd8\u9700\u63a7\u5236\u6df7\u53e0\u3002&quot;,&quot;control&quot;:&quot;Smoothing&quot;,&quot;low&quot;:&quot;Weak&quot;,&quot;high&quot;:&quot;Strong&quot;,&quot;default&quot;:50,&quot;metrics&quot;:[[&quot;Noise bandwidth&quot;,&quot;\u4fdd\u7559\u6709\u6548\u53d8\u5316\uff0c\u9650\u5236\u5e26\u5916\u566a\u58f0\u3002&quot;],[&quot;Group delay&quot;,&quot;\u6ce2\u5f62\u88ab\u5e73\u6ed1\u540e\u5ef6\u8fdf\u4e86\u591a\u5c11\u3002&quot;]]},{&quot;id&quot;:&quot;adc&quot;,&quot;name&quot;:&quot;ADC&quot;,&quot;kind&quot;:&quot;digital&quot;,&quot;symbol&quot;:&quot;01&quot;,&quot;input&quot;:&quot;Analog voltage&quot;,&quot;inputSymbol&quot;:&quot;V(t)&quot;,&quot;output&quot;:&quot;Digital code&quot;,&quot;outputSymbol&quot;:&quot;Code[n]&quot;,&quot;action&quot;:&quot;Sampling + quantization&quot;,&quot;formula&quot;:&quot;Continuous \u2192 discrete&quot;,&quot;note&quot;:&quot;Code \u662f\u7535\u538b\u7684\u6570\u5b57\u8868\u8fbe\uff0c\u4ecd\u9700\u8981 Calibration \u624d\u80fd\u89e3\u91ca\u4e3a\u7269\u7406\u91cf\u3002&quot;,&quot;control&quot;:&quot;Quantization detail&quot;,&quot;low&quot;:&quot;Coarse&quot;,&quot;high&quot;:&quot;Fine&quot;,&quot;default&quot;:45,&quot;metrics&quot;:[[&quot;Noise-free resolution&quot;,&quot;\u80fd\u7a33\u5b9a\u533a\u5206\u7684\u53d8\u5316\uff0c\u4f18\u5148\u4e8e\u6807\u79f0\u4f4d\u6570\u3002&quot;],[&quot;Settled throughput&quot;,&quot;\u5207\u6362\u4e0e\u6ee4\u6ce2\u540e\u771f\u6b63\u6709\u6548\u7684\u91c7\u6837\u901f\u5ea6\u3002&quot;]]},{&quot;id&quot;:&quot;mcu&quot;,&quot;name&quot;:&quot;MCU&quot;,&quot;kind&quot;:&quot;digital&quot;,&quot;symbol&quot;:&quot;r&quot;,&quot;input&quot;:&quot;Code + angle + time&quot;,&quot;inputSymbol&quot;:&quot;Measured \/ Baseline&quot;,&quot;output&quot;:&quot;Features \/ state&quot;,&quot;outputSymbol&quot;:&quot;Residual&quot;,&quot;action&quot;:&quot;Calibration + processing&quot;,&quot;formula&quot;:&quot;Residual = Measured \u2212 Baseline&quot;,&quot;note&quot;:&quot;\u7ed3\u5408\u89d2\u5ea6\u548c\u6807\u5b9a\u80cc\u666f\uff1b\u5355\u4e2a\u5149\u5f3a\u53d8\u5316\u4e0d\u80fd\u552f\u4e00\u8bc1\u660e\u63a5\u89e6\u3002&quot;,&quot;control&quot;:&quot;Contact contribution&quot;,&quot;low&quot;:&quot;Small&quot;,&quot;high&quot;:&quot;Large&quot;,&quot;default&quot;:55,&quot;metrics&quot;:[[&quot;Time alignment&quot;,&quot;\u89d2\u5ea6\u4e0e\u5149\u4fe1\u53f7\u5bf9\u5e94\u540c\u4e00\u65f6\u523b\u3002&quot;],[&quot;Latency&quot;,&quot;\u4ece\u91c7\u96c6\u5230\u7ed3\u679c\u7684\u603b\u5ef6\u8fdf\u3002&quot;]]},{&quot;id&quot;:&quot;power&quot;,&quot;name&quot;:&quot;POWER&quot;,&quot;kind&quot;:&quot;support&quot;,&quot;symbol&quot;:&quot;V&quot;,&quot;input&quot;:&quot;Supply input&quot;,&quot;inputSymbol&quot;:&quot;V_in(t)&quot;,&quot;output&quot;:&quot;Regulated supply rails&quot;,&quot;outputSymbol&quot;:&quot;V_rail(t)&quot;,&quot;action&quot;:&quot;Regulation&quot;,&quot;formula&quot;:&quot;Supply \u2192 stable rails&quot;,&quot;note&quot;:&quot;\u4e3a\u5404\u6709\u6e90\u6a21\u5757\u4f9b\u80fd\uff1b\u4f9b\u7535\u6ce2\u52a8\u4f1a\u6c61\u67d3\u4fe1\u53f7\u3002&quot;,&quot;control&quot;:&quot;Ripple rejection&quot;,&quot;low&quot;:&quot;Weak&quot;,&quot;high&quot;:&quot;Strong&quot;,&quot;default&quot;:65,&quot;metrics&quot;:[[&quot;Ripple&quot;,&quot;\u7535\u6e90\u8f68\u4e0a\u7684\u6b8b\u4f59\u6ce2\u52a8\u3002&quot;],[&quot;Drift&quot;,&quot;\u7535\u6e90\u4e0e\u53c2\u8003\u968f\u65f6\u95f4\u3001\u6e29\u5ea6\u7684\u53d8\u5316\u3002&quot;]]},{&quot;id&quot;:&quot;encoder&quot;,&quot;name&quot;:&quot;ENCODER&quot;,&quot;kind&quot;:&quot;support&quot;,&quot;symbol&quot;:&quot;\u03b8&quot;,&quot;input&quot;:&quot;Joint rotation&quot;,&quot;inputSymbol&quot;:&quot;\u03b8_true(t)&quot;,&quot;output&quot;:&quot;Angle + timestamp&quot;,&quot;outputSymbol&quot;:&quot;\u03b8_measured(t)&quot;,&quot;action&quot;:&quot;Angle measurement&quot;,&quot;formula&quot;:&quot;Rotation \u2192 angle + time&quot;,&quot;note&quot;:&quot;\u9519\u65f6\u6bd4\u8f83\u4f1a\u7559\u4e0b\u5047 Residual\uff1b\u5bf9\u9f50\u4e0e\u89d2\u5ea6\u51c6\u786e\u6027\u540c\u6837\u91cd\u8981\u3002&quot;,&quot;control&quot;:&quot;Time mismatch&quot;,&quot;low&quot;:&quot;Aligned&quot;,&quot;high&quot;:&quot;Delayed&quot;,&quot;default&quot;:20,&quot;metrics&quot;:[[&quot;Angle accuracy&quot;,&quot;\u5173\u8282\u89d2\u5ea6\u6d4b\u5f97\u662f\u5426\u51c6\u786e\u3002&quot;],[&quot;Time alignment&quot;,&quot;\u89d2\u5ea6\u662f\u5426\u4e0e\u5149\u4fe1\u53f7\u540c\u6b65\u3002&quot;]]}],&quot;sources&quot;:[{&quot;label&quot;:&quot;Photodiode principles&quot;,&quot;url&quot;:&quot;https:\/\/www.hamamatsu.com\/content\/dam\/hamamatsu-photonics\/sites\/documents\/99_SALES_LIBRARY\/ssd\/si_pd_kspd9001e.pdf&quot;},{&quot;label&quot;:&quot;TIA principles&quot;,&quot;url&quot;:&quot;https:\/\/www.ti.com\/lit\/an\/snoa515a\/snoa515a.pdf&quot;},{&quot;label&quot;:&quot;ADC principles&quot;,&quot;url&quot;:&quot;https:\/\/wiki.analog.com\/university\/courses\/electronics\/text\/chapter-20&quot;}]};\nwindow.HARDWARE_EFFECTS={&quot;tia&quot;:{&quot;name&quot;:&quot;TIA&quot;,&quot;input&quot;:&quot;Photocurrent&quot;,&quot;output&quot;:&quot;Voltage&quot;,&quot;primary&quot;:[&quot;noise&quot;,&quot;offset&quot;],&quot;defaultEffect&quot;:&quot;noise&quot;,&quot;metrics&quot;:[[&quot;In-band noise&quot;,&quot;\u5148\u770b\u6d4b\u91cf\u5e26\u5185\u7684\u603b\u566a\u58f0&quot;],[&quot;Offset drift&quot;,&quot;\u57fa\u7ebf\u80fd\u5426\u4fdd\u6301\u7a33\u5b9a&quot;]],&quot;note&quot;:&quot;\u5c0f\u4fe1\u53f7\u6015 Noise\uff1b\u57fa\u7ebf\u6015 Offset \/ Drift\u3002\u8fd8\u9700\u4fdd\u7559 Headroom\u3002&quot;,&quot;effects&quot;:{&quot;noise&quot;:{&quot;metric&quot;:&quot;In-band noise&quot;,&quot;path&quot;:&quot;Input noise \u2192 Voltage noise \u2192 \u6296\u52a8&quot;,&quot;level&quot;:85},&quot;offset&quot;:{&quot;metric&quot;:&quot;Input offset \/ Bias current&quot;,&quot;path&quot;:&quot;Input error \u2192 Output offset \u2192 \u5047 Residual&quot;,&quot;level&quot;:85},&quot;drift&quot;:{&quot;metric&quot;:&quot;Offset drift&quot;,&quot;path&quot;:&quot;Baseline drift \u2192 Residual drift&quot;,&quot;level&quot;:80},&quot;bandwidth&quot;:{&quot;metric&quot;:&quot;Closed-loop bandwidth&quot;,&quot;path&quot;:&quot;\u6709\u9650\u54cd\u5e94 \u2192 \u8109\u51b2\u53d8\u949d \/ \u5ef6\u8fdf&quot;,&quot;level&quot;:20}}},&quot;adc&quot;:{&quot;name&quot;:&quot;ADC&quot;,&quot;input&quot;:&quot;Voltage&quot;,&quot;output&quot;:&quot;Digital code&quot;,&quot;primary&quot;:[&quot;noise&quot;,&quot;bandwidth&quot;],&quot;defaultEffect&quot;:&quot;bandwidth&quot;,&quot;metrics&quot;:[[&quot;Noise-free resolution&quot;,&quot;\u80fd\u7a33\u5b9a\u5206\u8fa8\u7684\u5c0f\u53d8\u5316&quot;],[&quot;Settled throughput&quot;,&quot;\u771f\u6b63\u6709\u6548\u7684\u8bfb\u51fa\u901f\u5ea6&quot;]],&quot;note&quot;:&quot;\u8fd9\u91cc\u6f14\u793a Code noise \u4e0e\u6709\u9650\u8bfb\u51fa\u54cd\u5e94\uff1bQuantization \u2260 random Noise\u3002&quot;,&quot;effects&quot;:{&quot;noise&quot;:{&quot;metric&quot;:&quot;Noise-free resolution&quot;,&quot;path&quot;:&quot;Conversion noise \u2192 Code jitter \u2192 \u5f31\u63a5\u89e6\u6a21\u7cca&quot;,&quot;level&quot;:80},&quot;bandwidth&quot;:{&quot;metric&quot;:&quot;Filter response \/ Settling&quot;,&quot;path&quot;:&quot;\u6709\u9650\u8bfb\u51fa\u54cd\u5e94 \u2192 \u77ed Contact \u8870\u51cf \/ \u5ef6\u8fdf&quot;,&quot;level&quot;:25},&quot;offset&quot;:{&quot;metric&quot;:&quot;Offset error&quot;,&quot;path&quot;:&quot;Code offset \u2192 \u96f6\u70b9\u504f\u79fb&quot;,&quot;level&quot;:80},&quot;drift&quot;:{&quot;metric&quot;:&quot;Offset \/ Gain drift&quot;,&quot;path&quot;:&quot;\u8f6c\u6362\u7279\u6027\u53d8\u5316 \u2192 Readout drift&quot;,&quot;level&quot;:80}}},&quot;driver&quot;:{&quot;name&quot;:&quot;LED DRIVER&quot;,&quot;input&quot;:&quot;Command&quot;,&quot;output&quot;:&quot;LED current \u2192 Light&quot;,&quot;primary&quot;:[&quot;noise&quot;,&quot;drift&quot;],&quot;defaultEffect&quot;:&quot;noise&quot;,&quot;metrics&quot;:[[&quot;Current noise&quot;,&quot;\u7535\u6d41\u7a33\uff0c\u5149\u624d\u7a33&quot;],[&quot;Settling time&quot;,&quot;\u7a33\u5b9a\u540e\u518d\u53d6\u6837&quot;]],&quot;note&quot;:&quot;Current stability \u6291\u5236 Drift\uff1bSettling \u5f71\u54cd\u8c03\u5236\u91c7\u6837\uff0c\u4e0d\u662f\u63a5\u89e6\u4fe1\u53f7\u7684\u540e\u7aef\u4f4e\u901a\u3002&quot;,&quot;effects&quot;:{&quot;noise&quot;:{&quot;metric&quot;:&quot;Current noise&quot;,&quot;path&quot;:&quot;Current fluctuation \u2192 Light fluctuation \u2192 \u5047\u5f62\u53d8&quot;,&quot;level&quot;:90},&quot;drift&quot;:{&quot;metric&quot;:&quot;Current stability&quot;,&quot;path&quot;:&quot;Drive drift \u2192 Light drift \u2192 \u57fa\u7ebf\u6e38\u8d70&quot;,&quot;level&quot;:90}}},&quot;power&quot;:{&quot;name&quot;:&quot;POWER&quot;,&quot;input&quot;:&quot;Supply \/ Reference&quot;,&quot;output&quot;:&quot;Coupled readout error&quot;,&quot;primary&quot;:[&quot;noise&quot;,&quot;drift&quot;],&quot;defaultEffect&quot;:&quot;drift&quot;,&quot;metrics&quot;:[[&quot;Ripple &amp; noise&quot;,&quot;\u51cf\u5c11\u7535\u6e90\u8f68\u6270\u52a8&quot;],[&quot;Reference stability&quot;,&quot;\u53c2\u8003\u7535\u5e73\u4fdd\u6301\u7a33\u5b9a&quot;]],&quot;note&quot;:&quot;Indirect coupling\uff1a\u63a5\u6536\u7aef\u8fd8\u770b PSRR\uff1bReference drift \u4e5f\u53ef\u80fd\u6539\u53d8 Gain\u3002&quot;,&quot;effects&quot;:{&quot;noise&quot;:{&quot;metric&quot;:&quot;Ripple &amp; noise \/ PSRR&quot;,&quot;path&quot;:&quot;Rail disturbance \u21e2 Readout noise \u2192 \u8bef\u89e6\u53d1&quot;,&quot;level&quot;:80},&quot;drift&quot;:{&quot;metric&quot;:&quot;Reference stability&quot;,&quot;path&quot;:&quot;Rail \/ Reference drift \u21e2 Readout drift&quot;,&quot;level&quot;:95}}}};\nwindow.LITERATURE_REPORT=&quot;&lt;p&gt;&lt;b&gt;\u7ed3\u8bba\uff1a\u6821\u51c6\u4e86\u6765\u6e90\u4e0e\u9002\u7528\u8303\u56f4\uff0c\u4e0d\u7b49\u4e8e\u5b8c\u6210\u673a\u5668\u4eba\u5b9e\u7269\u6807\u5b9a\u3002&lt;\/b&gt; \u672c\u6b21\u6838\u5bf9\u5f53\u524d\u7f51\u9875\u76f8\u5173\u8bba\u6587\uff0c\u672a\u5ba3\u79f0\u7cfb\u7edf\u7efc\u8ff0\u5168\u90e842\u7bc7\u3002\u6570\u636e\u6765\u81ea\u539fPDF\u516c\u5f0f\/\u56fe\u8868\uff0c\u76ee\u5f55\u7d22\u5f15\u4ec5\u7528\u4e8e\u627e\u6587\u732e\u30022026-10-23\u3002&lt;\/p&gt;&lt;div class=\\&quot;evidence-status\\&quot;&gt;FBG: literature nominal&lt;\/div&gt; &lt;div class=\\&quot;evidence-status\\&quot;&gt;Bend: optional POF reference&lt;\/div&gt; &lt;div class=\\&quot;evidence-status\\&quot;&gt;Contact \/ Effects: uncalibrated&lt;\/div&gt;&lt;h3&gt;Before \u2192 Evidence \u2192 Action&lt;\/h3&gt;&lt;div class=\\&quot;table-wrap\\&quot;&gt;&lt;table class=\\&quot;evidence-table\\&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Quantity&lt;\/th&gt;&lt;th&gt;Before&lt;\/th&gt;&lt;th&gt;Evidence \/ After&lt;\/th&gt;&lt;th&gt;Source locator&lt;\/th&gt;&lt;th&gt;Scope &amp; decision&lt;\/th&gt;&lt;\/tr&gt;&lt;\/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;FBG \u00b7 Strain&lt;\/td&gt;&lt;td&gt;1.2 pm\/\u00b5\u03b5&lt;\/td&gt;&lt;td&gt;1.209 pm\/\u00b5\u03b5&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1109\/50.618377\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Kersey 1997 \u00b7 PDF p2 Eq3\uff1b1550 \u00d7 0.78 \u00d7 10\u207b\u00b3 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u540d\u4e49\u5149\u7ea4\u54cd\u5e94\uff1b\u66f4\u65b0 mini demo\u3002\u4e0d\u662f\u7ec7\u7269\/\u5173\u8282\u7684\u5e94\u53d8\u4f20\u9012\u7cfb\u6570\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;FBG \u00b7 Temperature&lt;\/td&gt;&lt;td&gt;10 pm\/\u00b0C&lt;\/td&gt;&lt;td&gt;10.3385 pm\/\u00b0C&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1109\/50.618377\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Kersey 1997 \u00b7 PDF p2 Eq4\uff1b1550 \u00d7 1000 \u00d7 6.67\u00d710\u207b\u2076 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u540c\u4e00\u6765\u6e90\u3001\u540c\u4e00\u6ce2\u957f\u6362\u7b97\uff1b\u663e\u793a\u4f4d\u6570\u7528\u4e8e\u590d\u7b97\uff0c\u4e0d\u662f\u6d4b\u91cf\u7cbe\u5ea6\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Strain cross-check&lt;\/td&gt;&lt;td&gt;\u56fa\u5b9a\u901a\u7528\u7cfb\u6570&lt;\/td&gt;&lt;td&gt;k = 0.7931 \u00b1 0.0034&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1117\/12.781426\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Roths 2008 \u00b7 PDF pp6\u20137\uff1bTable2 \/ conclusion \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u81ea\u7531\u3001\u65e0\u6d82\u5c42 FBG\uff1b\u6362\u7b971550nm\u4e3a1.229\u00b10.005 pm\/\u00b5\u03b5\uff0c\u4e0e1.209\u76f8\u5dee\u7ea61.68%\u3002\u4e0d\u540c\u5149\u7ea4\u4e0d\u80fd\u5408\u5e76\u4e3a\u901a\u7528\u7f6e\u4fe1\u533a\u95f4\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Temperature cross-check&lt;\/td&gt;&lt;td&gt;\u56fa\u5b9a\u901a\u7528\u7cfb\u6570&lt;\/td&gt;&lt;td&gt;6.69 \u00b1 0.07 ppm\/\u00b0C&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1088\/0957-0233\/9\/8\/004\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Haran 1998 \u00b7 PDF pp3\u20134\uff1b1303.39nm\u9694\u79bb\u53c2\u8003 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u82e5\u4ec5\u6309\u6ce2\u957f\u6362\u7b97\u52301550nm\uff0c\u4e3a10.3695\u00b10.1085 pm\/\u00b0C\uff1b\u975e1550nm\u5b9e\u6d4b\u3002Hill 1997 PDF p11\u4e5f\u7ed9\u51fa\u5178\u578b\u7ea610pm\/\u00b0C\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Intensity \u00b7 Bend&lt;\/td&gt;&lt;td&gt;L = 0.85 \u00b7 u\u00b2&lt;\/td&gt;&lt;td&gt;r = \u22120.00649\u03b8 + 1.126&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1088\/0957-0233\/22\/4\/045801\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Bilro 2011 \u00b7 PDF pp4\u20135\uff0cTable3 Subject A \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u4fa7\u629b\u5149 POF\u3001\u51f8\u5411\u5f2f\u66f2\u3001\u53c2\u8003\u901a\u9053\u3001\u819d\u652f\u5177\uff0c0\u201375\u00b0\u3002\u65b0\u589e\u53ef\u9009 POF reference\uff1b\u4e0d\u66ff\u4ee3\u673a\u5668\u4eba\u5b9e\u6d4b\u6807\u5b9a\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Normalized bend&lt;\/td&gt;&lt;td&gt;\u4e8c\u6b21\u635f\u8017\u5f62\u72b6&lt;\/td&gt;&lt;td&gt;L = \u2212ln[1 \u2212 (0.00649\/1.126)\u03b8]&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1088\/0957-0233\/22\/4\/045801\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;\u7531 Bilro \u62df\u5408\u6d3e\u751f\uff1br\u2080=1.126 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u53ea\u5f52\u4e00\u5316\u8bba\u6587\u7535\u538b\u6bd4\uff1b\u5f53\u5149\u7535\u8bfb\u51fa\u7ebf\u6027\u4e14\u7a33\u5b9a\u65f6\uff0c\u624d\u53ef\u89c6\u4f5c\u76f8\u5bf9\u5149\u529f\u7387\u300275\u00b0\u65f6\u6bd4\u503c0.56772\u3001Loss 0.56613\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Bend-loss theory&lt;\/td&gt;&lt;td&gt;\u4e8c\u6b21\u5f0f\u53ef\u80fd\u88ab\u5f53\u4f5c\u666e\u9002\u89c4\u5f8b&lt;\/td&gt;&lt;td&gt;\u4e0d\u80fd\u652f\u6301 L \u221d \u03b8\u00b2&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1364\/JOSA.66.000216\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Marcuse 1976 \u00b7 PDF p3 Eq32\u3001p4\u9650\u5236 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u6052\u5b9a\u66f2\u7387\u3001\u5f31\u5bfc\u5149\u7ea4\u8fd1\u4f3c\u542b R\u207b\u00bdexp(\u2212cR)\uff1b\u9700\u8981\u5149\u7ea4\u548c\u51e0\u4f55\u53c2\u6570\uff0c\u4e0d\u80fd\u76f4\u63a5\u5957\u7528\u4e8e\u4fa7\u629b\u5149 POF\u3001Contact pad\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;FBG \u00b7 Arm angle&lt;\/td&gt;&lt;td&gt;\u7edf\u4e00 angle gain&lt;\/td&gt;&lt;td&gt;Elbow 13.98 \/ 4.05 pm\/\u00b0&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1088\/1361-6501\/acd4d7\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Feng 2023 \u00b7 PDF pp6\u20138 \u4e2a\u4f53\u6807\u5b9a \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u4e24\u4f4d\u7a7f\u6234\u8005\uff1bWrist pitch 13.67 \/ 4.20 pm\/\u00b0\u3002\u8bf4\u660e\u4e2a\u4f53\u4e0e\u5b89\u88c5\u4f9d\u8d56\uff1b\u4e0d\u80fd\u6362\u6210 Intensity gain\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;FBG \u00b7 Force&lt;\/td&gt;&lt;td&gt;Contact = 0.65 \u00b7 c&lt;\/td&gt;&lt;td&gt;9.2 \/ 17.6 \/ 19.0 pm\/N&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1109\/JSEN.2022.3226039\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Di Palma 2023 \u00b7 PDF pp4\u20135 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u4e09\u79cd\u7845\u80f6\u5c01\u88c5\u30010\u201310N\u5206\u5e03\u8f7d\u8377\u3002\u53ea\u4f5c\u529b\u7075\u654f\u5ea6\u53c2\u8003\uff0c\u4e0d\u80fd\u66ff\u4ee30.65\u8fd9\u4e00\u65e0\u91cf\u7eb2\u5047\u8bbe\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;FBG \u00b7 Wearable accuracy&lt;\/td&gt;&lt;td&gt;\u4e00\u4e2a\u901a\u7528\u7cbe\u5ea6&lt;\/td&gt;&lt;td&gt;9.75 \/ 8.50 pm\/\u00b0\uff1bmean MAE 0.80\u00b0&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1109\/JSEN.2020.3046521\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Jha 2021 \u00b7 PDF pp5\u20136 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u6162\u901f\u6307\u5173\u8282\u3001IMU\u53c2\u8003\u3001\u53d7\u63a7\u6761\u4ef6\uff1b\u4e0d\u662f\u673a\u5668\u4eba\u52a8\u4f5c\/\u63a5\u89e6\u8bc6\u522b\u7387\u6216 Noise \u03c3\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Bench \u2260 worn&lt;\/td&gt;&lt;td&gt;\u628a\u53f0\u67b6\u8bef\u5dee\u76f4\u63a5\u79fb\u690d&lt;\/td&gt;&lt;td&gt;18.45 pm\/\u00b0\uff1bRMSE 0.13\u00b0 \/ 0.41\u00b0&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1364\/OFS.2018.WB4\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Jha 2018 \u00b7 PDF pp3\u20134 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u5f39\u7c27\u8026\u5408 FBG\uff1b\u524d\u8005\u53f0\u67b6\u3001\u540e\u8005\u4eba\u624b\u3002\u53ea\u6bd4\u8f83\u5404\u81ea\u5b9e\u9a8c\uff0c\u4e0d\u80fd\u7ed9\u5f53\u524d\u6f14\u793a\u6807\u6210\u5b9e\u6d4b\u7cbe\u5ea6\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Noise \/ Offset \/ Drift&lt;\/td&gt;&lt;td&gt;0.46 \/ 0.25 \/ 0.40 \u500d\u7387&lt;\/td&gt;&lt;td&gt;\u672a\u6807\u5b9a \u00b7 \u4fdd\u7559 illustrative&lt;\/td&gt;&lt;td&gt;&lt;a href=\\&quot;https:\/\/doi.org\/10.1049\/el:19900066\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;Morkel 1990\uff1bDyer 2005\uff1bTI \/ ADI\u539f\u7406\u6838\u5bf9 \u2197&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;\u7f3a\u5c11\u5149\u529f\u7387\u3001\u8bfb\u51fa\u589e\u76ca\u3001Noise spectrum\u3001Offset(T)\u3001\u65f6\u95f4\u5c3a\u5ea6\u3002\u8bba\u6587\u7684\u89d2\u5ea6\u8bef\u5dee\u4e0e\u6ce2\u957f\u8bef\u5dee\u4e0d\u80fd\u4f5c\u4e3a\u8fd9\u4e9b\u6ed1\u6761\u7684\u5e45\u5ea6\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Bandwidth \/ Threshold&lt;\/td&gt;&lt;td&gt;\u03b1 = 0.009^(1\u2212BW)\uff1bThreshold 0.17&lt;\/td&gt;&lt;td&gt;\u672a\u6807\u5b9a \u00b7 \u65e0 Hz \u6216\u53ef\u9760\u68c0\u51fa\u7387&lt;\/td&gt;&lt;td&gt;\u5f53\u524d\u4fe1\u53f7\u6a21\u578b\uff0c\u975e\u6587\u732e\u62df\u5408&lt;\/td&gt;&lt;td&gt;\u5fc5\u987b\u7531\u5b9e\u6d4b step response \/ frequency response \u548c\u65e0\u63a5\u89e6\u3001\u63a5\u89e6\u6837\u672c\u51b3\u5b9a\uff1bReplay \u65f6\u957f\u4e0d\u662f\u7269\u7406\u91c7\u6837\u5468\u671f\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;Legacy electronics&lt;\/td&gt;&lt;td&gt;2\u00b5W\u30010.45A\/W\u30011M\u03a9\u7b49\u65e7\u793a\u4f8b\u503c&lt;\/td&gt;&lt;td&gt;\u672a\u6821\u51c6\uff1b\u975e\u5f53\u524d\u8054\u52a8\u66f2\u7ebf\u4f9d\u636e&lt;\/td&gt;&lt;td&gt;arm-model.js\uff1bhardwareSignals()\u62bd\u8c61\u6f14\u793a&lt;\/td&gt;&lt;td&gt;\u65e7\u4e09\u901a\u9053\u6a21\u578b\u3001\u7535\u6c14\u589e\u76ca\u3001\u8bef\u5dee\u9608\u503c\u53ca\u5404\u5668\u4ef6\u72ec\u7acb\u793a\u610f\u5747\u4e0d\u80fd\u56e0\u672c\u6b21\u6587\u732e\u6838\u67e5\u800c\u89c6\u4e3a\u771f\u5b9e\u8bbe\u8ba1\u53c2\u6570\u3002&lt;\/td&gt;&lt;\/tr&gt;&lt;\/tbody&gt;&lt;\/table&gt;&lt;\/div&gt;&lt;h3&gt;\u5f2f\u66f2\u66f2\u7ebf\uff1a\u53ea\u6bd4\u8f83\u5f62\u72b6\uff0c\u4e0d\u5192\u5145\u673a\u5668\u4eba\u7cbe\u5ea6&lt;\/h3&gt;&lt;svg class=\\&quot;evidence-comparison\\&quot; viewBox=\\&quot;0 0 500 230\\&quot; role=\\&quot;img\\&quot; aria-label=\\&quot;Original quadratic loss versus normalized Bilro subject A fit over0\u201375degrees\\&quot;&gt;&lt;path d=\\&quot;M40 20V180H460\\&quot; fill=\\&quot;none\\&quot; stroke=\\&quot;#a0b49b\\&quot;\/&gt;&lt;path d=\\&quot;M40.00,180.00 L45.60,179.98 L51.20,179.91 L56.80,179.80 L62.40,179.65 L68.00,179.45 L73.60,179.21 L79.20,178.93 L84.80,178.60 L90.40,178.23 L96.00,177.81 L101.60,177.35 L107.20,176.84 L112.80,176.30 L118.40,175.71 L124.00,175.07 L129.60,174.39 L135.20,173.67 L140.80,172.90 L146.40,172.09 L152.00,171.24 L157.60,170.34 L163.20,169.40 L168.80,168.41 L174.40,167.38 L180.00,166.31 L185.60,165.19 L191.20,164.03 L196.80,162.82 L202.40,161.57 L208.00,160.28 L213.60,158.94 L219.20,157.56 L224.80,156.14 L230.40,154.67 L236.00,153.16 L241.60,151.60 L247.20,150.00 L252.80,148.36 L258.40,146.67 L264.00,144.94 L269.60,143.17 L275.20,141.35 L280.80,139.49 L286.40,137.58 L292.00,135.63 L297.60,133.64 L303.20,131.60 L308.80,129.52 L314.40,127.39 L320.00,125.22 L325.60,123.01 L331.20,120.75 L336.80,118.45 L342.40,116.11 L348.00,113.72 L353.60,111.29 L359.20,108.81 L364.80,106.29 L370.40,103.73 L376.00,101.12 L381.60,98.47 L387.20,95.77 L392.80,93.03 L398.40,90.25 L404.00,87.43 L409.60,84.56 L415.20,81.64 L420.80,78.68 L426.40,75.68 L432.00,72.64 L437.60,69.55 L443.20,66.41 L448.80,63.24 L454.40,60.01 L460.00,56.75\\&quot; stroke=\\&quot;#99a491\\&quot; stroke-dasharray=\\&quot;5 4\\&quot; fill=\\&quot;none\\&quot; stroke-width=\\&quot;2\\&quot;\/&gt;&lt;path d=\\&quot;M40.00,180.00 L45.60,179.16 L51.20,178.32 L56.80,177.47 L62.40,176.62 L68.00,175.76 L73.60,174.90 L79.20,174.03 L84.80,173.15 L90.40,172.28 L96.00,171.39 L101.60,170.50 L107.20,169.61 L112.80,168.71 L118.40,167.80 L124.00,166.89 L129.60,165.97 L135.20,165.05 L140.80,164.12 L146.40,163.18 L152.00,162.24 L157.60,161.29 L163.20,160.34 L168.80,159.38 L174.40,158.41 L180.00,157.44 L185.60,156.46 L191.20,155.47 L196.80,154.48 L202.40,153.48 L208.00,152.47 L213.60,151.46 L219.20,150.44 L224.80,149.41 L230.40,148.37 L236.00,147.33 L241.60,146.28 L247.20,145.22 L252.80,144.15 L258.40,143.08 L264.00,142.00 L269.60,140.91 L275.20,139.81 L280.80,138.70 L286.40,137.59 L292.00,136.46 L297.60,135.33 L303.20,134.19 L308.80,133.04 L314.40,131.88 L320.00,130.71 L325.60,129.53 L331.20,128.34 L336.80,127.14 L342.40,125.93 L348.00,124.72 L353.60,123.49 L359.20,122.25 L364.80,121.00 L370.40,119.74 L376.00,118.46 L381.60,117.18 L387.20,115.89 L392.80,114.58 L398.40,113.26 L404.00,111.93 L409.60,110.59 L415.20,109.23 L420.80,107.87 L426.40,106.49 L432.00,105.09 L437.60,103.68 L443.20,102.26 L448.80,100.83 L454.40,99.38 L460.00,97.91\\&quot; fill=\\&quot;none\\&quot; stroke=\\&quot;#19775c\\&quot; stroke-width=\\&quot;2.5\\&quot;\/&gt;&lt;g font-size=\\&quot;12\\&quot; fill=\\&quot;#42644e\\&quot;&gt;&lt;text x=\\&quot;40\\&quot; y=\\&quot;15\\&quot;&gt;Normalized loss&lt;\/text&gt;&lt;text x=\\&quot;40\\&quot; y=\\&quot;198\\&quot;&gt;0\u00b0&lt;\/text&gt;&lt;text x=\\&quot;435\\&quot; y=\\&quot;198\\&quot;&gt;75\u00b0&lt;\/text&gt;&lt;text x=\\&quot;40\\&quot; y=\\&quot;221\\&quot;&gt;Green: POF reference \u00b7 Dashed: original assumption&lt;\/text&gt;&lt;\/g&gt;&lt;\/svg&gt;&lt;p&gt;\u4e3a\u6bd4\u8f83\uff0c\u5c06\u539f\u65e0\u91cf\u7eb2Bend\u5750\u6807u\u6620\u5c04\u4e3a\u03b8\/75\u00b0\uff1b\u539f\u4e8c\u6b21\u5f0f\u4ecd\u662f\u6559\u5b66\u5047\u8bbe\u3002\u7eff\u8272\u66f2\u7ebf\u7531\u8bba\u6587\u62a5\u544a\u7684Subject A\u62df\u5408\u5f52\u4e00\u5316\u63a8\u5bfc\uff0c\u4e0d\u662f\u91cd\u65b0\u6d4b\u91cf\uff0c\u4e5f\u6ca1\u6709\u539f\u59cb\u6570\u636e\u53ef\u8ba1\u7b97\u65b0\u7684\u7f6e\u4fe1\u5e26\u3002\u4e3b\u6f14\u793a\u4e2d\u5207\u6362Bend curve\u4ec5\u6539\u53d8\u5f2f\u66f2\u80cc\u666f\uff1bContact\u3001\u566a\u58f0\u4e0e\u54cd\u5e94\u4ecd\u662f\u5408\u6210\u793a\u610f\u3002&lt;\/p&gt;&lt;h3&gt;Cross-check\u53d1\u73b0\u7684\u539f\u6587\u77db\u76fe&lt;\/h3&gt;&lt;ul&gt;&lt;li&gt;Bilro PDF p5 Table3\uff1aSubject B slope\u5370\u4e3a+0.0068\uff0c\u800cTable2\u4e94\u5929\u5747\u4e3a\u8d1f\uff0c\u5747\u503c\u22120.006796\u3002\u672c\u6b21\u53ea\u91c7\u7528\u65e0\u6b64\u7b26\u53f7\u51b2\u7a81\u7684Subject A\u62a5\u544a\u62df\u5408\uff1b\u62df\u5408\u7cfb\u6570\u4e0d\u662f\u539f\u59cb\u65f6\u5e8f\u6570\u636e\u3002&lt;\/li&gt;&lt;li&gt;Othonos PDF p17\uff1a\u6b63\u6587\u9884\u8ba113.7pm\/\u00b0C\uff0cFig26\u5b9e\u6d4b\u62df\u540812.8pm\/\u00b0C\uff0c\u5370\u51fa\u6750\u6599\u7cfb\u6570\u4ee3\u51651550nm\u4e3a14.1825pm\/\u00b0C\u3002\u5206\u522b\u4fdd\u7559\uff0c\u4e0d\u5e73\u5747\u3001\u4e0d\u7528\u5176\u4e89\u8bae\u4f30\u8ba1\u6821\u51c6\u3002Fig25\u5e94\u53d8\u62df\u54081.21pm\/\u00b5\u03b5\u53ef\u4f5c\u91cf\u7ea7\u4ea4\u53c9\u68c0\u67e5\u3002&lt;\/li&gt;&lt;li&gt;Li 2021 PDF p3 Fig4(b)\uff1anm\/%\u8f74\u768420.295\/20.777\u659c\u7387\u5e94\u6362\u7b97\u4e3a2.0295\/2.0777pm\/\u00b5\u03b5\uff0c\u4e0e\u6b63\u658720.30\/20.78pm\/\u00b5\u03b5\u5dee10\u500d\uff1b\u6392\u9664\u8fd9\u4e00\u4e89\u8bae\u7cfb\u6570\u3002&lt;\/li&gt;&lt;li&gt;Di Palma PDF p5\uff1a10N \/ 3cm\u00b2 = 3.33\u00d710\u2074Pa\uff0c\u4e0e\u5370\u51fa\u76843.33\u00d710\u2075Pa\u4e0d\u7b26\uff0c\u9762\u79ef\u4e5f\u4e0e\u53e6\u4e00\u5904\u5916\u5f62\u63cf\u8ff0\u4e0d\u4e00\u81f4\uff1b\u672c\u6b21\u53ea\u5f15\u7528Force\uff0c\u4e0d\u4f7f\u7528Pressure\u6362\u7b97\u3002&lt;\/li&gt;&lt;li&gt;Feng PDF p7\uff1a\u7537\u8155\u6eda\u8f6c\u91cd\u590d\u659c\u73876.61\u30016.67\u30016.68\u76f8\u5bf9\u4e2a\u4f537.12\u7684\u5e73\u5747\u504f\u5dee\u4e3a6.55%\uff0c\u4e0e\u6b63\u65872.52%\u4e0d\u7b26\uff1b\u4e0d\u5f15\u7528\u8be5\u6c47\u603b\u8bef\u5dee\u4e3a\u7cfb\u7edf\u7cbe\u5ea6\u3002&lt;\/li&gt;&lt;li&gt;Jha 2021 PDF p6 TableI mean Range\u4e3a1.77\u00b0\uff0c\u6b63\u6587\u4e3a1.75\u00b0\uff1b\u6309\u8868\u683c\u8bb0\u5f55\u5e76\u6807\u6ce8\u51b2\u7a81\u3002&lt;\/li&gt;&lt;\/ul&gt;&lt;h3&gt;\u8fd8\u7f3a\u4ec0\u4e48\uff0c\u624d\u80fd\u6821\u51c6\u771f\u5b9e\u8896\u5957\uff1f&lt;\/h3&gt;&lt;p&gt;\u2460 \u540c\u6b65\u8bb0\u5f55\u65e0\u63a5\u89e6\u7684Angle\u4e0eLight\/Dark\/Reference\uff0c\u5206\u89d2\u5ea6\u3001\u65b9\u5411\u3001\u901f\u5ea6\u3001\u6e29\u5ea6\u548c\u91cd\u65b0\u5b89\u88c5\u6279\u6b21\u62df\u5408Bend baseline\uff1b\u2461 \u5728\u4e0d\u540c\u89d2\u5ea6\u7528\u5df2\u77e5\u8f7d\u8377\u6d4bContact\u54cd\u5e94\u4e0eHysteresis\uff1b\u2462 \u56fa\u5b9a\u8f93\u5165\u6d4bNoise histogram \/ spectrum\uff0c\u6d4b\u96f6\u70b9\u968f\u6e29\u5ea6\u4e0e\u65f6\u95f4\u53d8\u5316\uff0c\u6d4bStep response\uff1b\u2463 \u7528\u672a\u53c2\u4e0e\u62df\u5408\u7684\u63a5\u89e6\u548c\u7a7a\u8f7d\u6570\u636e\u9009\u62e9Threshold\u5e76\u9a8c\u8bc1False alarm\u3001Miss\u3001Latency\u3002\u6ca1\u6709\u8fd9\u4e9b\u6570\u636e\uff0c\u4e0d\u80fd\u7ed9\u51fa\u771f\u5b9e\u8bc6\u522b\u51c6\u786e\u7387\u3002&lt;\/p&gt;&lt;p&gt;\u786c\u4ef6\u539f\u7406\u4e5f\u4e0e &lt;a href=\\&quot;https:\/\/www.ti.com\/lit\/an\/snoa515a\/snoa515a.pdf\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;TI AN-1803&lt;\/a&gt;\u3001&lt;a href=\\&quot;https:\/\/www.analog.com\/en\/resources\/analog-dialogue\/articles\/adc-input-noise.html\\&quot; target=\\&quot;_blank\\&quot; rel=\\&quot;noopener\\&quot;&gt;ADI ADC Input Noise&lt;\/a&gt; \u4ea4\u53c9\u6838\u5bf9\uff1aTIA\u7684\u566a\u58f0\u3001\u589e\u76ca\u548c\u54cd\u5e94\u76f8\u5173\uff1bADC\u8f93\u5165\u566a\u58f0\u5e94\u7531\u56fa\u5b9a\u8f93\u5165\u6837\u672c\u4f30\u8ba1\uff0c\u4e0d\u80fd\u7528Quantization\u6216\u52a8\u4f5c\u8bef\u5dee\u66ff\u4ee3\u3002&lt;\/p&gt;&quot;;\n&lt;\/script&gt;&lt;script&gt;\/* Normalized, linear equivalent readout; not a component or classifier specification. *\/\n(function(root,factory){if(typeof module==='object'&amp;&amp;module.exports)module.exports=factory();else root.SignalEffects=factory();})(typeof globalThis!=='undefined'?globalThis:this,function(){\n  'use strict';\n  const DEFAULT={noise:0,offset:0,drift:0,bandwidth:100,scene:'both',zero:false,matched:false};\n  const N=360,THRESHOLD=.17;\n  const clamp=(x,a,b)=&gt;Math.max(a,Math.min(b,Number.isFinite(+x)?+x:0));\n  function lowpass(values,alpha,initial=values[0]){let y=initial;return values.map((x,i)=&gt;(y+=(Array.isArray(alpha)?alpha[i]:alpha)*(x-y)));}\n  function noisePattern(){let seed=179;const a=Array.from({length:N},()=&gt;{let v=0;for(let j=0;j&lt;3;j++){seed=(Math.imul(seed,1664525)+1013904223)&gt;&gt;&gt;0;v+=seed\/4294967296-.5;}return v\/1.5;});const mean=a.reduce((s,v)=&gt;s+v,0)\/N;return a.map(v=&gt;v-mean);}\n  const NOISE=noisePattern();\n  \/\/ One repeatable normalized-time noise realization, independent of UI redraws.\n  function noiseAt(t){const x=clamp(t,0,1)*(N-1),i=Math.floor(x),f=x-i;return NOISE[i]*(1-f)+NOISE[Math.min(i+1,N-1)]*f;}\n  function compute(options={},inputTrace=null){\n    const s={...DEFAULT,...options},noise=clamp(s.noise,0,100)\/100,offset=clamp(s.offset,-100,100)\/100*.25,drift=clamp(s.drift,-100,100)\/100*.40,bw=clamp(s.bandwidth,0,100)\/100;\n    if(inputTrace!==null&amp;&amp;(!Array.isArray(inputTrace)||inputTrace.length&lt;2||inputTrace.some((p,i)=&gt;\n      !['t','baseline','residual','loss','contact'].every(k=&gt;Number.isFinite(p?.[k]))||p.t&lt;0||p.t&gt;1||(i&gt;0&amp;&amp;p.t&lt;=inputTrace[i-1].t))))throw new TypeError('Expected a finite motion trace with increasing normalized time.');\n    const alpha=Math.pow(.009,1-bw),time=inputTrace?inputTrace.map(p=&gt;p.t):Array.from({length:N},(_,i)=&gt;i\/(N-1));\n    const bend=inputTrace?inputTrace.map(p=&gt;p.baseline):time.map(t=&gt;s.scene==='contact'||t&lt;.10||t&gt;.88?0:.55*Math.pow(Math.sin(Math.PI*(t-.10)\/.78),2));\n    const contact=inputTrace?inputTrace.map(p=&gt;p.residual):time.map(t=&gt;s.scene!=='bend'&amp;&amp;t&gt;=.66&amp;&amp;t&lt;=.74?.40:0);\n    const ideal=inputTrace?inputTrace.map(p=&gt;p.loss):bend.map((v,i)=&gt;v+contact[i]);\n    const raw=ideal.map((v,i)=&gt;v+noise*.46*noiseAt(time[i])+offset+drift*time[i]);\n    \/\/ Preserve one response in normalized time when the motion sampling grid changes.\n    \/\/ The first sample is the initial condition; later steps use their actual time gap.\n    const response=inputTrace?time.map((t,i)=&gt;i===0?0:1-Math.pow(1-alpha,(t-time[i-1])*(N-1))):alpha;\n    \/\/ Start at the settled, no-contact DC level; no artificial turn-on transient.\n    const measured=lowpass(raw,response,inputTrace?raw[0]:offset),filteredBend=lowpass(bend,response,inputTrace?bend[0]:0);\n    const baseline=s.matched?filteredBend:bend;\n    \/\/ An ideal initial zero calibration removes the constant offset, not subsequent drift.\n    const residual=measured.map((v,i)=&gt;v-baseline[i]-(s.zero?offset:0));\n    const truth=inputTrace?inputTrace.map(p=&gt;p.contact&gt;1e-8):contact.map(v=&gt;v&gt;0),detected=residual.map(v=&gt;v&gt;THRESHOLD);\n    const falseAlarm=detected.map((v,i)=&gt;v&amp;&amp;!truth[i]),miss=truth.map((v,i)=&gt;v&amp;&amp;!detected[i]);\n    const start=truth.findIndex(Boolean),end=truth.lastIndexOf(true);\n    const firstAfter=start&lt;0?-1:detected.findIndex((v,i)=&gt;v&amp;&amp;i&gt;=start);\n    const onset=Math.max(0,firstAfter-start),overlap=truth.filter((v,i)=&gt;v&amp;&amp;detected[i]).length;\n    const hasContact=start&gt;=0,hasFalse=falseAlarm.some(Boolean),hasMiss=miss.some(Boolean);\n    \/\/ A smooth contact takes time to reach Threshold even in an ideal readout.\n    \/\/ Added latency is relative to that ideal cue, not the first infinitesimal touch.\n    const idealFirst=contact.findIndex(v=&gt;v&gt;THRESHOLD);\n    const late=hasContact&amp;&amp;firstAfter&gt;=0&amp;&amp;(inputTrace?idealFirst&gt;=0&amp;&amp;time[firstAfter]-time[idealFirst]&gt;2\/(N-1)+1e-12:onset&gt;2);\n    return {time,bend,contact,ideal,raw,measured,baseline,residual,truth,detected,falseAlarm,miss,threshold:THRESHOLD,alpha,\n      sourceTrace:inputTrace,opticalPower:inputTrace?inputTrace.map(p=&gt;p.power):ideal.map(v=&gt;Math.exp(-v)),\n      status:{hasContact,hasFalse,hasMiss,late,overlap,start,end,firstAfter,idealFirst}};\n  }\n  return {DEFAULT,compute,lowpass};\n});\n&lt;\/script&gt;&lt;script&gt;'use strict';\nconst HW_STATE={selected:'tia',levels:Object.fromEntries(window.ARM_HARDWARE.blocks.map(b=&gt;[b.id,b.default]))};\nconst FLOW_IDS=['driver','led','fiber','pd','tia','filter','adc','mcu'];\nconst blockById=id=&gt;HW.blocks.find(b=&gt;b.id===id);\nfunction hardwareIcon(id){\n  const art={\n    driver:'&lt;path d=&quot;M4 24H14V9H38V24H48&quot;\/&gt;&lt;path d=&quot;M4 30H48&quot; class=&quot;faint&quot;\/&gt;',\n    led:'&lt;path d=&quot;M5 24H17L25 12L33 24H44&quot;\/&gt;&lt;path d=&quot;M32 10L40 3M39 15L48 10&quot;\/&gt;',\n    fiber:'&lt;path d=&quot;M3 22C16 22 14 5 26 5S35 28 49 28&quot;\/&gt;&lt;circle cx=&quot;25&quot; cy=&quot;5&quot; r=&quot;3&quot;\/&gt;',\n    pd:'&lt;path d=&quot;M4 6L15 13M7 1L18 8M21 6V27L39 17Z M39 6V27 M39 17H49&quot;\/&gt;',\n    tia:'&lt;path d=&quot;M15 4V29L38 17Z M3 17H15M38 17H49&quot;\/&gt;&lt;text x=&quot;20&quot; y=&quot;21&quot;&gt;\u00b1&lt;\/text&gt;',\n    filter:'&lt;path d=&quot;M3 17L8 6L13 27L18 8L23 25&quot; class=&quot;faint&quot;\/&gt;&lt;path d=&quot;M27 17Q33 4 39 17T51 17&quot;\/&gt;',\n    adc:'&lt;path d=&quot;M3 26H12V20H22V13H32V7H46&quot;\/&gt;&lt;circle cx=&quot;12&quot; cy=&quot;20&quot; r=&quot;2&quot;\/&gt;&lt;circle cx=&quot;32&quot; cy=&quot;7&quot; r=&quot;2&quot;\/&gt;',\n    mcu:'&lt;rect x=&quot;14&quot; y=&quot;6&quot; width=&quot;25&quot; height=&quot;24&quot; rx=&quot;3&quot;\/&gt;&lt;path d=&quot;M7 11H14M7 23H14M39 11H47M39 23H47&quot;\/&gt;&lt;text x=&quot;18&quot; y=&quot;23&quot;&gt;r&lt;\/text&gt;',\n    power:'&lt;path d=&quot;M8 12H22M15 5V19M31 17H44M4 28H48&quot;\/&gt;',\n    encoder:'&lt;circle cx=&quot;26&quot; cy=&quot;17&quot; r=&quot;13&quot;\/&gt;&lt;path d=&quot;M26 17L35 8M26 17H40&quot;\/&gt;&lt;text x=&quot;8&quot; y=&quot;29&quot;&gt;\u03b8&lt;\/text&gt;'\n  };\n  return `&lt;svg class=&quot;block-icon&quot; viewBox=&quot;0 0 54 34&quot; aria-hidden=&quot;true&quot;&gt;${art[id]}&lt;\/svg&gt;`;\n}\nfunction blockButton(id,i){const b=blockById(id),pos=[[1,1],[2,1],[3,1],[4,1],[4,2],[3,2],[2,2],[1,2]][i],dir=i===3?'down':i&gt;3?'left':'right';return `&lt;button class=&quot;flow-block ${b.kind} ${HW_STATE.selected===id?'is-selected':''}&quot; data-block=&quot;${id}&quot; aria-label=&quot;${b.name}&quot; aria-pressed=&quot;${HW_STATE.selected===id}&quot; style=&quot;--col:${pos[0]};--row:${pos[1]}&quot;&gt;${hardwareIcon(id)}&lt;strong&gt;${b.name}&lt;\/strong&gt;&lt;small&gt;${['Command \u2192 Current','Current \u2192 Light','Light \u2192 Modulated light','Light \u2192 Current','Current \u2192 Voltage','Voltage \u2192 Filtered voltage','Voltage \u2192 Code','Code \u2192 Features'][i]}&lt;\/small&gt;${LINKED_HARDWARE[id]?`&lt;em class=&quot;block-effects&quot;&gt;${LINKED_HARDWARE[id].primary.map(effectName).join(' \u00b7 ')}&lt;\/em&gt;`:''}${i&lt;7?`&lt;span class=&quot;flow-link ${dir}&quot; aria-hidden=&quot;true&quot;&gt;${i===3?'\u2193':i&gt;3?'\u2190':'\u2192'}&lt;\/span&gt;`:''}&lt;\/button&gt;`;}\nfunction auxButton(id){const b=blockById(id);return `&lt;button class=&quot;aux-block ${HW_STATE.selected===id?'is-selected':''}&quot; data-block=&quot;${id}&quot; aria-label=&quot;${b.name}&quot; aria-pressed=&quot;${HW_STATE.selected===id}&quot;&gt;${hardwareIcon(id)}&lt;strong&gt;${b.name}&lt;\/strong&gt;${LINKED_HARDWARE[id]?`&lt;em class=&quot;block-effects&quot;&gt;${LINKED_HARDWARE[id].primary.map(effectName).join(' \u00b7 ')}&lt;\/em&gt;`:''}&lt;\/button&gt;`;}\nfunction sleeve(){return intro('02 \/ HARDWARE','\u70b9\u5f00\u5668\u4ef6\uff0c\u770b\u4fe1\u53f7\u5982\u4f55\u53d8\u5316\u3002','\u70b9\u9009 TIA\u3001ADC\u3001LED DRIVER\u3001POWER\uff0c\u8fde\u63a5 Typical effects\u3001Priority metrics \u4e0e\u8bc6\u522b\u6ce2\u5f62\u3002')+`\n  &lt;section class=&quot;surface architecture-card&quot; aria-label=&quot;\u53ef\u70b9\u51fb\u786c\u4ef6\u67b6\u6784\u56fe&quot;&gt;&lt;div class=&quot;architecture-heading&quot;&gt;&lt;h2&gt;Signal chain&lt;\/h2&gt;&lt;div class=&quot;signal-key&quot;&gt;&lt;span&gt;Electrical&lt;\/span&gt;&lt;span&gt;Optical&lt;\/span&gt;&lt;span&gt;Digital&lt;\/span&gt;&lt;\/div&gt;&lt;\/div&gt;\n  &lt;div class=&quot;support-branch&quot;&gt;${auxButton('power')}&lt;span class=&quot;support-line&quot; aria-hidden=&quot;true&quot;&gt;&lt;\/span&gt;&lt;span&gt;Supply rails \u2192 active blocks&lt;\/span&gt;&lt;\/div&gt;\n  &lt;div class=&quot;flow-grid&quot; role=&quot;group&quot; aria-label=&quot;Main signal chain&quot;&gt;${FLOW_IDS.map(blockButton).join('')}&lt;\/div&gt;\n  &lt;div class=&quot;aux-row&quot;&gt;&lt;div class=&quot;support-branch encoder-branch&quot;&gt;${auxButton('encoder')}&lt;span class=&quot;support-line&quot; aria-hidden=&quot;true&quot;&gt;&lt;\/span&gt;&lt;span&gt;Angle + time \u2192 MCU&lt;\/span&gt;&lt;\/div&gt;&lt;span class=&quot;control-caption&quot;&gt;MCU \u2192 Control \u2192 LED DRIVER&lt;\/span&gt;&lt;\/div&gt;&lt;\/section&gt;\n  &lt;div class=&quot;linked-hardware-inspector&quot; id=&quot;hardware-inspector&quot; aria-label=&quot;\u5668\u4ef6\u8f93\u5165\u8f93\u51fa\u4e0e\u4fe1\u53f7\u8d28\u91cf\u6f14\u793a&quot;&gt;${hardwareInspector()}&lt;\/div&gt;\n  &lt;details class=&quot;details&quot;&gt;&lt;summary&gt;Technical sources&lt;\/summary&gt;&lt;div class=&quot;details-body&quot;&gt;${sources(HW.sources)}&lt;\/div&gt;&lt;\/details&gt;`;}\nfunction hardwareDetail(){const b=blockById(HW_STATE.selected);return `&lt;div class=&quot;inspector-heading&quot;&gt;&lt;div&gt;&lt;span class=&quot;eyebrow&quot;&gt;SELECTED BLOCK&lt;\/span&gt;&lt;h2&gt;${b.name}&lt;\/h2&gt;&lt;\/div&gt;&lt;span class=&quot;concept-tag&quot;&gt;CONCEPTUAL WAVEFORMS&lt;\/span&gt;&lt;\/div&gt;\n  &lt;div class=&quot;io-flow&quot;&gt;&lt;div class=&quot;io-card&quot;&gt;&lt;small&gt;INPUT&lt;\/small&gt;&lt;h3&gt;${b.input}&lt;\/h3&gt;&lt;div id=&quot;hardware-input-plot&quot;&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;div class=&quot;conversion-card&quot;&gt;${hardwareIcon(b.id)}&lt;strong&gt;${b.action}&lt;\/strong&gt;&lt;span class=&quot;conversion-arrow&quot; aria-hidden=&quot;true&quot;&gt;\u2192&lt;\/span&gt;&lt;code&gt;${esc(b.formula)}&lt;\/code&gt;&lt;\/div&gt;&lt;div class=&quot;io-card output&quot;&gt;&lt;small&gt;OUTPUT&lt;\/small&gt;&lt;h3&gt;${b.output}&lt;\/h3&gt;&lt;div id=&quot;hardware-output-plot&quot;&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;\/div&gt;\n  &lt;div class=&quot;effect-row&quot;&gt;&lt;label for=&quot;hardware-effect&quot;&gt;${b.control}&lt;span&gt;${b.low} \u2192 ${b.high}&lt;\/span&gt;&lt;\/label&gt;&lt;input id=&quot;hardware-effect&quot; type=&quot;range&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;${HW_STATE.levels[b.id]}&quot; aria-label=&quot;${b.control}&quot;&gt;&lt;button class=&quot;reset-effect&quot; data-hw-reset=&quot;true&quot;&gt;Reset&lt;\/button&gt;&lt;span class=&quot;effect-status&quot; id=&quot;hardware-effect-status&quot; aria-live=&quot;polite&quot;&gt;&lt;\/span&gt;&lt;\/div&gt;\n  &lt;div class=&quot;metric-pair&quot;&gt;${b.metrics.map((m,i)=&gt;`&lt;article&gt;&lt;span&gt;${i?'02':'01'}&lt;\/span&gt;&lt;div&gt;&lt;h3&gt;${m[0]}&lt;\/h3&gt;&lt;p&gt;${m[1]}&lt;\/p&gt;&lt;\/div&gt;&lt;\/article&gt;`).join('')}&lt;\/div&gt;&lt;p class=&quot;hardware-note&quot;&gt;${b.note}&lt;\/p&gt;&lt;p class=&quot;axis-note&quot;&gt;\u793a\u610f\u6ce2\u5f62\u91c7\u7528\u5404\u81ea\u5f52\u4e00\u5316\u5750\u6807\uff0c\u4ec5\u8bf4\u660e\u53d8\u5316\uff0c\u4e0d\u8868\u793a\u5b9e\u9645\u5e45\u503c\u3001\u5c3a\u5bf8\u6216\u989d\u5b9a\u6027\u80fd\u3002&lt;\/p&gt;`;}\nfunction hardwareInspector(){return LINKED_HARDWARE[HW_STATE.selected]?motionLab()+`&lt;details class=&quot;details conversion-detail&quot;&gt;&lt;summary&gt;Conversion \u00b7 Input \u2192 Output&lt;\/summary&gt;&lt;div class=&quot;details-body&quot;&gt;${hardwareDetail()}&lt;\/div&gt;&lt;\/details&gt;`:`&lt;section class=&quot;surface hardware-inspector&quot;&gt;${hardwareDetail()}&lt;\/section&gt;`;}\nfunction selectHardware(id){if(!blockById(id))return;stopMotion();HW_STATE.selected=id;if(LINKED_HARDWARE[id])applyHardwareImpact(id);$('#hardware-inspector').innerHTML=hardwareInspector();$$('[data-block]').forEach(x=&gt;{const active=x.dataset.block===id;x.classList.toggle('is-selected',active);x.setAttribute('aria-pressed',String(active));});updateHardware();updateMotion();updateSignalEffects();}\nfunction hardwareSignals(id,value){\n  const d=value\/100,n=160,times=Array.from({length:n},(_,i)=&gt;i\/(n-1)),sin=(t,f=1)=&gt;Math.sin(2*Math.PI*f*t),clamp=x=&gt;Math.max(.02,Math.min(.94,x));\n  let a=[],b=[],ghostA=null,ghostB=null,ghostLabel='',limit=null,dots=null,status='';\n  if(id==='driver'){a=times.map(t=&gt;t&gt;.2&amp;&amp;t&lt;.75?.78:.08);let y=.08;b=a.map((x,i)=&gt;{y+=(x-y)*(.025+.5*d);return y+.008*sin(i\/n,17);});status=d&lt;.3?'Long settling':'Faster settling';}\n  if(id==='led'){a=times.map(t=&gt;.62+.12*sin(t));b=a.map(x=&gt;x*(1-.55*d));ghostB=a;ghostLabel='Before drift';status=d&gt;.4?'Optical drift':'Stable drive, light may drift';}\n  if(id==='fiber'){a=times.map(t=&gt;.74+.025*sin(t));b=a.map(x=&gt;x*Math.exp(-2*d));ghostB=a;ghostLabel='Incident light';status=d&gt;.5?'Loss \u2191 \u00b7 Power \u2193':'Loss modulation';}\n  if(id==='pd'){a=times.map(t=&gt;(.12+.75*d)*(.75+.15*sin(t)));b=a.map(x=&gt;.82*x+.07);limit={y:.07,label:'Dark current'};status=d&lt;.2?'Background matters':'Light \u2192 Photocurrent';}\n  if(id==='tia'){a=times.map(t=&gt;.19+.14*sin(t,1.5));const raw=a.map(x=&gt;.05+(1+4*d)*x);b=raw.map(x=&gt;Math.min(.86,x));limit={y:.86,label:'Output limit'};status=raw.some(x=&gt;x&gt;.86)?'Clipping':'Linear region';}\n  if(id==='filter'){a=times.map(t=&gt;clamp(.5+.26*sin(t,1.5)+.09*sin(t,17)+.05*sin(t,31)));let y=a[0];b=a.map(x=&gt;{y+=(x-y)*(.6-.565*d);return y;});ghostB=a;ghostLabel='Raw input';status=d&gt;.6?'Smoother \u00b7 More delay':'Band limiting';}\n  if(id==='adc'){const f=t=&gt;.5+.33*sin(t,1.2),levels=2+Math.round(d*12),samples=13;a=times.map(f);const q=t=&gt;Math.round(f(t)*levels)\/levels;b=times.map(t=&gt;q(Math.floor(t*(samples-1))\/(samples-1)));dots=Array.from({length:samples},(_,i)=&gt;[i\/(samples-1),q(i\/(samples-1))]);ghostB=a;ghostLabel='Analog input';status=d&gt;.6?'Finer quantization':'Coarser quantization';}\n  if(id==='mcu'){const bg=times.map(t=&gt;.32+.12*sin(t)),contact=times.map(t=&gt;.48*d*Math.exp(-Math.pow((t-.62)\/.12,2)));a=bg.map((v,i)=&gt;v+contact[i]);b=contact;ghostA=bg;ghostLabel='Baseline';status=d&gt;.15?'Residual after compensation':'Baseline matched';}\n  if(id==='power'){a=times.map(t=&gt;.6+.10*sin(t,9)+.055*sin(t,2));b=a.map(x=&gt;.6+(x-.6)*(1-.96*d));ghostB=a;ghostLabel='Supply input';status=d&gt;.6?'Ripple reduced':'Residual ripple';}\n  if(id==='encoder'){a=times.map(t=&gt;.5+.3*sin(t));b=times.map(t=&gt;.5+.3*sin(t-.23*d));ghostB=a;ghostLabel='True angle';status=d&gt;.05?'Time misalignment':'Time aligned';}\n  return {a,b,ghostA,ghostB,ghostLabel,limit,dots,status};\n}\nfunction wavePlot(values,label,options={}){\n  const X=t=&gt;18+230*t,Y=y=&gt;116-92*y,path=arr=&gt;arr.map((v,i)=&gt;`${i?'L':'M'}${X(i\/(arr.length-1)).toFixed(2)},${Y(v).toFixed(2)}`).join(' '),ghost=options.ghost,tracePath=options.discrete&amp;&amp;options.dots?options.dots.map(([x,y],i)=&gt;i?`H${X(x).toFixed(2)}V${Y(y).toFixed(2)}`:`M${X(x).toFixed(2)},${Y(y).toFixed(2)}`).join(' '):path(values);\n  return `&lt;svg class=&quot;wave-plot ${options.clipping?'clipped':''}&quot; viewBox=&quot;0 0 270 142&quot; role=&quot;img&quot; aria-label=&quot;${esc(label)} conceptual waveform${options.clipping?', clipping at output limit':''}&quot;&gt;&lt;path d=&quot;M18 13V116H248&quot; class=&quot;wave-axis&quot;\/&gt;&lt;path d=&quot;M18 70H248M18 24H248&quot; class=&quot;wave-grid&quot;\/&gt;${ghost?`&lt;path d=&quot;${path(ghost)}&quot; class=&quot;wave-ghost&quot;\/&gt;`:''}${options.limit?`&lt;path d=&quot;M18 ${Y(options.limit.y)}H248&quot; class=&quot;wave-limit&quot;\/&gt;&lt;text x=&quot;246&quot; y=&quot;${Y(options.limit.y)-5}&quot; text-anchor=&quot;end&quot; class=&quot;wave-limit-label&quot;&gt;${options.limit.label}&lt;\/text&gt;`:''}&lt;path d=&quot;${tracePath}&quot; class=&quot;wave-line&quot;\/&gt;${(options.dots||[]).map(([x,y])=&gt;`&lt;path d=&quot;M${X(x)} 116V${Y(y)}&quot; class=&quot;sample-stem&quot;\/&gt;&lt;circle cx=&quot;${X(x)}&quot; cy=&quot;${Y(y)}&quot; r=&quot;2.7&quot; class=&quot;sample-dot&quot;\/&gt;`).join('')}&lt;text x=&quot;18&quot; y=&quot;137&quot; class=&quot;wave-label&quot;&gt;${esc(label)}&lt;\/text&gt;&lt;text x=&quot;248&quot; y=&quot;137&quot; text-anchor=&quot;end&quot; class=&quot;wave-label&quot;&gt;${options.discrete?'sample':'time'} \u2192&lt;\/text&gt;${ghost?`&lt;text x=&quot;20&quot; y=&quot;10&quot; class=&quot;ghost-label&quot;&gt;${esc(options.ghostLabel)} \u00b7 faint&lt;\/text&gt;`:''}&lt;\/svg&gt;`;\n}\nfunction updateHardware(){if(!$('#hardware-input-plot'))return;const item=blockById(HW_STATE.selected),data=hardwareSignals(item.id,HW_STATE.levels[item.id]);$('#hardware-input-plot').innerHTML=wavePlot(data.a,item.inputSymbol,{ghost:data.ghostA,ghostLabel:data.ghostLabel});$('#hardware-output-plot').innerHTML=wavePlot(data.b,item.outputSymbol,{ghost:data.ghostB,ghostLabel:data.ghostLabel,limit:data.limit,dots:data.dots,discrete:item.id==='adc',clipping:data.status==='Clipping'});$('#hardware-effect-status').textContent=data.status;$('#hardware-effect-status').classList.toggle('clipping',data.status==='Clipping');}\n&lt;\/script&gt;&lt;script&gt;'use strict';\nconst EFFECT_STATE={...window.SignalEffects.DEFAULT};\nconst EFFECT_CONTEXT={hardware:null,effect:null,custom:false};\nconst LINKED_HARDWARE=window.HARDWARE_EFFECTS;\nconst EFFECT_CONTROLS=[\n  {id:'noise',name:'Noise',hint:'\u968f\u673a\u8d77\u4f0f',min:0,max:100,left:'Quiet',right:'Noisy',icon:'M2 17L7 12L12 23L17 6L22 18L27 9L32 21L37 13L42 17'},\n  {id:'offset',name:'Offset',hint:'\u6574\u4f53\u5e73\u79fb',min:-100,max:100,left:'Negative',right:'Positive',icon:'M2 20H42M2 10H42M32 7L36 3L40 7M36 3V17'},\n  {id:'drift',name:'Drift',hint:'\u57fa\u7ebf\u6e38\u8d70',min:-100,max:100,left:'Falling',right:'Rising',icon:'M2 24C12 24 12 19 22 16S32 9 42 5'},\n  {id:'bandwidth',name:'Bandwidth',hint:'\u5e73\u6ed1 \u2194 \u8ddf\u968f',min:0,max:100,left:'Narrow',right:'Wide',icon:'M2 24H12V5H25V24H42M2 24C14 24 15 7 23 11S29 24 42 24'}\n];\nfunction effectLevel(id,value){if(id==='bandwidth')return value&lt;30?'Narrow':value&lt;70?'Medium':'Wide';if(id==='noise')return value===0?'None':value&lt;35?'Low':value&lt;70?'Medium':'High';return value===0?'Zero':`${value&lt;0?'\u2212':'+'} ${Math.abs(value)&lt;35?'Low':Math.abs(value)&lt;70?'Medium':'High'}`;}\nlet QUALITY_RESULT=null;\nfunction qualityControls(){return `&lt;div class=&quot;unified-effect-controls&quot;&gt;${EFFECT_CONTROLS.map(c=&gt;`&lt;div class=&quot;quality-control&quot; data-effect-control=&quot;${c.id}&quot;&gt;&lt;div class=&quot;quality-control-head&quot;&gt;&lt;svg viewBox=&quot;0 0 46 29&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;${c.icon}&quot;\/&gt;&lt;\/svg&gt;&lt;label for=&quot;quality-${c.id}&quot;&gt;&lt;b&gt;${c.name}&lt;\/b&gt;&lt;span&gt;${c.hint}&lt;\/span&gt;&lt;\/label&gt;&lt;output id=&quot;quality-${c.id}-value&quot;&gt;${effectLevel(c.id,EFFECT_STATE[c.id])}&lt;\/output&gt;&lt;\/div&gt;&lt;input type=&quot;range&quot; id=&quot;quality-${c.id}&quot; data-quality-input=&quot;${c.id}&quot; aria-label=&quot;${c.name}&quot; min=&quot;${c.min}&quot; max=&quot;${c.max}&quot; value=&quot;${EFFECT_STATE[c.id]}&quot;&gt;&lt;div class=&quot;quality-range-labels&quot;&gt;&lt;span&gt;${c.left}&lt;\/span&gt;&lt;span&gt;${c.right}&lt;\/span&gt;&lt;\/div&gt;&lt;\/div&gt;`).join('')}&lt;div class=&quot;quality-switches&quot;&gt;&lt;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;quality-zero&quot; ${EFFECT_STATE.zero?'checked':''}&gt;&lt;span&gt;Zero calibration&lt;small&gt;\u53bb\u6389\u56fa\u5b9a Offset&lt;\/small&gt;&lt;\/span&gt;&lt;\/label&gt;&lt;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;quality-matched&quot; ${EFFECT_STATE.matched?'checked':''}&gt;&lt;span&gt;Matched baseline&lt;small&gt;\u5339\u914d\u8fd0\u52a8\u54cd\u5e94\u7684\u5ef6\u8fdf&lt;\/small&gt;&lt;\/span&gt;&lt;\/label&gt;&lt;\/div&gt;&lt;\/div&gt;`;}\nfunction qualityModelNotes(){return `&lt;details class=&quot;quality-sources&quot;&gt;&lt;summary&gt;Model &amp; sources \u00b7 Equivalent readout&lt;\/summary&gt;&lt;p&gt;\u5f52\u4e00\u5316\u6559\u5b66\u793a\u610f\uff0c\u56fa\u5b9a\u5750\u6807\uff1b\u4e0d\u662f\u5668\u4ef6\u4f20\u9012\u51fd\u6570\u3002POF reference \u53ea\u501f\u7528 Bilro \u819d\u90e8\u88c5\u7f6e\u7684\u5f2f\u66f2\u62df\u5408\uff1bContact\u3001Noise\u3001Offset\u3001Drift\u3001Bandwidth \u548c Threshold \u5747\u672a\u7ecf\u8fc7\u673a\u5668\u4eba\u5b9e\u7269\u6807\u5b9a\u3002Measured = H(Ideal + Noise + Offset + Drift)\u3002Residual = Measured \u2212 Bend baseline\uff0cZero calibration \u7406\u60f3\u5730\u53bb\u6389\u56fa\u5b9a Offset\uff1bMatched baseline \u4f7f\u7528\u76f8\u540c H\u3002Noise \u4f4d\u4e8e\u7b49\u6548 Filter \u524d\uff0cDrift \u7528\u5355\u5411\u53d8\u5316\u793a\u610f\u3002Threshold \u53ea\u4ea7\u751f Contact cue\uff1b\u5f31\u63a5\u89e6\u548c\u63a5\u89e6\u8fb9\u7f18\u53ef\u80fd\u4f4e\u4e8e Threshold\u3002&lt;\/p&gt;&lt;p&gt;\u5668\u4ef6\u9009\u62e9\u4ec5\u9ad8\u4eae\u5173\u6ce8\u70b9\uff1b\u6ed1\u6761\u4e3a\u5171\u4eab\u7684\u7cfb\u7edf\u5f71\u54cd\uff0c\u4e0d\u4ee3\u8868\u5404\u5668\u4ef6\u72ec\u7acb\u8bef\u5dee\u76f8\u52a0\u3002ADC Quantization \u2260 random Noise\uff1bLED DRIVER Settling \u5c5e\u4e8e\u8c03\u5236\u91c7\u6837\uff1bPOWER \u7ecf\u7535\u6e90\u8f68\u4e0e\u53c2\u8003\u95f4\u63a5\u8026\u5408\uff0cReference drift \u4e5f\u53ef\u80fd\u6539\u53d8 Gain\u3002&lt;\/p&gt;${sources([{label:'TIA noise \u00b7 TI',url:'https:\/\/www.ti.com\/lit\/an\/snoa515a\/snoa515a.pdf'},{label:'ADC noise \u00b7 ADI',url:'https:\/\/www.analog.com\/en\/resources\/analog-dialogue\/articles\/adc-input-noise.html'},{label:'Power coupling \u00b7 TI',url:'https:\/\/www.ti.com\/lit\/SLYY192'},{label:'Offset \/ Drift \u00b7 ADI',url:'https:\/\/www.analog.com\/media\/en\/training-seminars\/tutorials\/MT-037.pdf'},{label:'Filter response \u00b7 ADI',url:'https:\/\/www.analog.com\/en\/resources\/app-notes\/an-649.html'}])}&lt;\/details&gt;`;}\nfunction qualityPath(a,Y){return a.map((v,i)=&gt;`${i?'L':'M'}${(18+i*624\/(a.length-1)).toFixed(2)},${Y(v).toFixed(2)}`).join(' ');}\nfunction qualityRegions(flags,y,height,cls){let svg='',start=-1;for(let i=0;i&lt;=flags.length;i++){if(flags[i]&amp;&amp;start&lt;0)start=i;if(!flags[i]&amp;&amp;start&gt;=0){svg+=`&lt;rect x=&quot;${(18+start*624\/flags.length).toFixed(2)}&quot; y=&quot;${y}&quot; width=&quot;${Math.max(1,(i-start)*624\/flags.length).toFixed(2)}&quot; height=&quot;${height}&quot; class=&quot;${cls}&quot;\/&gt;`;start=-1;}}return svg;}\nfunction qualityY(v,residual=false){const min=-1.25,max=residual?1.75:2.75;return 170-(v-min)\/(max-min)*150;}\nfunction qualityWave(r,residual=false){const Y=v=&gt;qualityY(v,residual),zero=Y(0),line=residual?r.residual:r.measured;\n  return `&lt;svg class=&quot;quality-wave&quot; viewBox=&quot;0 0 660 190&quot; role=&quot;img&quot; aria-label=&quot;${residual?'Residual compared with Ideal contact and Threshold':'Ideal and Measured normalized loss readout with Bend baseline'}&quot;&gt;\n  ${qualityRegions(r.truth,7,166,'quality-contact-window')}\n  &lt;path class=&quot;quality-grid-line&quot; d=&quot;M18 ${Y(.5)}H642M18 ${Y(-.5)}H642&quot;\/&gt;&lt;path class=&quot;quality-axis&quot; d=&quot;M18 8V173H642M18 ${zero}H642&quot;\/&gt;\n  ${residual?`&lt;path class=&quot;quality-threshold&quot; d=&quot;M18 ${Y(r.threshold)}H642&quot;\/&gt;&lt;text x=&quot;640&quot; y=&quot;${Y(r.threshold)-5}&quot; text-anchor=&quot;end&quot; class=&quot;quality-svg-label&quot;&gt;Threshold&lt;\/text&gt;`:`&lt;path class=&quot;quality-baseline&quot; d=&quot;${qualityPath(r.baseline,Y)}&quot;\/&gt;`}\n  &lt;path class=&quot;quality-ideal&quot; d=&quot;${qualityPath(residual?r.contact:r.ideal,Y)}&quot;\/&gt;\n  &lt;path class=&quot;${residual?'quality-residual':'quality-measured'}&quot; d=&quot;${qualityPath(line,Y)}&quot;\/&gt;\n  &lt;line class=&quot;motion-cursor quality-time-cursor&quot; x1=&quot;18&quot; x2=&quot;18&quot; y1=&quot;8&quot; y2=&quot;173&quot;\/&gt;\n  &lt;circle class=&quot;quality-time-dot&quot; data-quality-dot=&quot;${residual?'residual':'measured'}&quot; r=&quot;4&quot; fill=&quot;${residual?'#bf7b47':'#24805e'}&quot; stroke=&quot;#fffefa&quot; stroke-width=&quot;1.5&quot;\/&gt;\n  &lt;text x=&quot;21&quot; y=&quot;${zero+13}&quot; class=&quot;quality-svg-label&quot;&gt;zero&lt;\/text&gt;&lt;text x=&quot;640&quot; y=&quot;187&quot; text-anchor=&quot;end&quot; class=&quot;quality-svg-label&quot;&gt;Time \u2192&lt;\/text&gt;\n  ${r.status.hasContact?`&lt;text x=&quot;${18+(r.time[r.status.start]+r.time[r.status.end])\/2*624}&quot; y=&quot;17&quot; text-anchor=&quot;middle&quot; class=&quot;quality-contact-label&quot;&gt;Contact&lt;\/text&gt;`:''}\n  &lt;\/svg&gt;`;}\nfunction updateQualityCursor(){if(!QUALITY_RESULT)return;const r=QUALITY_RESULT,t=MOTION.time,x=18+t*624,pos=t*(r.time.length-1),i=Math.floor(pos),f=pos-i;\n  $$('.quality-time-cursor').forEach(el=&gt;{el.setAttribute('x1',x);el.setAttribute('x2',x);});\n  $$('[data-quality-dot]').forEach(el=&gt;{const a=r[el.dataset.qualityDot],value=a[i]*(1-f)+a[Math.min(i+1,a.length-1)]*f;el.setAttribute('cx',x);el.setAttribute('cy',qualityY(value,el.dataset.qualityDot==='residual'));});\n}\nfunction qualityDecision(r){return `&lt;svg class=&quot;quality-decision&quot; viewBox=&quot;0 0 660 67&quot; role=&quot;img&quot; aria-label=&quot;True contact versus detected contact cue. Red regions are false alarms; hatched regions are missed contact.&quot;&gt;&lt;defs&gt;&lt;pattern id=&quot;quality-miss-hatch&quot; width=&quot;5&quot; height=&quot;5&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;&lt;rect width=&quot;5&quot; height=&quot;5&quot; fill=&quot;#f9e7c7&quot;\/&gt;&lt;path d=&quot;M-1 1L1 -1M0 5L5 0M4 6L6 4&quot; stroke=&quot;#bd8c44&quot; stroke-width=&quot;1&quot;\/&gt;&lt;\/pattern&gt;&lt;\/defs&gt;&lt;text x=&quot;18&quot; y=&quot;10&quot; class=&quot;quality-svg-label&quot;&gt;True contact&lt;\/text&gt;&lt;rect x=&quot;18&quot; y=&quot;15&quot; width=&quot;624&quot; height=&quot;11&quot; rx=&quot;2&quot; class=&quot;quality-lane&quot;\/&gt;${qualityRegions(r.truth,15,11,'quality-hit')}&lt;text x=&quot;18&quot; y=&quot;40&quot; class=&quot;quality-svg-label&quot;&gt;Detected cue&lt;\/text&gt;&lt;rect x=&quot;18&quot; y=&quot;45&quot; width=&quot;624&quot; height=&quot;11&quot; rx=&quot;2&quot; class=&quot;quality-lane&quot;\/&gt;${qualityRegions(r.detected,45,11,'quality-hit')}${qualityRegions(r.falseAlarm,45,11,'quality-false-fill')}${qualityRegions(r.miss,45,11,'quality-miss-fill')}&lt;line class=&quot;motion-cursor quality-time-cursor&quot; x1=&quot;18&quot; x2=&quot;18&quot; y1=&quot;4&quot; y2=&quot;60&quot;\/&gt;&lt;\/svg&gt;`;}\nfunction updateSignalEffects(){updateQualityContextState();if(!$('#quality-signal-plot'))return;const r=window.SignalEffects.compute(EFFECT_STATE,window.MotionModel.trace(MOTION,360)),s=r.status;QUALITY_RESULT=r;\n  $('#quality-signal-plot').innerHTML=qualityWave(r);$('#quality-residual-plot').innerHTML=qualityWave(r,true);$('#quality-decision-plot').innerHTML=qualityDecision(r);\n  $('#quality-equation').textContent=EFFECT_STATE.matched?'Measured \u2212 Matched baseline':'Measured \u2212 Static baseline';\n  if(EFFECT_STATE.zero)$('#quality-equation').textContent+=' \u2212 Offset';\n  for(const c of EFFECT_CONTROLS){const value=effectLevel(c.id,EFFECT_STATE[c.id]);$('#quality-'+c.id+'-value').textContent=value;$('#quality-'+c.id).setAttribute('aria-valuetext',value);$('#quality-'+c.id).value=EFFECT_STATE[c.id];}\n\n  const tags=[s.hasFalse?['False alarm','\u65e0\u63a5\u89e6\u65f6\u51fa\u73b0\u7ebf\u7d22','bad']:['No false alarm','\u5f53\u524d\u793a\u610f\u672a\u51fa\u73b0\u8bef\u62a5','good']];\n  if(s.hasContact)tags.push(!s.overlap?['Miss','\u63a5\u89e6\u671f\u95f4\u672a\u68c0\u51fa','bad']:s.hasMiss?['Below threshold','\u90e8\u5206\u63a5\u89e6\u4f4e\u4e8e Threshold','warn']:['Contact visible','\u63a5\u89e6\u7ebf\u7d22\u4fdd\u7559','good']);\n  else tags.push(['No contact','\u6ca1\u6709\u5916\u90e8 Contact','neutral']);\n  if(s.late)tags.push(['Delayed cue','\u7ebf\u7d22\u665a\u4e8e\u7406\u60f3 Contact cue','warn']);\n  $('#quality-verdict').innerHTML=tags.map(([name,note,kind])=&gt;`&lt;span class=&quot;${kind}&quot;&gt;&lt;b&gt;${name}&lt;\/b&gt;&lt;small&gt;${note}&lt;\/small&gt;&lt;\/span&gt;`).join('');updateQualityCursor();\n}\nfunction resetSignalEffects(){const scene=EFFECT_STATE.scene;Object.assign(EFFECT_STATE,window.SignalEffects.DEFAULT,{scene});EFFECT_CONTEXT.custom=true;for(const c of EFFECT_CONTROLS)$('#quality-'+c.id).value=EFFECT_STATE[c.id];$('#quality-zero').checked=false;$('#quality-matched').checked=false;updateSignalEffects();}\n\nfunction qualityHardwareTabs(){return `&lt;div class=&quot;quality-hardware-tabs&quot; role=&quot;group&quot; aria-label=&quot;Hardware effect shortcuts&quot;&gt;${['tia','adc','driver','power'].map(id=&gt;`&lt;button data-quality-hardware=&quot;${id}&quot; aria-pressed=&quot;${EFFECT_CONTEXT.hardware===id}&quot;&gt;${hardwareIcon(id)}&lt;strong&gt;${LINKED_HARDWARE[id].name}&lt;\/strong&gt;&lt;small&gt;${LINKED_HARDWARE[id].primary.map(effectName).join(' \u00b7 ')}&lt;\/small&gt;&lt;\/button&gt;`).join('')}&lt;\/div&gt;`;}\nfunction effectName(id){return EFFECT_CONTROLS.find(c=&gt;c.id===id)?.name||id;}\nfunction qualityHardwareContext(){const p=LINKED_HARDWARE[EFFECT_CONTEXT.hardware];if(!p)return '';\n  return `&lt;div class=&quot;linked-context&quot;&gt;&lt;div class=&quot;linked-route&quot;&gt;&lt;span&gt;${p.input}&lt;\/span&gt;&lt;i&gt;\u2192&lt;\/i&gt;&lt;b&gt;${p.name}&lt;\/b&gt;&lt;i&gt;${EFFECT_CONTEXT.hardware==='power'?'\u21e2':'\u2192'}&lt;\/i&gt;&lt;span&gt;${p.output}&lt;\/span&gt;&lt;\/div&gt;&lt;div class=&quot;linked-body&quot;&gt;&lt;div class=&quot;linked-effects&quot;&gt;${Object.keys(p.effects).map(id=&gt;`&lt;button data-hardware-impact=&quot;${id}&quot; aria-pressed=&quot;${EFFECT_CONTEXT.effect===id}&quot; class=&quot;${p.primary.includes(id)?'primary-impact':''}&quot;&gt;${effectName(id)}${p.primary.includes(id)?'&lt;i aria-label=&quot;priority&quot;&gt;\u25cf&lt;\/i&gt;':''}&lt;\/button&gt;`).join('')}&lt;\/div&gt;&lt;div class=&quot;linked-priorities&quot;&gt;${p.metrics.map(([name,note])=&gt;`&lt;div&gt;&lt;small&gt;PRIORITY&lt;\/small&gt;&lt;b&gt;${name}&lt;\/b&gt;&lt;span&gt;${note}&lt;\/span&gt;&lt;\/div&gt;`).join('')}&lt;\/div&gt;&lt;\/div&gt;&lt;div class=&quot;linked-explanation&quot;&gt;&lt;span id=&quot;linked-effect-path&quot;&gt;&lt;\/span&gt;&lt;\/div&gt;&lt;\/div&gt;`;\n}\n\/\/ Selection changes attention, never the user's physical inputs or shared effects.\nfunction applyHardwareImpact(id,effect){const p=LINKED_HARDWARE[id];if(!p)return;Object.assign(EFFECT_CONTEXT,{hardware:id,effect:p.effects[effect]?effect:p.defaultEffect});}\nfunction selectQualityHardware(id){if(!LINKED_HARDWARE[id])return;\n  if(current==='sleeve'){selectHardware(id);return;}\n  applyHardwareImpact(id);HW_STATE.selected=id;$('#quality-hardware-context').innerHTML=qualityHardwareContext();updateQualityContextState();\n}\nfunction selectHardwareImpact(effect){const p=LINKED_HARDWARE[EFFECT_CONTEXT.hardware];if(!p?.effects[effect])return;EFFECT_CONTEXT.effect=effect;updateQualityContextState();$('#quality-'+effect)?.focus({preventScroll:true});}\nfunction updateQualityContextState(){const p=LINKED_HARDWARE[EFFECT_CONTEXT.hardware];\n  $$('[data-quality-hardware]').forEach(b=&gt;b.setAttribute('aria-pressed',String(b.dataset.qualityHardware===EFFECT_CONTEXT.hardware)));\n  $$('[data-hardware-impact]').forEach(b=&gt;b.setAttribute('aria-pressed',String(b.dataset.hardwareImpact===EFFECT_CONTEXT.effect)));\n  $$('[data-effect-control]').forEach(e=&gt;{e.classList.toggle('is-priority',!!p?.primary.includes(e.dataset.effectControl));e.classList.toggle('is-focused',e.dataset.effectControl===EFFECT_CONTEXT.effect);});\n  if(p&amp;&amp;$('#linked-effect-path'))$('#linked-effect-path').textContent=p.effects[EFFECT_CONTEXT.effect]?.path||'\u8c03\u6574\u53f3\u4fa7 Shared effects\uff0c\u89c2\u5bdf\u540c\u4e00\u7ec4\u6ce2\u5f62';\n}\n&lt;\/script&gt;&lt;script&gt;(function(root,factory){\n  if(typeof module==='object'&amp;&amp;module.exports)module.exports=factory();\n  else root.MotionModel=factory();\n})(typeof globalThis!=='undefined'?globalThis:this,function(){\n  'use strict';\n  \/\/ Kersey 1997 PDF p2 Eqs3-4, scaled to1550nm; nominal bare-fiber response.\n  const FBG=Object.freeze({wavelengthNm:1550,strainFactor:.78,thermalPerC:6.67e-6,strainPmPerMicrostrain:1550*.78*.001,thermalPmPerC:1550*1000*6.67e-6});\n  \/\/ Bilro 2011 PDF p5 Table3 SubjectA; knee-brace voltage-ratio fit, not robot calibration.\n  const POF=Object.freeze({slopePerDegree:-.00649,intercept:1.126,maxAngleDeg:75});\n  const clamp=v=&gt;Math.max(0,Math.min(1,Number(v)||0));\n  function sample(time,options={}){\n    const t=clamp(time),scene=options.scene||'both';\n    const bendAmplitude=scene==='contact'?0:clamp(options.bend??.75);\n    const contactAmplitude=scene==='bend'?0:clamp(options.contact??.7);\n    const bend=bendAmplitude*Math.pow(Math.sin(Math.PI*t),2);\n    const u=(t-.54)\/.2;\n    const contact=u&gt;0&amp;&amp;u&lt;1?contactAmplitude*Math.pow(Math.sin(Math.PI*u),2):0;\n    const profile=options.profile==='bilro'?'bilro':'illustrative';\n    const referenceRatio=1+POF.slopePerDegree\/POF.intercept*(POF.maxAngleDeg*bend);\n    const baseline=profile==='bilro'?-Math.log(referenceRatio):.85*bend*bend;\n    const residual=.65*contact;\n    const loss=baseline+residual;\n    return {t,bend,contact,baseline,residual,loss,power:Math.exp(-loss),profile};\n  }\n  function trace(options={},count=201){\n    const n=Math.max(2,Math.round(Number(count)||201));\n    return Array.from({length:n},(_,i)=&gt;sample(i\/(n-1),options));\n  }\n  return {sample,trace,FBG,POF};\n});\n&lt;\/script&gt;&lt;script&gt;'use strict';\nconst MOTION={scene:'both',profile:'illustrative',bend:.75,contact:.7,time:.64,playing:false,frame:null,last:null};\nconst motionEl=id=&gt;document.getElementById(id);\nconst motionLevel=v=&gt;v===0?'None':v&lt;.34?'Low':v&lt;.68?'Medium':'High';\nconst motionScenes=[['bend','Bend only'],['contact','Contact only'],['both','Bend + contact']];\nconst motionReduced=window.matchMedia?window.matchMedia('(prefers-reduced-motion: reduce)'):null;\nconst motionPlayLabel=()=&gt;motionReduced&amp;&amp;motionReduced.matches?'\u25b7 Step':'\u25b6 Replay';\n\nfunction motionLab(){\n  if(!EFFECT_CONTEXT.hardware)applyHardwareImpact('tia');\n  return `&lt;section class=&quot;motion-lab unified-lab surface&quot; id=&quot;motion-lab&quot; aria-label=&quot;Signal quality interactive demo&quot;&gt;\n    &lt;div class=&quot;motion-heading&quot;&gt;&lt;div&gt;&lt;span class=&quot;eyebrow&quot;&gt;ONE INPUT \u00b7 ONE SIGNAL CHAIN&lt;\/span&gt;&lt;h2&gt;Move &amp;amp; touch + hardware&lt;\/h2&gt;&lt;\/div&gt;&lt;button class=&quot;reset-effect&quot; data-quality-reset=&quot;true&quot;&gt;Clear effects&lt;\/button&gt;&lt;\/div&gt;\n    &lt;div class=&quot;unified-grid&quot;&gt;&lt;div class=&quot;motion-input&quot;&gt;\n      &lt;div class=&quot;motion-scenes&quot; role=&quot;group&quot; aria-label=&quot;\u8fd0\u52a8\u4e0e\u63a5\u89e6\u573a\u666f&quot;&gt;${motionScenes.map(([id,label])=&gt;`&lt;button type=&quot;button&quot; data-motion-scene=&quot;${id}&quot; aria-pressed=&quot;${MOTION.scene===id}&quot; class=&quot;${MOTION.scene===id?'active':''}&quot;&gt;${label}&lt;\/button&gt;`).join('')}&lt;\/div&gt;\n        &lt;svg class=&quot;motion-arm&quot; viewBox=&quot;0 0 440 250&quot; aria-label=&quot;\u53ef\u62d6\u52a8\u673a\u5668\u4eba\u624b\u81c2\u4e0e Contact pad&quot;&gt;\n          &lt;defs&gt;&lt;pattern id=&quot;motion-knit&quot; width=&quot;8&quot; height=&quot;8&quot; patternUnits=&quot;userSpaceOnUse&quot;&gt;&lt;path d=&quot;M0 8L8 0&quot; stroke=&quot;#afc4a1&quot; stroke-width=&quot;.65&quot;\/&gt;&lt;\/pattern&gt;&lt;\/defs&gt;\n          &lt;path d=&quot;M38 90H410&quot; class=&quot;motion-guide&quot;\/&gt;\n          &lt;path d=&quot;M48 90H202&quot; class=&quot;motion-bone&quot; stroke-width=&quot;48&quot;\/&gt;\n          &lt;rect x=&quot;77&quot; y=&quot;60&quot; width=&quot;108&quot; height=&quot;60&quot; rx=&quot;18&quot; class=&quot;motion-sleeve&quot;\/&gt;\n          &lt;rect x=&quot;77&quot; y=&quot;60&quot; width=&quot;108&quot; height=&quot;60&quot; rx=&quot;18&quot; fill=&quot;url(#motion-knit)&quot;\/&gt;\n          &lt;circle cx=&quot;202&quot; cy=&quot;90&quot; r=&quot;30&quot; class=&quot;motion-joint&quot;\/&gt;&lt;circle cx=&quot;202&quot; cy=&quot;90&quot; r=&quot;14&quot; fill=&quot;#fffefa&quot; stroke=&quot;#adbea5&quot;\/&gt;\n          &lt;g id=&quot;motion-forearm&quot; transform=&quot;translate(202 90)&quot;&gt;\n            &lt;path d=&quot;M20 0H160&quot; class=&quot;motion-bone&quot; stroke-width=&quot;42&quot;\/&gt;\n            &lt;rect x=&quot;31&quot; y=&quot;-26&quot; width=&quot;112&quot; height=&quot;52&quot; rx=&quot;16&quot; class=&quot;motion-sleeve&quot;\/&gt;\n            &lt;rect x=&quot;31&quot; y=&quot;-26&quot; width=&quot;112&quot; height=&quot;52&quot; rx=&quot;16&quot; fill=&quot;url(#motion-knit)&quot;\/&gt;\n            &lt;path d=&quot;M35 8Q83 -13 141 8&quot; stroke=&quot;#19775c&quot; stroke-width=&quot;3&quot; fill=&quot;none&quot;\/&gt;\n            &lt;g data-motion-drag=&quot;bend&quot; role=&quot;slider&quot; tabindex=&quot;0&quot; aria-label=&quot;Drag arm&quot; aria-valuemin=&quot;0&quot; aria-valuemax=&quot;100&quot; aria-valuenow=&quot;75&quot;&gt;&lt;title&gt;\u62d6\u52a8\u624b\u81c2 \u00b7 Arrow keys \u8c03\u8282 Bend&lt;\/title&gt;&lt;circle cx=&quot;160&quot; cy=&quot;0&quot; r=&quot;23&quot; fill=&quot;transparent&quot;\/&gt;&lt;circle class=&quot;motion-handle&quot; cx=&quot;160&quot; cy=&quot;0&quot; r=&quot;10&quot; fill=&quot;#fffefa&quot; stroke=&quot;#19775c&quot; stroke-width=&quot;2&quot;\/&gt;&lt;path d=&quot;M155 -3H165M155 3H165&quot; stroke=&quot;#19775c&quot;\/&gt;&lt;\/g&gt;\n            &lt;rect id=&quot;motion-pad&quot; x=&quot;79&quot; y=&quot;-23&quot; width=&quot;36&quot; height=&quot;15&quot; rx=&quot;5&quot; fill=&quot;#edf4e1&quot; stroke=&quot;#19775c&quot;\/&gt;\n            &lt;g id=&quot;motion-touch&quot;&gt;&lt;path d=&quot;M97 -61V-36M90 -43L97 -35L104 -43&quot; stroke=&quot;#c37442&quot; stroke-width=&quot;2.5&quot; fill=&quot;none&quot;\/&gt;&lt;circle cx=&quot;97&quot; cy=&quot;-68&quot; r=&quot;4&quot; fill=&quot;#c37442&quot;\/&gt;&lt;\/g&gt;\n            &lt;g data-motion-drag=&quot;contact&quot; role=&quot;slider&quot; tabindex=&quot;0&quot; aria-label=&quot;Drag contact&quot; aria-valuemin=&quot;0&quot; aria-valuemax=&quot;100&quot; aria-valuenow=&quot;70&quot;&gt;&lt;title&gt;\u5411\u5185\u62d6\u52a8 Contact pad \u00b7 Arrow keys \u8c03\u8282\u63a5\u89e6&lt;\/title&gt;&lt;rect x=&quot;70&quot; y=&quot;-64&quot; width=&quot;54&quot; height=&quot;62&quot; rx=&quot;14&quot; fill=&quot;transparent&quot;\/&gt;&lt;circle class=&quot;motion-handle contact-handle&quot; cx=&quot;97&quot; cy=&quot;-43&quot; r=&quot;10&quot; fill=&quot;#fff7ee&quot; stroke=&quot;#c37442&quot; stroke-width=&quot;2&quot;\/&gt;&lt;path d=&quot;M93 -46L97 -42L101 -46&quot; fill=&quot;none&quot; stroke=&quot;#c37442&quot;\/&gt;&lt;\/g&gt;\n          &lt;\/g&gt;\n          &lt;path id=&quot;motion-fiber&quot; d=&quot;M100 105Q170 130 200 115&quot; stroke=&quot;#c37442&quot; stroke-width=&quot;4&quot; fill=&quot;none&quot; stroke-linecap=&quot;round&quot;\/&gt;\n          &lt;text x=&quot;38&quot; y=&quot;35&quot;&gt;BENDING&lt;\/text&gt;&lt;path d=&quot;M96 38L162 69&quot; class=&quot;motion-leader&quot;\/&gt;\n          &lt;text x=&quot;310&quot; y=&quot;35&quot;&gt;CONTACT&lt;\/text&gt;&lt;path d=&quot;M332 42V57&quot; class=&quot;motion-leader&quot;\/&gt;\n          &lt;text x=&quot;38&quot; y=&quot;231&quot; class=&quot;motion-arm-note&quot;&gt;\u62d6\u52a8\u624b\u81c2 \u00b7 \u5411\u5185\u63a8 Contact pad&lt;\/text&gt;\n        &lt;\/svg&gt;\n      &lt;label class=&quot;bend-profile&quot;&gt;Bend curve &lt;select id=&quot;bend-profile&quot; aria-label=&quot;Bend curve source&quot;&gt;&lt;option value=&quot;illustrative&quot; ${MOTION.profile==='illustrative'?'selected':''}&gt;Illustrative&lt;\/option&gt;&lt;option value=&quot;bilro&quot; ${MOTION.profile==='bilro'?'selected':''}&gt;POF reference&lt;\/option&gt;&lt;\/select&gt;&lt;\/label&gt;\n      &lt;div class=&quot;motion-controls&quot;&gt;\n        &lt;label for=&quot;motion-bend&quot;&gt;&lt;span&gt;Bend &lt;output id=&quot;motion-bend-out&quot;&gt;&lt;\/output&gt;&lt;\/span&gt;&lt;input id=&quot;motion-bend&quot; aria-label=&quot;Bend amplitude&quot; type=&quot;range&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;${MOTION.bend*100}&quot;&gt;&lt;small&gt;Less&lt;span&gt;More&lt;\/span&gt;&lt;\/small&gt;&lt;\/label&gt;\n        &lt;label for=&quot;motion-contact&quot;&gt;&lt;span&gt;Contact &lt;output id=&quot;motion-contact-out&quot;&gt;&lt;\/output&gt;&lt;\/span&gt;&lt;input id=&quot;motion-contact&quot; aria-label=&quot;Contact strength&quot; type=&quot;range&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;${MOTION.contact*100}&quot;&gt;&lt;small&gt;Less&lt;span&gt;More&lt;\/span&gt;&lt;\/small&gt;&lt;\/label&gt;\n      &lt;\/div&gt;\n      &lt;div class=&quot;motion-transport&quot;&gt;&lt;button type=&quot;button&quot; id=&quot;motion-play&quot; aria-pressed=&quot;false&quot;&gt;${motionPlayLabel()}&lt;\/button&gt;&lt;label for=&quot;motion-time&quot;&gt;&lt;span&gt;Time&lt;\/span&gt;&lt;input id=&quot;motion-time&quot; type=&quot;range&quot; min=&quot;0&quot; max=&quot;1000&quot; value=&quot;${Math.round(MOTION.time*1000)}&quot; aria-label=&quot;\u52a8\u4f5c\u65f6\u95f4\u6e38\u6807&quot;&gt;&lt;\/label&gt;&lt;\/div&gt;\n      &lt;\/div&gt;&lt;div class=&quot;unified-hardware&quot;&gt;&lt;div class=&quot;lab-part-label lab-hardware-label&quot;&gt;&lt;b&gt;Hardware \u2192 Effects&lt;\/b&gt;&lt;\/div&gt;\n      ${qualityHardwareTabs()}&lt;div id=&quot;quality-hardware-context&quot;&gt;${qualityHardwareContext()}&lt;\/div&gt;${qualityControls()}\n    &lt;\/div&gt;&lt;div class=&quot;unified-output&quot;&gt;\n      &lt;div class=&quot;quality-flow&quot;&gt;&lt;span&gt;Bend + Contact&lt;\/span&gt;&lt;i&gt;\u2192&lt;\/i&gt;&lt;span&gt;Ideal&lt;\/span&gt;&lt;i&gt;+ Effects \u2192&lt;\/i&gt;&lt;span&gt;Measured&lt;\/span&gt;&lt;\/div&gt;\n      &lt;div class=&quot;quality-plot-head&quot;&gt;&lt;h3&gt;Readout&lt;\/h3&gt;&lt;div&gt;&lt;span class=&quot;quality-key ideal&quot;&gt;Ideal&lt;\/span&gt;&lt;span class=&quot;quality-key measured&quot;&gt;Measured&lt;\/span&gt;&lt;span class=&quot;quality-key baseline&quot;&gt;Bend baseline&lt;\/span&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;div id=&quot;quality-signal-plot&quot;&gt;&lt;\/div&gt;\n      &lt;div class=&quot;quality-plot-head&quot;&gt;&lt;h3&gt;Residual&lt;\/h3&gt;&lt;div&gt;&lt;span class=&quot;quality-key ideal&quot;&gt;Ideal contact&lt;\/span&gt;&lt;span class=&quot;quality-key residual&quot;&gt;Residual&lt;\/span&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;div id=&quot;quality-residual-plot&quot;&gt;&lt;\/div&gt;\n      &lt;div class=&quot;quality-equation&quot; id=&quot;quality-equation&quot;&gt;&lt;\/div&gt;\n      &lt;div id=&quot;quality-decision-plot&quot;&gt;&lt;\/div&gt;&lt;div class=&quot;quality-verdict&quot; id=&quot;quality-verdict&quot; role=&quot;status&quot; aria-live=&quot;polite&quot;&gt;&lt;\/div&gt;\n\n    &lt;\/div&gt;&lt;\/div&gt;\n    &lt;p class=&quot;motion-caption&quot;&gt;&lt;span id=&quot;motion-provenance&quot;&gt;&lt;\/span&gt; \u00b7 &lt;b&gt;Contact \/ Effects: illustrative&lt;\/b&gt;&lt;\/p&gt;\n    ${qualityModelNotes()}\n  &lt;\/section&gt;`;\n}\n\nfunction motionDraw(){\n  if(!motionEl('motion-lab')){stopMotion();return;}\n  motionEl('motion-provenance').textContent=MOTION.profile==='bilro'?'Bend: POF knee reference (0\u201375\u00b0), not robot calibration':'Bend: illustrative, not calibrated';\n  const p=window.MotionModel.sample(MOTION.time,MOTION),angle=p.bend*(MOTION.profile==='bilro'?75:72),radians=angle*Math.PI\/180;\n  motionEl('motion-forearm').setAttribute('transform',`translate(202 90) rotate(${angle})`);\n  motionEl('motion-fiber').setAttribute('d',`M100 105 Q166 128 196 116 Q${210+angle*.11} ${118+angle*.13} ${202+45*Math.cos(radians)} ${90+45*Math.sin(radians)+13}`);\n  motionEl('motion-touch').setAttribute('opacity',p.contact&gt;.01?Math.min(1,.25+p.contact):0);\n  motionEl('motion-pad').setAttribute('fill',p.contact&gt;.01?'#e5bb93':'#edf4e1');\n  updateQualityCursor();\n  document.querySelectorAll('[data-motion-drag]').forEach(el=&gt;{const id=el.dataset.motionDrag;el.setAttribute('aria-valuenow',Math.round(MOTION[id]*100));el.setAttribute('aria-valuetext',motionLevel(MOTION[id]));});\n  motionEl('motion-time').value=Math.round(MOTION.time*1000);\n}\n\nfunction updateMotion(){\n  if(!motionEl('motion-lab'))return;\n  ['bend','contact'].forEach(id=&gt;{motionEl(`motion-${id}-out`).textContent=motionLevel(MOTION[id]);motionEl(`motion-${id}`).value=MOTION[id]*100;});\n  document.querySelectorAll('[data-motion-scene]').forEach(button=&gt;{const active=button.dataset.motionScene===MOTION.scene;button.classList.toggle('active',active);button.setAttribute('aria-pressed',String(active));});\n  const bendDisabled=MOTION.scene==='contact',contactDisabled=MOTION.scene==='bend';\n  motionEl('motion-bend').disabled=bendDisabled;motionEl('motion-contact').disabled=contactDisabled;\n  motionEl('motion-bend').closest('label').classList.toggle('inactive',bendDisabled);motionEl('motion-contact').closest('label').classList.toggle('inactive',contactDisabled);\n  updateSignalEffects();motionDraw();\n}\n\nfunction stopMotion(){\n  MOTION.playing=false;MOTION.last=null;\n  if(MOTION.frame!==null)cancelAnimationFrame(MOTION.frame);MOTION.frame=null;\n  if(motionEl('motion-play')){motionEl('motion-play').textContent=motionPlayLabel();motionEl('motion-play').setAttribute('aria-pressed','false');motionEl('motion-play').setAttribute('aria-label',motionReduced&amp;&amp;motionReduced.matches?'\u9010\u6b65\u67e5\u770b\u624b\u81c2\u52a8\u4f5c':'\u64ad\u653e\u624b\u81c2\u52a8\u4f5c');}\n}\n\nfunction motionTick(now){\n  if(!MOTION.playing||!motionEl('motion-lab')){stopMotion();return;}\n  if(MOTION.last!==null)MOTION.time=Math.min(1,MOTION.time+Math.min(100,now-MOTION.last)\/6000);\n  MOTION.last=now;motionDraw();\n  if(MOTION.time&gt;=1){stopMotion();return;}\n  MOTION.frame=requestAnimationFrame(motionTick);\n}\n\ndocument.addEventListener('click',event=&gt;{\n  const button=event.target.closest('[data-motion-scene],#motion-play');if(!button)return;\n  if(button.dataset.motionScene){stopMotion();MOTION.scene=button.dataset.motionScene;MOTION.time=.64;updateMotion();return;}\n  if(MOTION.playing){stopMotion();return;}\n  if(motionReduced&amp;&amp;motionReduced.matches){MOTION.time=MOTION.time&gt;=.999?0:Math.min(1,MOTION.time+.1);motionDraw();return;}\n  MOTION.time=0;MOTION.last=null;MOTION.playing=true;button.textContent='\u2161 Pause';button.setAttribute('aria-pressed','true');button.setAttribute('aria-label','\u6682\u505c\u624b\u81c2\u52a8\u4f5c');MOTION.frame=requestAnimationFrame(motionTick);\n});\ndocument.addEventListener('input',event=&gt;{\n  const id=event.target.id;if(!['motion-bend','motion-contact','motion-time'].includes(id))return;\n  if(id==='motion-time'){stopMotion();MOTION.time=Number(event.target.value)\/1000;motionDraw();}\n  else{stopMotion();MOTION[id==='motion-bend'?'bend':'contact']=Number(event.target.value)\/100;updateMotion();}\n});\ndocument.addEventListener('visibilitychange',()=&gt;{if(document.hidden)stopMotion();});\nwindow.addEventListener('hashchange',stopMotion);\nif(motionReduced&amp;&amp;motionReduced.addEventListener)motionReduced.addEventListener('change',stopMotion);\n\n\/\/ SVG handles and sliders edit the same physical input state.\nlet motionDrag=null;\nfunction motionPoint(event,svg){const p=svg.createSVGPoint();p.x=event.clientX;p.y=event.clientY;return p.matrixTransform(svg.getScreenCTM().inverse());}\nfunction enableMotionInput(id){\n  stopMotion();\n  if((id==='bend'&amp;&amp;MOTION.scene==='contact')||(id==='contact'&amp;&amp;MOTION.scene==='bend'))MOTION.scene='both';\n  if(id==='contact'||Math.sin(Math.PI*MOTION.time)**2&lt;.25)MOTION.time=.64;\n}\ndocument.addEventListener('pointerdown',event=&gt;{\n  const handle=event.target.closest('[data-motion-drag]');if(!handle||event.button!==0)return;\n  event.preventDefault();const svg=handle.ownerSVGElement,id=handle.dataset.motionDrag;enableMotionInput(id);updateMotion();\n  const point=motionPoint(event,svg),angle=MotionModel.sample(MOTION.time,MOTION).bend*(MOTION.profile==='bilro'?75:72)*Math.PI\/180;\n  motionDrag={svg,handle,id,pointer:event.pointerId,start:point,value:MOTION[id],normal:{x:-Math.sin(angle),y:Math.cos(angle)}};\n  svg.setPointerCapture(event.pointerId);handle.focus({preventScroll:true});\n});\ndocument.addEventListener('pointermove',event=&gt;{\n  if(!motionDrag||event.pointerId!==motionDrag.pointer)return;event.preventDefault();\n  const d=motionDrag,p=motionPoint(event,d.svg),clamp=v=&gt;Math.max(0,Math.min(1,v));\n  if(d.id==='bend'){const angle=Math.atan2(p.y-90,p.x-202)*180\/Math.PI;MOTION.bend=clamp(angle\/((MOTION.profile==='bilro'?75:72)*Math.sin(Math.PI*MOTION.time)**2));}\n  else MOTION.contact=clamp(d.value+((p.x-d.start.x)*d.normal.x+(p.y-d.start.y)*d.normal.y)\/70);\n  updateMotion();\n});\nfunction releaseMotionDrag(event){if(motionDrag&amp;&amp;event.pointerId===motionDrag.pointer){if(motionDrag.svg.hasPointerCapture(event.pointerId))motionDrag.svg.releasePointerCapture(event.pointerId);motionDrag=null;}}\ndocument.addEventListener('pointerup',releaseMotionDrag);document.addEventListener('pointercancel',releaseMotionDrag);\ndocument.addEventListener('keydown',event=&gt;{\n  const handle=event.target.closest('[data-motion-drag]');if(!handle||!['ArrowUp','ArrowDown','ArrowLeft','ArrowRight','Home','End'].includes(event.key))return;\n  event.preventDefault();const id=handle.dataset.motionDrag;enableMotionInput(id);\n  MOTION[id]=event.key==='Home'?0:event.key==='End'?1:Math.max(0,Math.min(1,MOTION[id]+(['ArrowUp','ArrowRight'].includes(event.key)?.05:-.05)));updateMotion();\n});\n\ndocument.addEventListener('change',event=&gt;{if(event.target.id==='bend-profile'){stopMotion();MOTION.profile=event.target.value;updateMotion();}});\n&lt;\/script&gt;&lt;script&gt;'use strict';\nfunction evidenceReview(){return '&lt;details class=&quot;details evidence-panel&quot; id=&quot;literature-evidence&quot;&gt;&lt;summary&gt;Literature cross-check \u00b7 \u6570\u503c\u3001\u6765\u6e90\u4e0e\u672a\u6807\u5b9a\u9879&lt;\/summary&gt;&lt;div class=&quot;details-body&quot;&gt;'+window.LITERATURE_REPORT+'&lt;\/div&gt;&lt;\/details&gt;';}\n&lt;\/script&gt;&lt;script&gt;'use strict';\nconst M=window.ArmModel,HW=window.ARM_HARDWARE;\nconst $=s=&gt;document.querySelector(s),$$=s=&gt;[...document.querySelectorAll(s)];\nconst esc=s=&gt;String(s??'').replace(\/[&amp;&lt;&gt;&quot;']\/g,c=&gt;({'&amp;':'&amp;amp;','&lt;':'&amp;lt;','&gt;':'&amp;gt;','&quot;':'&amp;quot;',&quot;'&quot;:'&amp;#39;'}[c]));\nconst fmt=(v,n=2)=&gt;Number.isFinite(v)?(Math.abs(v)&lt;.5*Math.pow(10,-n)?0:v).toFixed(n):'\u2014';\nconst NAV=[['principle','Principle'],['sleeve','Hardware']];\nlet current='principle',fbg={strain:400,temp:20,comp:true};\nconst intro=(tag,title,text)=&gt;`&lt;div class=&quot;intro&quot;&gt;&lt;div&gt;&lt;div class=&quot;eyebrow&quot;&gt;${tag}&lt;\/div&gt;&lt;h1&gt;${title}&lt;\/h1&gt;&lt;p&gt;${text}&lt;\/p&gt;&lt;\/div&gt;&lt;span class=&quot;badge orange&quot;&gt;TEACHING MODEL \u00b7 NOT LIVE&lt;\/span&gt;&lt;\/div&gt;`;\nfunction sources(items){return `&lt;div class=&quot;source-row&quot;&gt;${items.map(x=&gt;`&lt;a href=&quot;${esc(x.url)}&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;${esc(x.label||x.title)} \u2197&lt;\/a&gt;`).join('')}&lt;\/div&gt;`;}\nfunction control(id,label,value,min,max,step,unit){return `&lt;div class=&quot;control&quot;&gt;&lt;label for=&quot;${id}&quot;&gt;${label}&lt;strong&gt;&lt;output id=&quot;${id}-out&quot;&gt;${value}&lt;\/output&gt; ${unit}&lt;\/strong&gt;&lt;\/label&gt;&lt;input type=&quot;range&quot; id=&quot;${id}&quot; min=&quot;${min}&quot; max=&quot;${max}&quot; step=&quot;${step}&quot; value=&quot;${value}&quot;&gt;&lt;small&gt;${min}\u2013${max} ${unit}&lt;\/small&gt;&lt;\/div&gt;`;}\nfunction principle(){return intro('01 \/ PRINCIPLE','\u7528\u4e00\u4ef6\u8896\u5957\uff0c\u5206\u6e05\u8fd0\u52a8\u4e0e\u89e6\u78b0\u3002','Bending \u4e0e Contact \u5148\u6539\u53d8\u5149\u8def\u7684\u635f\u8017\uff0c\u518d\u6210\u4e3a\u7535\u4fe1\u53f7\u3002Encoder \u63d0\u4f9b\u5173\u8282\u89d2\u5ea6\uff0c\u6263\u9664\u5df2\u6807\u5b9a\u7684\u8fd0\u52a8\u80cc\u666f\uff0c\u5269\u4e0b\u7684 Residual \u624d\u7528\u4e8e\u5224\u65ad\u5916\u90e8\u63a5\u89e6\u3002')+`\n  ${motionLab()}\n  &lt;div class=&quot;mechanism-strip&quot;&gt;&lt;b&gt;Deformation&lt;\/b&gt;&lt;span&gt;\u2192&lt;\/span&gt;&lt;b&gt;Optical loss&lt;\/b&gt;&lt;span&gt;\u2192&lt;\/span&gt;&lt;b&gt;Power \u2192 Current \u2192 Voltage&lt;\/b&gt;&lt;span&gt;\u2192&lt;\/span&gt;&lt;b&gt;ADC \u2192 Inference&lt;\/b&gt;&lt;\/div&gt;\n  &lt;div class=&quot;section-head&quot;&gt;&lt;h2&gt;What changes, what it means&lt;\/h2&gt;&lt;p&gt;\u76f4\u63a5\u89c2\u6d4b\u4e0e\u6807\u5b9a\u540e\u63a8\u65ad\uff0c\u5206\u5f00\u7406\u89e3&lt;\/p&gt;&lt;\/div&gt;&lt;div class=&quot;compact-map&quot;&gt;&lt;article&gt;&lt;h3&gt;Intensity sensing&lt;\/h3&gt;&lt;code&gt;P = P\u2080 \u00b7 exp(\u2212A)&lt;\/code&gt;&lt;p&gt;Bending\u3001Contact \u4e0e\u5b89\u88c5\u53d8\u5316\u90fd\u53ef\u80fd\u5f71\u54cd Power\u3002\u5355\u4e2a\u8bfb\u6570\u4e0d\u80fd\u552f\u4e00\u8bc6\u522b\u539f\u56e0\uff0c\u4e5f\u4e0d\u80fd\u76f4\u63a5\u5206\u8fa8 Macrobending \u4e0e Microbending\u3002&lt;\/p&gt;&lt;\/article&gt;&lt;article&gt;&lt;h3&gt;FBG sensing&lt;\/h3&gt;&lt;code&gt;\u03bbB = 2 \u00b7 n_eff \u00b7 \u039b&lt;\/code&gt;&lt;p&gt;Strain \u4e0e Temperature \u4f1a\u79fb\u52a8\u53cd\u5c04\u5cf0\u3002\u6d4b\u7684\u662f Wavelength\uff0c\u5206\u79bb\u4e24\u79cd\u4f5c\u7528\u9700\u8981\u989d\u5916\u7684\u6e29\u5ea6\u4fe1\u606f\u3002&lt;\/p&gt;&lt;\/article&gt;&lt;article&gt;&lt;h3&gt;Temporal sensing&lt;\/h3&gt;&lt;code&gt;P(t), \u03bb(t) \u2192 features&lt;\/code&gt;&lt;p&gt;Slip \u4e0e Vibration \u4f9d\u8d56\u65f6\u95f4\u7279\u5f81\u3001\u8db3\u591f\u7684\u5e26\u5bbd\u53ca\u771f\u503c\u6807\u5b9a\u3002\u672c\u9875\u793a\u610f\u5173\u6ce8\u4f4e\u9891\u53d8\u5316\uff1b\u5feb\u901f\u4e8b\u4ef6\u9700\u91cd\u65b0\u786e\u8ba4\u5e26\u5bbd\u4e0e\u540c\u6b65\u3002&lt;\/p&gt;&lt;\/article&gt;&lt;\/div&gt;\n  &lt;details class=&quot;details&quot; id=&quot;fbg-details&quot;&gt;&lt;summary&gt;FBG mini demo \u00b7 Strain \u00d7 Temperature&lt;\/summary&gt;&lt;div class=&quot;details-body&quot;&gt;&lt;div class=&quot;fbg-lab&quot;&gt;&lt;div&gt;&lt;div class=&quot;controls&quot;&gt;${control('strain','Mechanical strain',fbg.strain,-500,1000,10,'\u00b5\u03b5')}${control('temperature','Temperature change',fbg.temp,-10,40,1,'\u00b0C')}&lt;\/div&gt;&lt;label class=&quot;switch&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;fbg-comp&quot; ${fbg.comp?'checked':''}&gt;Ideal temperature compensation&lt;\/label&gt;&lt;\/div&gt;&lt;div&gt;&lt;div id=&quot;fbg-spectrum&quot;&gt;&lt;\/div&gt;&lt;div class=&quot;fbg-result&quot; id=&quot;fbg-result&quot;&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;\/div&gt;&lt;p&gt;Literature nominal\uff1a&lt;code&gt;\u0394\u03bb [pm] \u2248 1.209 \u00d7 \u03b5 [\u00b5\u03b5] + 10.3385 \u00d7 \u0394T [\u00b0C]&lt;\/code&gt;\u3002\u03b5 \u4e3a\u5916\u52a0\u673a\u68b0\u5e94\u53d8\uff0c\u70ed\u81a8\u80c0\u4e0d\u91cd\u590d\u8ba1\u5165\uff1b\u7cfb\u6570\u7531 Kersey 1997 \u7684\u5f52\u4e00\u5316\u54cd\u5e94\u5728 1550 nm \u6362\u7b97\uff0c\u663e\u793a\u4f4d\u6570\u4ec5\u7528\u4e8e\u590d\u7b97\uff0c\u4e0d\u4ee3\u8868\u6807\u5b9a\u7cbe\u5ea6\uff1b\u9002\u7528\u4e8e\u540d\u4e49\u5149\u7ea4\u5e94\u53d8\uff0c\u4e0d\u7b49\u4e8e\u8863\u7269\u5e94\u53d8\u3002\u5b9e\u9645\u5c01\u88c5\u4ecd\u9700\u6807\u5b9a\u3002\u8865\u507f\u5047\u5b9a\u5df2\u77e5\u4e14\u5171\u6e29\u7684 \u0394T\u3001\u7cfb\u6570\u5339\u914d\u53ca\u7406\u60f3\u5e94\u53d8\u9694\u79bb\uff0c\u4e0d\u6a21\u62df\u771f\u5b9e\u6b8b\u4f59\u8bef\u5dee\u3002\u9700\u8981 Wavelength interrogator\uff0c\u4e0d\u80fd\u76f4\u63a5\u6cbf\u7528\u672c\u6848\u4f8b\u7684\u5149\u5f3a\u8bfb\u51fa\u3002&lt;\/p&gt;&lt;\/div&gt;&lt;\/details&gt;\n  ${evidenceReview()}\n  ${calibrationNotes()}\n  ${sources([{label:'Intensity textile \u00b7 2020',url:'https:\/\/www.nature.com\/articles\/s41598-020-70880-8'},{label:'FBG coefficients \u00b7 2022',url:'https:\/\/www.mdpi.com\/1424-8220\/22\/9\/3429'},{label:'Shape \/ force ambiguity \u00b7 2026',url:'https:\/\/doi.org\/10.1002\/aisy.70488'}])}`;}\nfunction updatePrinciple(){updateMotion();updateFBG();}\nfunction updateFBG(){\n  if(!$('#fbg-spectrum'))return;\n  const coefficients=window.MotionModel.FBG;\n  const shift=coefficients.strainPmPerMicrostrain*fbg.strain+coefficients.thermalPmPerC*fbg.temp,peak=coefficients.wavelengthNm+shift\/1000,estimate=(shift-(fbg.comp?coefficients.thermalPmPerC*fbg.temp:0))\/coefficients.strainPmPerMicrostrain;\n  const x=v=&gt;35+(v-1549)\/3.1*450,curve=p=&gt;Array.from({length:200},(_,i)=&gt;{const w=1549+i*3.1\/199;return `${i?'L':'M'}${fmt(x(w),2)},${fmt(111-80*Math.exp(-.5*((w-p)\/.075)**2),2)}`;}).join(' ');\n  $('#fbg-spectrum').innerHTML=`&lt;svg class=&quot;spectrum&quot; viewBox=&quot;0 0 520 150&quot; role=&quot;img&quot; aria-label=&quot;Illustrative FBG spectrum, current peak ${fmt(peak,3)} nm&quot;&gt;&lt;path d=&quot;M35 18 V111 H490&quot; stroke=&quot;#c7d5bb&quot; fill=&quot;none&quot;\/&gt;${[1549,1550,1551,1552].map(n=&gt;`&lt;text x=&quot;${x(n)}&quot; y=&quot;134&quot; text-anchor=&quot;middle&quot;&gt;${n}&lt;\/text&gt;`).join('')}&lt;path d=&quot;${curve(1550)}&quot; stroke=&quot;#a0b194&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;5 4&quot; fill=&quot;none&quot;\/&gt;&lt;path d=&quot;${curve(peak)}&quot; stroke=&quot;#267b58&quot; stroke-width=&quot;2.4&quot; fill=&quot;none&quot;\/&gt;&lt;text x=&quot;490&quot; y=&quot;17&quot; text-anchor=&quot;end&quot;&gt;WAVELENGTH \/ nm&lt;\/text&gt;&lt;\/svg&gt;`;\n  $('#fbg-result').innerHTML=`&lt;span&gt;\u0394\u03bb &lt;strong&gt;${fmt(shift,0)} pm&lt;\/strong&gt;&lt;\/span&gt;&lt;span&gt;\u2192&lt;\/span&gt;&lt;span&gt;${fbg.comp?'Ideal compensated':'Apparent'} \u03b5 &lt;strong&gt;${fmt(estimate,1)} \u00b5\u03b5&lt;\/strong&gt;&lt;\/span&gt;`;\n  $('#strain-out').textContent=fbg.strain;$('#temperature-out').textContent=fbg.temp;\n}\nfunction calibrationNotes(){return `&lt;details class=&quot;details&quot;&gt;&lt;summary&gt;Calibration \u00b7 \u4e3a\u4ec0\u4e48\u80fd\u533a\u5206 Bending \u4e0e Contact\uff1f&lt;\/summary&gt;&lt;div class=&quot;details-body&quot;&gt;&lt;p&gt;&lt;b&gt;01 \u00b7 Electrical baseline\uff1a&lt;\/b&gt;\u56fa\u5b9a\u8026\u5408\u3001\u906e\u5149\u3001\u786e\u8ba4\u96f6\u5916\u8f7d\u3002\u9010\u8def\u6d4b Dark \/ Light\u3001Noise\u3001Drift\u3001\u9971\u548c\u4e0e\u91cd\u590d\u6027\uff1b\u5148\u786e\u8ba4\u673a\u68b0\u8bd5\u6837\u4ea7\u751f\u7684\u53d8\u5316\u8db3\u591f\u7a33\u5b9a\u3002&lt;\/p&gt;&lt;p&gt;&lt;b&gt;02 \u00b7 No-contact motion\uff1a&lt;\/b&gt;\u8bb0\u5f55\u4e0d\u540c Joint angle\u3001\u8fd0\u52a8\u65b9\u5411\u3001\u901f\u5ea6\u4e0e\u6e29\u5ea6\u4e0b\u7684\u7a7a\u8f7d\u54cd\u5e94\uff0c\u5efa\u7acb bB(\u03b8, \u03b8\u0307, T) \u4e0e bC(\u03b8, \u03b8\u0307, T)\u3002Encoder \u65f6\u95f4\u5fc5\u987b\u4e0e\u5149\u4fe1\u53f7\u5bf9\u9f50\u3002&lt;\/p&gt;&lt;p&gt;&lt;b&gt;03 \u00b7 Force calibration\uff1a&lt;\/b&gt;\u56fa\u5b9a Contact pad \u4e0e\u538b\u5934\uff0c\u7528\u5df2\u77e5\u8f7d\u8377\u8bb0\u5f55 Loading \/ Unloading\uff0c\u5e76\u5728\u4e0d\u540c\u89d2\u5ea6\u91cd\u590d\u3002\u7075\u654f\u5ea6\u968f\u89d2\u5ea6\u53d8\u5316\u65f6\u4f7f\u7528 K(\u03b8)\u3002&lt;\/p&gt;&lt;p&gt;&lt;b&gt;04 \u00b7 Residual &amp; consistency\uff1a&lt;\/b&gt;&lt;code&gt;Sj = Con,j \u2212 Coff,j\uff1bqj = (Sj\/SR)\/(Sj,0\/SR,0)\uff1bzj = \u2212ln(qj)\uff1brj = zj \u2212 bj(\u03b8, \u03b8\u0307, T)&lt;\/code&gt;\u3002\u7528\u4e24\u8def Residual \u8054\u5408\u4f30\u8ba1 Force\uff0c\u518d\u68c0\u67e5\u662f\u5426\u7b26\u5408\u5df2\u6807\u5b9a\u7684\u54cd\u5e94\u6a21\u5f0f\u3002R1 \u53ea\u80fd\u8865\u507f\u7ecf\u9a8c\u8bc1\u7684\u5171\u540c\u53d8\u5316\u3002&lt;\/p&gt;&lt;p&gt;&lt;b&gt;05 \u00b7 Independent validation\uff1a&lt;\/b&gt;\u7528\u672a\u53c2\u4e0e\u62df\u5408\u7684\u89d2\u5ea6\u3001\u8f7d\u8377\u53ca\u91cd\u65b0\u7a7f\u88c5\u6279\u6b21\u9a8c\u8bc1\uff0c\u62a5\u544a False positive\u3001Miss rate\u3001Error \u4e0e Latency\u3002\u53ea\u6709\u786e\u8ba4\u65e0\u63a5\u89e6\u65f6\u624d\u80fd\u91cd\u8bbe Baseline\u3002&lt;\/p&gt;&lt;div class=&quot;notice orange&quot;&gt;\u8bc6\u522b\u8fb9\u754c\uff1a\u5f53\u524d\u53ea\u8ba8\u8bba\u4e00\u4e2a\u5df2\u77e5 Contact pad\u3002\u82e5 Mount shift \u6216\u5176\u4ed6\u6270\u52a8\u6070\u597d\u4ea7\u751f\u76f8\u540c\u7684\u53cc\u901a\u9053\u54cd\u5e94\uff0c\u73b0\u6709\u89c2\u6d4b\u4ecd\u65e0\u6cd5\u552f\u4e00\u6392\u9664\uff1b\u9700\u8981\u66f4\u591a\u72ec\u7acb\u89c2\u6d4b\u6216\u91cd\u65b0\u6807\u5b9a\u3002&lt;\/div&gt;&lt;\/div&gt;&lt;\/details&gt;`;}\nfunction render(){\n  stopMotion();\n  const hash=location.hash.slice(1),aliases={system:'principle',recognition:'principle',simulation:'principle',hardware:'sleeve',build:'sleeve',control:'principle',calibration:'principle'};\n  current=NAV.some(([id])=&gt;id===hash)?hash:(aliases[hash]||'principle');\n  $('#nav').innerHTML=NAV.map(([id,label],i)=&gt;`&lt;a href=&quot;#${id}&quot; class=&quot;${current===id?'active':''}&quot; ${current===id?'aria-current=&quot;page&quot;':''}&gt;&lt;span aria-hidden=&quot;true&quot;&gt;0${i+1}&lt;\/span&gt;${label}&lt;\/a&gt;`).join('');\n  if(current==='sleeve'&amp;&amp;LINKED_HARDWARE[HW_STATE.selected]&amp;&amp;EFFECT_CONTEXT.hardware!==HW_STATE.selected)applyHardwareImpact(HW_STATE.selected);\n  document.body.dataset.page=current;\n  $('#main').innerHTML=({principle,sleeve})[current]();\n  if(current==='principle')updatePrinciple();else {updateHardware();updateMotion();}updateSignalEffects();\n}\ndocument.addEventListener('click',e=&gt;{\n  const b=e.target.closest('button,a');if(!b)return;\n  if(b.classList.contains('skip')){e.preventDefault();$('#main').focus();return;}\n  if(b.dataset.block)selectHardware(b.dataset.block);\n  if(b.dataset.qualityHardware)selectQualityHardware(b.dataset.qualityHardware);\n  if(b.dataset.hardwareImpact)selectHardwareImpact(b.dataset.hardwareImpact);\n  if(b.dataset.qualityReset)resetSignalEffects();\n  if(b.dataset.hwReset){const item=blockById(HW_STATE.selected);HW_STATE.levels[item.id]=item.default;$('#hardware-effect').value=item.default;updateHardware();}\n});\ndocument.addEventListener('input',e=&gt;{if(e.target.dataset.qualityInput){EFFECT_CONTEXT.custom=true;EFFECT_CONTEXT.effect=e.target.dataset.qualityInput;EFFECT_STATE[e.target.dataset.qualityInput]=+e.target.value;updateSignalEffects();}if(e.target.id==='hardware-effect'){HW_STATE.levels[HW_STATE.selected]=+e.target.value;updateHardware();}if(e.target.id==='strain'){fbg.strain=+e.target.value;updateFBG();}if(e.target.id==='temperature'){fbg.temp=+e.target.value;updateFBG();}});\ndocument.addEventListener('change',e=&gt;{if(e.target.id==='quality-zero'||e.target.id==='quality-matched'){EFFECT_STATE[e.target.id==='quality-zero'?'zero':'matched']=e.target.checked;updateSignalEffects();}if(e.target.id==='fbg-comp'){fbg.comp=e.target.checked;updateFBG();}});\nwindow.addEventListener('hashchange',()=&gt;{render();window.scrollTo(0,0);});\n\nrender();\n&lt;\/script&gt;&lt;\/body&gt;&lt;\/html&gt;\n\"><\/iframe>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template\/full-width.php","meta":[],"_links":{"self":[{"href":"https:\/\/ezblog.cn\/index.php?rest_route=\/wp\/v2\/pages\/577"}],"collection":[{"href":"https:\/\/ezblog.cn\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ezblog.cn\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ezblog.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ezblog.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=577"}],"version-history":[{"count":2,"href":"https:\/\/ezblog.cn\/index.php?rest_route=\/wp\/v2\/pages\/577\/revisions"}],"predecessor-version":[{"id":579,"href":"https:\/\/ezblog.cn\/index.php?rest_route=\/wp\/v2\/pages\/577\/revisions\/579"}],"wp:attachment":[{"href":"https:\/\/ezblog.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=577"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}