デバイスが I²C データを読み取り、数値が変動していても、必ずしも目的の物理量を測定できているわけではありません。発熱する PCB に貼り付けられた温度計は、基板温度を主に測定している可能性があります。移動中の加速度計は、重力のみで傾斜角を算出することはできません。VOC アルゴリズムが出力する CO₂ 換算値も、直接測定された CO₂ 濃度ではありません。センサを理解するには、物理対象、敏感素子、サンプリング、結果の解釈の各層を追跡する必要があります。
物理量 → 敏感素子 熱結合、取り付け、方向 信号処理 / サンプリング 利得、帯域幅、ADC 生データ / タイムスタンプ バイト順、スケール、ステータス 校正・補償・推定 単位付きの結果 + 有効性 レジスタの読み取りはチェーンの中間ステップに過ぎず:物理的な取り付けと解釈 モデルも同様に重要 デジタル出力は外部アナログ回路を削減しますが、取り付け誤差、温度ドリフト、サンプリング歪み、モデル偏差を自動 的に解消するわけではありません。
問題 参照エントリ 最初に区別すべきこと
仕様書に 16 bit とあるが、正確か エラーと分解能 最小コードステップ、ノイズ、バイアス
NTC の温度計算が逆方向になっている 分圧と逆算 上腕抵抗、下腕抵抗、温度単位
データは平滑化されているが、運動が正しくない サンプリングとフィルタリング エイリアシング、遅延、真の変化
IMU の積分でなぜドリフトするか 慣性測定と融合 角速度、比力、観測可能な方向
環境数値は信頼できるか 取り付けとモデル 直接測定、補償、推算
ID は正常だがデータが異常 完全な読み取りフロー 設定、変換完了、アトミック読み取り、キャリブレーション
分解能、再現性、正確性はそれぞれ異なる問いに答える
理想的な 12 ビット ADC において、3.3 V 範囲でのコード幅は約 3.3/4096 = 0.806 mV です。これは量子化スケールに過ぎず、実際にはオフセット、ゲイン、非線形性、リファレンス誤差、ノイズが含まれます。数値表示を 0.01°C まで行っても、測定誤差が 0.01°C 未満であることを意味しません。複数回の結果が近いことは再現性が良いことを示しますが、全体が高めになっている可能性もあります。
誤差予算では、決定論的バイアスとランダム不確かさを区別する必要があります。2つの誤差に最大限界値しかない場合、保守的な総限界値は加算できます。適切な統計的定義があり、近似独立である場合にのみ、二乗和平方根(RSS)が適しています。データシート上の2つの「±最大誤差」を単純に RSS して、保証された最悪誤差として扱うことはできません。
レンジにも代償があります:より広い範囲は通常、LSB 1つあたりの物理量を増加させますが、ノイズ、過負荷回復、帯域幅は同じ比率で変化する必要はありません。ピークが飽和しないことをまず確認し、目標帯域と温度において有効な結果を評価する必要があります。
NTC:実際の分圧方向から抵抗を逆算する
VEX = 3.3 V R固定 10 kΩ NTC R25 = 10 kΩ ADC ノード V V = VEX × RNTC / (R固定 + RNTC) RNTC = R固定 × V / (VEX − V) オープン回路は VEX に近づき、短絡は 0 V に近づく NTC が分圧の下腕にある場合:温度上昇に伴い、ADC ノード電圧は低下する ADC が同源リファレンスを使用する場合、比率測定が可能です。異常判定には、ピンリーク、保護、故障位置も考慮する 必要があります。
図では固定抵抗が上、NTC が下にあるため、V = VEX·RNTC/(R固定+RNTC) となり、逆算すると RNTC = R固定·V/(VEX−V) が得られます。上下の抵抗を入れ替えると、式も随之に変更されます。NTC は温度上昇に伴い抵抗値が低下するため、この図では電圧は温度上昇とともに低下します。これが式的方向を確認する簡単な根拠となります。
適用温度範囲内では、B 定数近似は 1/T = 1/T25 + ln(R/R25)/B と表せ、T と T25 はケルビン単位を使用し、最後に 273.15 を引いて摂氏に変換します。R25=10 kΩ、B=3950 K と仮定すると、25°C でノードは 1.65 V、50°C で抵抗は約 3.588 kΩ、ノード電圧は約 0.871 V となります。このパラメータセットは計算例であり、すべての 10 kΩ NTC を代表するものではありません。
分圧励起と ADC リファレンスが同じ電源から供給される場合、正規化された読み取り値 q≈V/VEX を使用し、RNTC=R固定·q/(1−q) と書けます。理想的には励起振幅の誤差を消去できます。しかし、抵抗の許容差、ADC オフセット、リファレンス経路のノイズ、NTC モデル誤差は消去できません。ADI:比率式 NTC インターフェース
電流による自己発熱も発生します。25°C で 10 kΩ の抵抗2つが 3.3 V で直列接続されている場合、NTC の消費電力は約 0.272 mW です。温度上昇は、実際の媒体中の放散係数を用いて計算する必要があり、「消費電力が小さいから温度誤差は無視できる」と断言することはできません。抵抗値を上げるか間欠駆動にすることで消費電力を減らせますが、その分、ソースインピーダンスの増加や安定待ちの必要性が生じます。より広い温度範囲では、メーカーの曲線、テーブル参照、または Steinhart–Hart モデルに従う必要があり、単一の B 定数がすべての温度をカバーできるとは限りません。ADI:サーミスタ測定設計
ノード電圧が 0 または電源電圧に近づいた場合、逆算に入る前に短絡、開放、レンジオーバーを判断し、分母がゼロに近づくことや、有効に見える極端な温度値が得られることを避けてください。具体的な故障応答は、断点の位置、リーク、保護ネットワークによって異なります。
分圧の上下を替えると温度曲線は反転する
同じ温度で上下を替えるとqは1−qになり、正しい逆算は同じ温度へ戻る。勾配変化により同じADCステップでも温度分解能は一定ではない。比率式が消すのは励起振幅で部品・モデル誤差ではない。
図を準備しています 再読み込み
分圧の上下を替えると温度曲線は反転する 抵抗は温度で下がるが電圧の向きは上下位置で決まる。逆算は接続に合わせる必要がある。
{"id":"ntc-ratiometric-inversion","title":"分圧の上下を替えると温度曲線は反転する","summary":"抵抗は温度で下がるが電圧の向きは上下位置で決まる。逆算は接続に合わせる必要がある。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"position\"><button data-mode=\"lower\" data-i18n=\"lower\"></button><button data-mode=\"upper\" data-i18n=\"upper\"></button></div><div class=\"control\"><label for=\"temp\" data-i18n=\"temp\"></label><output for=\"temp\" id=\"temp-value\"></output><input id=\"temp\" type=\"range\" min=\"0\" max=\"80\" value=\"25\" step=\"0.5\"></div><div class=\"chart-wrap\"><div class=\"chart-label\" data-i18n=\"plot\"></div><svg id=\"plot\" class=\"curve\" viewBox=\"0 0 360 210\" role=\"img\" data-i18n-label=\"plot\"></svg></div><div class=\"metrics\"><div><span data-i18n=\"res\"></span><strong id=\"res\"></strong></div><div><span data-i18n=\"ratio\"></span><strong id=\"ratio\"></strong></div><div><span data-i18n=\"recovered\"></span><strong id=\"recovered\"></strong></div><div><span data-i18n=\"sensitivity\"></span><strong id=\"sensitivity\"></strong></div></div><p id=\"eq\" class=\"formula\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:550;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:550 20px ui-monospace,monospace}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px ui-monospace,monospace;background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px ui-monospace,monospace}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 ui-monospace,monospace;white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:ui-monospace,monospace}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px ui-monospace,monospace;padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 ui-monospace,monospace;overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n.chart-wrap{margin:18px 0}.chart-label{font-size:12px;color:var(--muted);min-height:3.2em}.curve{display:block;width:100%;height:auto;max-height:320px;overflow:visible}.curve text{font:11px ui-monospace,monospace;fill:var(--muted)}.gridline{stroke:var(--rule);stroke-width:1}.metrics strong{font-size:20px;min-height:3.2em}.formula{font:12px/1.8 ui-monospace,monospace;min-height:9em}.readout{min-height:8em}.presets button{flex-basis:30%}.scope p{overflow-wrap:anywhere} .unit-note{font-size:12px;color:var(--muted);margin:10px 0}\n\n.metrics span{word-break:break-all;line-break:strict}.metrics>div{padding-right:6px}\n\n","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';row.style.gridTemplateColumns='repeat('+r.length+',minmax(0,1fr))';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}function plot(id,series,xr,yr,opts={}){const e=$('#'+id),X=x=>42+(x-xr[0])/(xr[1]-xr[0])*298,Y=y=>175-(y-yr[0])/(yr[1]-yr[0])*148;let out='<defs><clipPath id=\"clip-'+id+'\"><rect x=\"42\" y=\"27\" width=\"298\" height=\"148\"/></clipPath></defs>';for(let i=0;i<3;i++){let x=xr[0]+i*(xr[1]-xr[0])/2,y=yr[0]+i*(yr[1]-yr[0])/2;out+='<path class=\"gridline\" d=\"M '+X(x)+' 27V175M42 '+Y(y)+'H340\"/><text x=\"'+X(x)+'\" y=\"194\" text-anchor=\"middle\">'+esc(opts.xfmt?opts.xfmt(x):Number(x.toFixed(2)))+'</text><text x=\"36\" y=\"'+(Y(y)+4)+'\" text-anchor=\"end\">'+esc(opts.yfmt?opts.yfmt(y):Number(y.toFixed(2)))+'</text>';}out+='<g clip-path=\"url(#clip-'+id+')\">';for(const s of series){out+='<path fill=\"none\" stroke=\"'+(s.color||'var(--accent)')+'\" stroke-width=\"2.5\" '+(s.dash?'stroke-dasharray=\"5 4\"':'')+' d=\"'+s.pts.map((p,i)=>(i?'L':'M')+X(p[0]).toFixed(2)+','+Y(p[1]).toFixed(2)).join(' ')+'\"/>';}for(const p of opts.points||[])out+='<circle cx=\"'+X(p[0])+'\" cy=\"'+Y(p[1])+'\" r=\"4\" fill=\"var(--second)\" stroke=\"var(--paper)\" stroke-width=\"1.5\"/>';if(opts.cursor!==undefined)out+='<path d=\"M'+X(opts.cursor)+' 27V175\" stroke=\"var(--muted)\" stroke-dasharray=\"3 3\"/>';e.innerHTML=out+'</g>';e.dataset.curves=JSON.stringify(series.map(s=>s.pts));}const curve=(fn,lo,hi,n=120)=>Array.from({length:n+1},(_,i)=>{const x=lo+(hi-lo)*i/n;return[x,fn(x)]});function inputs(draw){document.querySelectorAll('input,select').forEach(e=>{e.addEventListener('input',draw);e.addEventListener('change',draw)});draw()}const n=id=>+$('#'+id).value;const show=(id,v,d=3)=>set(id,Number(v.toFixed(d)));let mode='lower';function draw(){let temp=n('temp'),R=t=>10*Math.exp(3950*(1/(t+273.15)-1/298.15)),ratio=t=>mode==='lower'?R(t)/(10+R(t)):10/(10+R(t)),q=ratio(temp),r=mode==='lower'?10*q/(1-q):10*(1-q)/q,recovered=1/(1/298.15+Math.log(r/10)/3950)-273.15;pressed(mode);show('temp-value',temp);plot('plot',[{pts:curve(ratio,0,80)}],[0,80],[0,1],{points:[[temp,q]]});show('res',r,4);show('ratio',q,5);show('recovered',recovered,3);show('sensitivity',(ratio(temp+.001)-ratio(temp-.001))/.002,6);set('eq', (mode==='lower'?'RNTC = Rfixed q/(1−q)':'RNTC = Rfixed (1−q)/q')+'\\nT = 1/[1/298.15 + ln(R/R25)/B] − 273.15');}document.querySelectorAll('[data-mode]').forEach(e=>e.onclick=()=>{mode=e.dataset.mode;draw()});inputs(draw);","audio":false,"strings":{"heading":"分圧の上下を替えると温度曲線は反転する","intro":"NTC位置を切り替え、分圧比、逆算温度、局所感度を見る。","lower":"下側","plot":"横軸°C、縦軸 q=V/VEX","position":"NTC位置","ratio":"分圧比 q","recovered":"逆算温度(°C)","res":"NTC(kΩ)","reset":"リセット","scope":"R25=10 kΩ、B=3950 K、固定10 kΩ、理想レシオメトリックADC。0–80°Cの学習モデル、自己発熱・許容差・量子化なし。","scopeLabel":"モデルの範囲と前提","sensitivity":"dq/dT(1/°C)","temp":"真の温度(°C)","upper":"上側"}}
温度測定:センサ温度がいかに被測定対象を代表するか
NTC、RTD、デジタル温度計はいずれも熱結合を必要とし、応答速度はパッケージ、取り付け、媒体、熱容量によって共同で決定されます。高精度な白金抵抗体では、励起による自己発熱、2線式のリード線抵抗、3/4線式の補償も考慮する必要があり、「PT100」とあるだけで ±0.1°C が保証されるわけではありません。デジタルデバイスは一部のアナログ設計を省略しますが、パッケージや基板熱源の影響を解消するわけではありません。
DS18B20 はオプションの分解能とマルチポイント 1-Wire をサポートし、12 ビット変換の最大所要時間は 750 ms に達します。分解能設定、電源モード、バス負荷はシステム動作に影響します。寄生給電の場合、変換段階で強力なプルアップが必要になることがあり、データ線1本だけを接続して給電と帰還経路を無視してはいけません。ADI DS18B20 データシート
熱電対は両端の温度に依存する熱起電力を発生させ、単一のハンダ点で絶対温度を出力するわけではありません。冷接点補償は配線端の温度を測定し、そのタイプを基準温度に対して換算した等価熱起電力に変換し、測定電圧と合成してから熱接点温度を逆引きします。関係が非線形であるため、すべての温度範囲で2つの温度を単純に加算することはできません。補償センサは、近傍チップの温度ではなく、実際の配線端の温度を代表すべきです。ADI:冷接点補償
アナログとデジタルのサンプリングはいずれも時間モデルを必要とする
SAR ADC のサンプリングコンデンサは、信号源を経由して充電する必要があります。単極モデルに簡略化すると、フルスケールのステップ応答が半分 N ビット LSB に収束するには、約 t ≥ (N+1)ln2·R源Cサンプリング が必要です。12 ビットの場合、約 9 個の時定数です。10 kΩ と 10 pF を仮定すると、この部分だけで約 0.90 μs となり、実際にはスイッチインピーダンスとドライバの安定化過程も考慮する必要があります。ADI:ソースインピーダンスとサンプリングセットル時間
サンプリングレートは、アナログ帯域幅とアンチエイリアシングフィルタと連携する必要があります。例えば、1 ksample/s で 900 Hz の正弦波をサンプリングすると、離散データ内で 100 Hz の正弦波と区別できなくなります。サンプリング後の移動平均では、本来の 900 Hz の正体を回復できません。デジタルセンサ内部にすでにサンプリング/フィルタリングがあっても、出力データレート、帯域幅、フィルタ設定を確認する必要があります。
平均化は条件を満たすランダムノイズを低減できますが、遅延を増加させます。長さ N の単純移動平均は、線形位相モデルにおいて (N−1)/2 個のサンプリング間隔の群遅延を持ちます。1 ksample/s、N=21 の場合、約 10 ms です。固定バイアスは除去できず、相関ノイズも 1/√N で減少するとは限りません。制御システムでは、遅延を閉ループ予算に組み込む必要があります。
デジタルインターフェースの速度は伝送能力を示すだけであり、測定更新率ではありません。UART 自体は長距離物理層を規定していません。I²C の消費電力が SPI より常に低いわけではありません。インターフェースの選択には、ケーブルの電気的特性、有効データ量、アドレスまたはチップセレクト、タイムスタンプ、FIFO 深さを組み合わせる必要があり、具体的な論理レベルは インターフェース物理層 を参照してください。
同じサンプルが異なる信号に対応する
900 Hzと100 Hzは各サンプルで一致しても間では異なる。1000 Hzでは全標本が同じ値になる。余弦を使い位相対応を単純化した図で、一般の折返しに位相処理が不要という意味ではない。
cos ( 2 π ( f s − f ) n / f s ) = cos ( 2 π f n / f s )
図を準備しています 再読み込み
同じサンプルが異なる信号に対応する 離散点は完全に一致し得るため、後段処理はこの点だけで元周波数を判断できない。
{"id":"sampling-alias-identity","title":"同じサンプルが異なる信号に対応する","summary":"離散点は完全に一致し得るため、後段処理はこの点だけで元周波数を判断できない。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"control\"><label for=\"f\" data-i18n=\"f\"></label><output for=\"f\" id=\"f-value\"></output><input id=\"f\" type=\"range\" min=\"0\" max=\"2000\" value=\"900\" step=\"10\"></div><div class=\"chart-wrap\"><div class=\"chart-label\" data-i18n=\"plot\"></div><svg id=\"plot\" class=\"curve\" viewBox=\"0 0 360 210\" role=\"img\" data-i18n-label=\"plot\"></svg></div><div class=\"metrics\"><div><span data-i18n=\"alias\"></span><strong id=\"alias\"></strong></div><div><span data-i18n=\"period\"></span><strong id=\"period\"></strong></div></div><p id=\"eq\" class=\"formula\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:550;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:550 20px ui-monospace,monospace}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px ui-monospace,monospace;background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px ui-monospace,monospace}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 ui-monospace,monospace;white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:ui-monospace,monospace}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px ui-monospace,monospace;padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 ui-monospace,monospace;overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n.chart-wrap{margin:18px 0}.chart-label{font-size:12px;color:var(--muted);min-height:3.2em}.curve{display:block;width:100%;height:auto;max-height:320px;overflow:visible}.curve text{font:11px ui-monospace,monospace;fill:var(--muted)}.gridline{stroke:var(--rule);stroke-width:1}.metrics strong{font-size:20px;min-height:3.2em}.formula{font:12px/1.8 ui-monospace,monospace;min-height:9em}.readout{min-height:8em}.presets button{flex-basis:30%}.scope p{overflow-wrap:anywhere} .unit-note{font-size:12px;color:var(--muted);margin:10px 0}\n\n.metrics span{word-break:break-all;line-break:strict}.metrics>div{padding-right:6px}\n\n","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';row.style.gridTemplateColumns='repeat('+r.length+',minmax(0,1fr))';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}function plot(id,series,xr,yr,opts={}){const e=$('#'+id),X=x=>42+(x-xr[0])/(xr[1]-xr[0])*298,Y=y=>175-(y-yr[0])/(yr[1]-yr[0])*148;let out='<defs><clipPath id=\"clip-'+id+'\"><rect x=\"42\" y=\"27\" width=\"298\" height=\"148\"/></clipPath></defs>';for(let i=0;i<3;i++){let x=xr[0]+i*(xr[1]-xr[0])/2,y=yr[0]+i*(yr[1]-yr[0])/2;out+='<path class=\"gridline\" d=\"M '+X(x)+' 27V175M42 '+Y(y)+'H340\"/><text x=\"'+X(x)+'\" y=\"194\" text-anchor=\"middle\">'+esc(opts.xfmt?opts.xfmt(x):Number(x.toFixed(2)))+'</text><text x=\"36\" y=\"'+(Y(y)+4)+'\" text-anchor=\"end\">'+esc(opts.yfmt?opts.yfmt(y):Number(y.toFixed(2)))+'</text>';}out+='<g clip-path=\"url(#clip-'+id+')\">';for(const s of series){out+='<path fill=\"none\" stroke=\"'+(s.color||'var(--accent)')+'\" stroke-width=\"2.5\" '+(s.dash?'stroke-dasharray=\"5 4\"':'')+' d=\"'+s.pts.map((p,i)=>(i?'L':'M')+X(p[0]).toFixed(2)+','+Y(p[1]).toFixed(2)).join(' ')+'\"/>';}for(const p of opts.points||[])out+='<circle cx=\"'+X(p[0])+'\" cy=\"'+Y(p[1])+'\" r=\"4\" fill=\"var(--second)\" stroke=\"var(--paper)\" stroke-width=\"1.5\"/>';if(opts.cursor!==undefined)out+='<path d=\"M'+X(opts.cursor)+' 27V175\" stroke=\"var(--muted)\" stroke-dasharray=\"3 3\"/>';e.innerHTML=out+'</g>';e.dataset.curves=JSON.stringify(series.map(s=>s.pts));}const curve=(fn,lo,hi,n=120)=>Array.from({length:n+1},(_,i)=>{const x=lo+(hi-lo)*i/n;return[x,fn(x)]});function inputs(draw){document.querySelectorAll('input,select').forEach(e=>{e.addEventListener('input',draw);e.addEventListener('change',draw)});draw()}const n=id=>+$('#'+id).value;const show=(id,v,d=3)=>set(id,Number(v.toFixed(d)));function draw(){let f=n('f'),alias=Math.abs(((f+500)%1000)-500),wave=(freq,t)=>Math.cos(2*Math.PI*freq*t/1000),samples=Array.from({length:11},(_,i)=>[i,wave(f,i)]);show('f-value',f);plot('plot',[{pts:curve(t=>wave(f,t),0,10,800)},{pts:curve(t=>wave(alias,t),0,10,800),color:'var(--second)'}],[0,10],[-1.2,1.2],{points:samples});show('alias',alias);show('period',1);set('eq','x[n] = cos(2π f n/fs)\\nfalias = abs(((f + fs/2) mod fs) − fs/2)\\n= '+alias+' Hz');$('#alias').dataset.samples=JSON.stringify(samples.map(x=>x[1]));}inputs(draw);","audio":false,"strings":{"alias":"ベースバンド周波数(Hz)","f":"入力周波数(Hz)","heading":"同じサンプルが異なる信号に対応する","intro":"入力周波数を変え、元の余弦とベースバンドの折返しを比較。","period":"サンプル間隔(ms)","plot":"横軸 ms、青:入力、金:折返し、点:共通サンプル","reset":"リセット","scope":"fs=1000 Hz、振幅1・位相0の余弦、理想瞬時サンプル、折返し防止フィルターなし。金は等価な基底帯域解釈。","scopeLabel":"モデルの範囲と前提"}}
IMU:各観測量がいかに姿勢を制約するか
加速度計は比力を測定し、f = Rᵀ(a−g) で表される一般的な座標規約の一種を表せます。ここで R は機体から世界へのマッピング、a は並進加速度、g は重力ベクトルです。静止支持時、その大きさは約 1g であり、どの軸が正または負になるかは、取り付けと座標定義に依存します。自由落下では理想的な出力はゼロに近づきます。これを用いて傾斜角を推定するには、並進加速度が重力に対して無視できるなどの条件に依存します。ADI:加速度計傾斜測定
ジャイロは角速度を提供し、積分することで姿勢変化を短時間追跡できますが、ゼロバイアスが蓄積します。一定の 0.1°/s の補正されていないバイアスは、60秒後には約 6° の角度誤差を引き起こす可能性があります。3次元運動では、回転関係に従ってクォータニオンまたは回転行列を更新する必要があり、3つのオイラー角をそれぞれ自由に加算することはできません。
観測量 制約できる内容 主な制限
ジャイロ角速度 短時間の回転変化 ゼロバイアス、温度ドリフト、ノイズ積分
加速度比力 準静的状態での重力方向 並動、振動、重力軸周りのヨーを単独で決定できない
磁場ベクトル 適切な条件下での航向参照 硬鉄/軟鉄、近傍電流、地磁気と傾角
融合アルゴリズムは補完情報を活用し、誤差を推定しますが、「9軸があればドリフトのない絶対姿勢が得られる」と約束するものではありません。磁場が乱されている場合に磁力計を盲目的に信頼すると、航向を誤った方向へ引きずり込む可能性があります。持続的な加速も傾斜として誤解される可能性があります。アルゴリズム名を変更するだけでなく、時間同期、取り付け軸変換、有効性判断、適切なノイズ/バイアスモデルが必要です。
静止時のジャイロの平均値を用いて、その条件下でのゼロバイアスを推定できます。しかし、加速度計で静止した3軸の読み取り値をすべてゼロに減算することはできません。そうすると、重力の観測値も一緒に削除されてしまいます。多姿勢キャリブレーションは、バイアス、ゲイン、軸間誤差を区別するために使用されますが、温度変化には追加の補償が必要になる場合があります。
環境センサ:出力単位がすべての解釈を意味しない
湿度と温度は相関しており、ケースの通風、熱源、汚染、結露が測定を変更します。チップはキャリブレーション済みですが、密閉された発熱するケースに装着しても、室内空気を代表できるとは限りません。環境温湿度の取り付けは、熱隔離とガス交換を中心に設計する必要があります。Sensirion:温湿度設計ガイド
気圧から高度への変換には、基準気圧と大気モデルが必要です。海抜近くで、密度を 1.225 kg/m³ と仮定すると、Δh≈−Δp/(ρg) となり、100 Pa は約 8.32 m に対応します。これは局所的な近似に過ぎず、気象による気圧変化も高度変化として解釈されます。ある気圧精度が、すべての標高で固定された高度精度に変換できるわけではありません。BME280 などの生データも、工場出荷時の補償パラメータに従って変換する必要があり、ADC レジスタを直接 Pa や %RH として扱うことはできません。Bosch BME280 データシート
照度 lux には人目の分光感度重み付けの意味が含まれており、ケースの透光率、光源のスペクトル、入射角がシステム結果に影響します。lux を出力するデジタルセンサでも、機体全体の補正が必要になる場合があります。粒子状物質の光散乱測定は、粒径、屈折率、湿度などの条件に依存しており、「レーザーを採用しているから」質量濃度の誤差がないと直接導き出すことはできません。
VOC デバイスが計算する CO₂eq/eCO₂ は、CO₂ 吸収などの物理的特性を対象とした直接測定とは異なります。例えば SGP30 は、アルゴリズムによって計算された TVOC と CO₂ 等価信号を明確に出力しており、これを真の CO₂ 濃度の汎用代替品として扱うことはできず、単一ガス指標で全体的な空気品質を概括すべきではありません。Sensirion SGP30 データシート
通信から結果の信頼性への読み取りフロー
ID の読み取りは、1回の通信で期待される識別値を取得したことを証明するだけであり、レンジ、出力レート、動作モードを設定して読み返し、変換完了を待ち、ステータス/CRC を照合し、規定された連続読み取りまたはラッチメカニズムに従って同一フレームのマルチバイトデータを取得する必要があります。全ゼロまたは 0xFF は、バス、電源、未変換、設定、または実際のデータのいずれかであり、1つのビットパターンだけで故障を確定することはできません。
解析時には、符号付き形式、バイト順、単位スケール、タイムスタンプを明確にし、オーバーフロー、FIFO サンプルドロップ、データ陳腐化を確認します。フィルタリング前に生データと設定を保存し、キャリブレーションには既知の条件と適切な参照を使用します。一般的な氷水と当地の沸騰水がすべての温度計の 0/100°C キャリブレーションポイントを正確に構成すると仮定してはいけません。最後に、参照誤差、取り付け、再現性を結果の信頼範囲に一緒に組み込みます。
再計算モデル
from math import exp , log , isclose , sin , pi
r25 , beta , t25 = 10000 , 3950 , 298. 15
r50 = r25 * exp ( beta * ( 1 / 323. 15 - 1 / t25 ) )
v50 = 3. 3 * r50 / ( 10000 + r50 )
r_back = 10000 * v50 / ( 3. 3 - v50 )
t_back = 1 / ( 1 / t25 + log ( r_back / r25 ) / beta ) - 273. 15
assert isclose ( t_back , 50 )
assert 3588 < r50 < 3589 and 0. 871 < v50 < 0. 872
assert isclose ( ( 3. 3 / 20000 ) * * 2 * 10000 * 1000 , 0. 27225 )
assert 0. 9 < 13 * log ( 2 ) * 10000 * 10e-12 * 1e6 < 0. 91
assert isclose ( ( 21 - 1 ) / 2 / 1000 , 0. 010 )
assert isclose ( 0. 1 * 60 , 6 )
assert 8. 32 < 100 / ( 1. 225 * 9. 80665 ) < 8. 33
for n in range ( 20 ) :
assert isclose ( sin ( 2 * pi * 900 * n / 1000 ) , - sin ( 2 * pi * 100 * n / 1000 ) , abs_tol = 1e-12 )
print ( ' NTC 逆算、自己発熱、セットル時間、エイリアシング、遅延、局所気圧高度モデルが通過' )
上記は教育モデルのローカル再計算であり、実物のセンサデータの収集やキャリブレーション実験は行われていません。
継続的な参照