# キャリブレーション検証履歴 (Calibration Verification History)

本ドキュメントは MiniTIAS 実機（baseline 1 枚 `MiniTIAS_20260408_144434`）に対するシミュレーション結果の **キャリブレーション** と **検証イテレーション** を時系列で記録する．

目的:

- 「どの仮説で何を変え，何が起きたか」を残し，**後から経緯を辿れる**ようにする．
- **失敗・予想外も同等に記録**し，方向性のドリフトと「うろ覚えで同じ仮説を試し直す」事態を防ぐ．
- 各イテレーションの **学び** を明示し，次の意思決定の根拠を蓄積する．

関連ドキュメント:

- 現状の物理仕様: [SPEC_03_基準設計の物理構成](../04_SPEC/SPEC_03_基準設計の物理構成.md)
- 開発ステップ全体: [PLAN_02_開発ステップ](../03_PLAN/PLAN_02_開発ステップ.md)
- 実測リファレンス: `reference_measurement/MiniTIAS_20260408_144434/`

## 実測ターゲット (Measurement Target)

baseline 1 枚（`MiniTIAS_20260408_144434`，ROI 1400×1409，sRGB 符号化済み Y' luma）:

| 指標 | 値 |
| --- | --- |
| mean | 146.71 |
| CoV | 0.0427 |
| 勾配 % | 6.10 |
| 中心/周辺比 (C/P) | 1.0650 |
| std | 6.26 |
| max/min 比 | 1.392 |

評価は `sm-evaluate` で実施．シミュ側の比較は OETF 順方向適用後（Step 8-3 以降）に sRGB ドメインで行うのが正式．linear ドメイン比較は Step 8-3 以前または同一条件シミュ間の検証用．

## 俯瞰サマリ (Overall Progression)

時系列での主要指標推移．**残差倍率** = (シミュ - 実測) / (初期残差 - 実測) として「初期からどれだけ縮まったか」を見る．

| Step | 設定 | 空間 | mean | CoV | 勾配% | C/P | CoV 残差倍率 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 実測 TARGET | — | sRGB | 146.71 | 0.0427 | 6.10 | 1.065 | 1.0× |
| 8-1 spp=128 | R0.85, d8, linear | linear | 151.79 | 0.236 | 24.83 | 1.330 | 5.5× |
| 8-1 spp=1024 (基準確定) | R0.85, d8, linear | linear | 152.02 | 0.183 | 24.72 | 1.328 | 4.3× |
| 8-2 R=0.92 sweep | R0.92, d12, linear | linear | — | 0.170 | 19.42 | 1.241 | 4.0× |
| 8-3 OETF 適用 | R0.85, d8, spp1024 | **sRGB** | 146.71* | **0.089** | **12.57** | **1.144** | **2.1×** |
| 8-3 OETF + R=0.92 + d=12 | R0.92, d12 | sRGB | 146.71* | 0.081 | 9.72 | 1.108 | 1.9× |
| 8-7 size 1.5×1.5 (Φe 保存) | linear, R0.85, d8 | linear | 429.99 | 0.186 | 26.21 | 1.355 | (形状指標 ≈ 8-1) |

\* mean アンカー固定．R, d, spp は `reflectance`, `max_depth`, `samples_per_pixel`．

最大の跳躍は **8-3 OETF（残差 4.3× → 2.1×）**．現時点の確定基準は **R=0.85, d=8, spp=1024, OETF=on** で残差 2.1×．残る 1.6〜1.9× の残差は **LSC（ISP レンズシェーディング補正）** が主因候補（未対処，[Step 8-N 候補](#step-8-n-候補-lsc-順方向モデル未着手) 参照）．

## イテレーション履歴 (Iteration Log)

### Step 8-1: spp 校正 (128 → 1024)

- **日付**: 2026-05-18
- **背景・問題意識**: 初期シミュ（spp=128）と実測の差が CoV 0.236 vs 0.0427 ≈ **5.5 倍** と大きすぎる．これは MC ノイズなのか，物理モデルの構造的勾配なのか，**切り分けないと方向性が定まらない**．
- **仮説（物理動機）**: モンテカルロノイズは `1/√spp` で減衰する独立成分．一方，物理由来の空間勾配は spp 非依存．spp を 8 倍にすればノイズ成分の寄与が `1/√8 ≈ 35%` に減るので，残った差が「物理」だと確定できる．
- **試した変更**: `configs/scene_baseline.yaml` の `render.spp` を 128 → 1024（8 倍）．他は据え置き．
- **期待した効果**: ノイズ系指標（max/min, std, CoV の量子化的外れ値成分）は減少．勾配や中心/周辺比は spp 非依存なら不変．
- **実際の結果**:

  | 指標 | spp=128 | spp=1024 | 動いた量 |
  | --- | --- | --- | --- |
  | CoV | 0.236 | 0.183 | -22% |
  | std | 35.83 | 27.85 | -22% |
  | max/min 比 | 11.59 | 4.27 | **-63%**（極端な外れ値が消えた） |
  | mean | 151.79 | 152.02 | ≈ 不変 |
  | 中心/周辺比 | 1.330 | 1.328 | ≈ 不変 |
  | 勾配 % | 24.83 | 24.72 | ≈ 不変 |

- **解釈**: max/min, std, CoV はノイズ由来成分を含んで動いた．中心/周辺比と勾配 % は spp 非依存 → **物理由来の構造的勾配**．ノイズ分解 `std² = 信号² + ノイズ²`，`ノイズ ∝ 1/√spp` で逆算すると spp=1024 の残留ノイズ std ≈ 8.5，真の物理信号 std ≈ 26.5．**spp→∞（ノイズゼロ）でも CoV は ≈ 0.174 までしか下がらない**（実測 0.0427 の約 4 倍）．
- **学び**: spp を増やしても CoV は 0.183 → 0.174 程度で頭打ち．**spp 増加は費用対効果なし**．残差 4.3× は物理モデル要因と確定．spp=1024 を基準として確定．
- **次のアクション**: 物理モデル側を疑う．最も効きそうな反射率を振る → [Step 8-2](#step-8-2-反射率スイープ-r075092) へ．

### Step 8-2: 反射率スイープ (R=0.75〜0.92)

- **日付**: 2026-05-18
- **背景・問題意識**: 8-1 で「物理モデル要因」と確定．MiniTIAS は白筐体内壁の多重反射で照明を均一化する設計なので，**内壁反射率**が直接効くはず．暫定 0.85 が低めの可能性．
- **仮説（物理動機）**: 反射率↑ → 多重反射光（より均一な ambient 成分）↑ → 評価板全体が均一に近づく．インテグレーティングスフィア近似 `1/(1-R)` で R=0.85 → 0.92 で実効反射が 6.7 → 12.5（+88%）．
- **試した変更**: `materials.printer_white.reflectance` を 0.75, 0.80, 0.85（基準）, 0.90, 0.92 の 5 点で振る．spp=256, depth=12, linear ドメイン評価．
- **期待した効果**: 単調改善．実測 (CoV=0.0427) に近づける R を見つける．
- **実際の結果**:

  | R | CoV | 勾配 % | C/P |
  | --- | --- | --- | --- |
  | 0.75 | 0.2173 | 25.91 | 1.350 |
  | 0.80 | 0.2034 | 24.00 | 1.316 |
  | 0.85（基準） | 0.1893 | 22.08 | 1.283 |
  | 0.90 | 0.1753 | 20.15 | 1.252 |
  | 0.92（マット白プラ実用上限） | 0.1697 | 19.42 | 1.241 |

- **解釈**: 全指標が R に対し単調・線形に改善するが**感度が低い**（∂勾配/∂R ≈ −38 %/単位，linear）．実測 (CoV=0.0427) 到達には外挿で **R ≈ 1.2〜1.4** が必要 ＝ **物理範囲外**．
- **学び**: 反射率は**弱い二次レバー**．これ単独では差を閉じられない．構造的に違う何か（評価方法・座標系・ドメイン）を疑うべき．
- **次のアクション**: もっと大きな自由度を持つレバーを探す．**評価方法自体を疑う** → [Step 8-3](#step-8-3-oetf-順方向適用手法訂正) へ．

### Step 8-3: OETF 順方向適用（手法訂正）

- **日付**: 2026-05-18 頃（コミット `26904da`）
- **背景・問題意識**: 反射率スイープでも残差 4× を解消できない．「シミュ linear と実測 sRGB を直接比較」が成立しているか改めて疑った．実測データ提供側 README にも「シミュを線形のまま比較すると勾配/CoV の絶対値は変わる」と明示されていた（**見落としていた**）．
- **仮説（物理動機）**: 実測 PNG は実機 ISP の **sRGB ガンマ（OETF, IEC 61966-2-1）** が掛かった非線形符号化値（Camera2 `YUV_420_888` → BT.601 は定義上ガンマ済み R'G'B' 上の量）．シミュは linear．**「無次元指標はスケール不変」は線形変換のみ成立**，非線形 OETF 下では成立しない（`Σwᵢ·f(xᵢ) ≠ f(Σwᵢ·xᵢ)`）．OETF を順方向適用してドメインを揃えれば，物理量差ではなく「符号化ドメイン不一致」だった分が消える．
- **試した変更**:
  - `src/sm_tias_lightsim/evaluation/oetf.py` を新規実装（標準 sRGB OETF + 露出ソルバ）．
  - `EvaluationConfig.oetf` スキーマ追加（[SPEC_02 参照](../04_SPEC/SPEC_02_シーン定義仕様.md)）．
  - `sm-evaluate` に統合．ROI 抽出後・指標算出前に OETF を順方向適用．
  - `configs/eval_baseline.yaml` で有効化．`configs/eval_real.yaml` は非適用（実測 PNG への二重適用禁止）．
  - 露出は AE が制御する量＝実測 ROI mean (146.71) に対数二分でアンカー（線形ゲインなので形状指標には自由度を持ち込まない；OETF が非線形なため「曲線上の動作点」を合わせる原理的アンカーとして必須）．
- **期待した効果**: ガンマ非線形性で「同じ物理だが見かけが違う」分が解消，残差が大きく縮む．データに合わせて回す係数はゼロ．
- **実際の結果**:

  | ソース | 空間 | CoV | 勾配 % | C/P |
  | --- | --- | --- | --- | --- |
  | R0.85, d8, spp1024 | linear | 0.183 | 24.65 | 1.327 |
  | 〃 | **sRGB** | **0.089** | **12.57** | **1.144** |
  | R0.85, d12, spp256 | sRGB | 0.091 | 11.16 | 1.126 |
  | R0.92, d12, spp256 | sRGB | 0.081 | 9.72 | 1.108 |
  | **実測 TARGET** | sRGB | **0.0427** | **6.10** | **1.0650** |

  - CoV 0.183 → 0.089（残差 4.3× → 2.1×，**67% 解消**）
  - 勾配 24.65 → 12.57（残差差 18.6 → 6.5，**65% 解消**）
- **解釈**: **見かけ差の約 2/3 が符号化ドメイン不一致**だったと判明．無彩色シーンでは「linear RGB → チャネル別 OETF → Rec.709 加重和」と「luminance 直接 OETF」が厳密一致（Rec.709 重みは合計 1，R=G=B の無彩色画素では `Σwᵢ·f(x) = f(x) = f(x·Σwᵢ)`）．OETF は不整合を作るのではなく **消す操作**．OETF 前のシミュ linear luma と実測 sRGB luma は別ドメインだった．
- **学び**:
  - 寄与順を訂正: **OETF（最大・約 2/3）＞ ISP LSC（残差主因候補）＞ 反射率（弱い）**．旧版「主因は ISP レンズシェーディング (83%)」は OETF を抜かした交絡判断で誤りだった．
  - 「データに合わせて回す係数はゼロ」が成立する標準変換は **overfitting なしで残差を大きく縮められる**．
  - 標準仕様（IEC 61966-2-1, Rec.709）の存在を前提として常に確認すべき．「実機カメラ出力は例外なくガンマ符号化」が標準前提．
- **次のアクション**:
  - OETF 順方向適用を sm-evaluate へ正規実装（コミット `26904da`）．
  - 残差 1.6〜1.9× は LSC で対処予定（[Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手) 未着手）．**残差はガンマ曲線いじりで消さず正直に保持**．

### Step 8-4: max_depth 検証 (8 → 12)

- **日付**: 2026-05-18 頃
- **背景・問題意識**: `max_depth=8` で打ち切ると `0.85^8 ≈ 27%` のエネルギーが「未追跡」のまま残る．均一化に効く **後段多重反射** を取りこぼしている可能性．
- **仮説（物理動機）**: 後段反射光は「均一な ambient 成分」（部屋の壁が消灯後も薄明るく見える理屈，閉じた拡散面でのインテグレーティングスフィア応答）．これを取りこぼすと勾配が **系統的に過大評価** される．
- **試した変更**: 同条件で `render.max_depth` を 8 と 12 で比較レンダ．
- **期待した効果**: depth↑ で勾配 ↓．
- **実際の結果**: 同一 R=0.85, spp=1024 で
  - 勾配 (linear): 24.65 → 22.08 = **-2.6 pt**
  - 勾配 (sRGB): 12.57 → 11.16 = **-1.4 pt**
  - CoV (sRGB, R0.85): 0.089 → 0.091（誤差レベル，方向は spp ノイズに埋もれる）
- **解釈**: depth=8 は系統的に勾配を **過大評価**．エネルギー 27% 未追跡分のうち均一寄与分が効いていた．
- **学び**:
  - **キャリブ用途は depth≥12 推奨**．
  - レンダコスト ~1.5× になるので，確定 `configs/scene_baseline.yaml` の `render.max_depth` は **現状 8 のまま**（既知差分 #8）．
  - 3D ベイクは可視化用途で **均一性をなるべく忠実に**見せたいので，`--bake-max-depth 16` で render 設定から独立化（コミット `a0fe07d`）．**「2D 校正都合」と「3D 可視化忠実性」を分離**．
- **次のアクション**: 確定 YAML の depth 変更は保留．3D ベイクのみ独立化で適用．

### Step 8-5: 3D 可視化改善（path ベイク・テクスチャ投影・幾何カリング etc.）

- **日付**: 2026-05-18 〜 2026-05-XX（コミット `7181efa`, `c32ccd6`, `a0fe07d`）
- **背景・問題意識**: 内部キャリブ調整は 8-3 までで頭打ち感．並行して **シミュ結果の「見せ方」**（3D ビュー）が分かりにくい問題が浮上．特に「評価板はテクスチャ投影で正確，壁は per-vertex ベイクで荒い」という **手法非対称** が，物理判断の混乱を生んでいた．
- **仮説（物理動機，複数）**:
  - per-vertex ベイク（直接光 + cos） → **path ベイク（多重反射込み per-face MC）** にすれば物理的に正確になる．
  - 評価板・壁・カバーをすべて同じ手法（path ベイク）で計算し，**共有 clim・統一着色** で見せれば，相対比較が物理に基づく．
  - 隣接内壁の「見かけ 100 倍段差」は物理ではなく，**法線が外を向く「外向き面（≈ 0 入射）」の混在** が主因では？
- **試した変更**:
  - `src/sm_tias_lightsim/visualize/baker.py` に `mode="path"`（scalar_rgb，コサイン重点 hemisphere MC，多重反射込み per-face 照度）追加．`exclude_mesh_ids` 対応．`max_depth` 引数で render 設定から独立．
  - `src/sm_tias_lightsim/visualize/viewer.py` 全メッシュ統一着色（共有 lit-clim・log/linear・単一カラーバー・viridis・depth peeling）を既定化．
  - `--render <luminance.npy>` で評価板への任意テクスチャ投影（E = π · L / ρ で壁と同一 W/m² スケール）．
  - `--bake-cache <npz>` で 1 回計算 → 以後即時．
  - `--cull-outward`（既定 ON）で外向き ≈ 0 面を非描画．
  - `--bake-max-depth`（既定 16）で render 設定から独立．
  - `--no-sensor-marker` / `--no-led-markers` / `--no-markers` でマーカー個別非表示．
- **期待した効果**: 評価板も壁も多重反射込みで正しく着色，共有 clim で物理どおりの相対比較が可能になる．外向き面除外で「暗殻の濁り」「見かけ段差」が消える．
- **実際の結果**:
  - 評価板を path ベイクで多重反射込み着色．壁・カバーとも統一 clim でほぼ均一に見える（物理どおり）．
  - 外向き面除外で「隣接内壁の見かけ 100 倍段差」が解消．内壁照度自体は同一手法ベイクで ~1〜2 倍以内 ＝ **物理どおりほぼ均一**だった．
  - 一方，per-face MC ベイク特有の **シーム/粒状感/scalar_rgb の遅さ**（高 samples 非現実的）は残る．
- **解釈**:
  - 「見え方の問題」と「物理の問題」を **厳格に分離**: 同一手法で計算すれば物理は均一．見かけ段差は **手法非対称**（評価板＝テクスチャ・壁＝ベイク）と **外向き面の混入** で説明できた．
  - per-face MC ベイクの原理的天井（粒状感・継ぎ目）は **対症療法で消えない**．
- **学び**:
  - **物理量と計算手法の対称性を常に問う**: 同じ物理量を異なる手法で計算してはいけない．
  - **見え方 ≠ 物理**: 見かけ 100 倍段差が出ても，同手法で再計算すれば 1〜2 倍以内なら物理は均一．
  - per-face シーム/粒状感の解消は **全メッシュ UV 統合シームレスライトマップベイク** が必要 ＝ 別プロジェクト規模．
- **次のアクション**:
  - 精細な評価は引き続き 2D `sm-render`/`sm-evaluate`（path tracer）で（**校正済みの定量結果**，不変）．
  - シーム解消は別タスク（必要時に `/implement`）．
  - path ベイク高速化（wavefront/GPU 化）も別タスク．

### Step 8-6: LED 物性確定 (LP-2835D90VW)

- **日付**: 2026-05-27（コミット `f5048a4`）
- **背景・問題意識**: SPEC_03 既知差分 #3「LED 1 個あたりの実 W 値が未検証」を残していた．現状 `radiance=2807.247` は実測 mean アンカーで決まった校正値で，**規格値からの導出ではない**．LED 物性が確定すれば，独立に検証できる．
- **仮説（物理動機）**: 規格値から radiance を独立推定し，現校正値と並べる．大きく合えば **物理妥当性の担保**，合わなければ何かのレバーの不確かさを炙り出せる（縮退の所在が分かる）．
- **試した変更**: LED Paradise 商品ページから物性取得．SPEC_03 LED セクションを拡張．
  - 型番: **LP-2835D90VW**（Ra98 SunLightLED 2835 チップ LED 4000K）
  - 電気: Vf 3.1 V (typ), If 60 mA (max)，駆動条件は **規格通り 60 mA フル**（ユーザー確認）
  - 光学: Φv 16–19 lm @ 60 mA（中央値 17.5 lm），配光角 120°（半値全幅，Lambertian と整合），Ra 98，色温度 4000 K
  - 詳細 IES プロファイル：**未提供**（LED Paradise は公開せず）
- **期待した効果**: 校正値 2807 と規格推定が大きく合うか，どこに不確かさが残るかを明確化．
- **実際の結果**: 規格値から radiance を独立計算

  | ステップ | 値 |
  | --- | --- |
  | Φv（typ 中央値） | 17.5 lm |
  | LER（4000K Ra98 典型値） | ≈ 280 lm/W |
  | Φe = Φv / LER | **0.0625 W** |
  | A = 2.8 × 3.5 mm | 9.8 × 10⁻⁶ m² |
  | **規格推定 L = Φe / (A·π)** | **≈ 2030 W/(m²·sr)** |
  | 現状校正値 | 2807 W/(m²·sr) |
  | **比** | **1.38×** |

  - サニティチェック: ウォールプラグ効率 = Φe / (Vf·If) = 0.0625 / 0.186 ≈ **33.6%**（実用 LED として妥当範囲，Cree 等で 40%・廉価品で 25–30%）．
  - integrating sphere 近似で 1.38× を反射率に帰着: R=0.85 → 0.89 で `(1-0.85)/(1-0.89) = 1.36×`（観測 1.38× とほぼ一致）．R=0.89 はマット白プラ実用上限 0.92 の範囲内．
- **解釈**:
  - **規格 → radiance の換算は物理的に整合**（桁・係数とも）．
  - 校正値が 1.38× 高い差分は **反射率の不確かさに帰着可能**（物理範囲内 R≈0.89 で説明可）．LED 側が大きくおかしいわけではない．
  - 形状指標への影響なし（線形ゲイン）．
- **学び**:
  - 物理レバーを 1 個ずつ独立化する作業は，絶対値が動かなくても **不確かさの所在を局所化する** 価値がある．
  - 既知差分 #3 をクローズ（LED 物性確定・物理整合確認済み）．残課題は反射率の実フィラメント分光データでの再校正（既知差分 #1）に帰着．
  - 配光は「データシート記載が配光角 120° のみ，IES 未提供」．Lambertian 仮定は数学的に整合だが厳密検証は不可．実 SMD 2835 はやや前方凸の可能性があり ISP LSC と打ち消し合う近似として現状妥当．
- **次のアクション**: 次は LED 周辺幾何の検証（発光面サイズの妥当性）→ [Step 8-7](#step-8-7-発光面サイズ検証-2835-vs-1515φe-保存) へ．

### Step 8-7: 発光面サイズ検証 (2.8×3.5 vs 1.5×1.5，Φe 保存)

- **日付**: 2026-05-27
- **背景・問題意識**: 「現実装はパッケージ外形 2.8 × 3.5 mm を発光面として使う」仮定が物理的に正しいか疑問．実 SMD 2835 の真の発光部は **チップ + 蛍光体 ~1.5 × 1.5 mm**（パッケージ面積の ~23%）のみで，周りは白プラスチック筐体（光らない）．
- **仮説（物理動機，複数）**:
  - 評価板まで 65 mm vs 発光面 ~1.5〜2.8 mm → distance/size ≈ 25〜40 で **遠方界点光源近似**が成立．形状指標は発光面サイズに不変のはず．
  - 絶対値（mean）は校正で吸収済みなので変化しないはず．
- **試した変更**: `configs/scene_baseline_emitter_real.yaml` を Python ワンライナーで自動生成．
  - 全 18 LED の `size`: [2.8, 3.5] → [1.5, 1.5] mm
  - 全 18 LED の `radiance`: 2807.247 → **12227.12** W/(m²·sr)（スケール係数 4.356 = 元面積 / 新面積）
  - **Φe = L · A · π は厳密に保存**（0.0864 W per LED で同一）．
  - linear ドメインで `sm-evaluate` 比較（OETF 経由しない直接比較）．
- **期待した効果**: mean ≈ 不変，CoV/勾配/C/P/max-min/radial profile ≈ 不変（点光源近似が成立する遠方界）．
- **実際の結果**（linear，同条件）:

  | 指標 | 元 (2.8×3.5) | 検証 (1.5×1.5) | 比 | 評価 |
  | --- | --- | --- | --- | --- |
  | mean | 152.52 | 429.99 | **2.82×** | ⚠️ 予想外に大きく変化 |
  | std | 27.85 | 80.12 | 2.88× | mean スケールに比例 |
  | CoV | 0.1826 | 0.1863 | 1.02× | ✅ 形状指標 ≈ 不変 |
  | 勾配 % | 24.65 | 26.21 | 1.06× | ✅ 形状指標 ≈ 不変 |
  | C/P | 1.327 | 1.355 | 1.02× | ✅ 形状指標 ≈ 不変 |
  | max/min | 4.28 | 4.36 | 1.02× | ✅ 形状指標 ≈ 不変 |
  | 放射プロファイル中心/端 | 1.63 | 1.68 | 1.03× | ✅ 形状指標 ≈ 不変 |

  画像保存先: `output/baseline_linear_npy/` と `output/emitter_real/`（各 `figures/luminance_map.png`, `radial_profile.png`, `histogram.png`, `zone_map.png`）．放射プロファイルの曲線形は**目視で瓜二つ**，色スケールのみ違う．
- **追跡調査**: 予想外の 2.83× mean 上昇の機序を STL 幾何分析で追跡．
  - LED 基板カバー（`meshes/LED基板カバー.stl`）は z=-66.6〜-64.1 の 2 階建て構造（天井梁 + 底板）．
  - LED 中心 z=-65.3 は底板 z=-65.5 の上面から **0.2 mm の至近距離**．
  - 底板には LED ごとに **複雑な曲線形の穴**あり（trimesh の euler_number=-4 ＝ genus 3 と整合）．LED は穴の中に位置．
  - 仮説: 厚みゼロの面光源（z=-65.3）と固体（z=-65.5〜-66.6）の **0.2 mm coplanar 状態**で Mitsuba 上に予期しない遮蔽相互作用が起きている可能性．完全機序解明には Mitsuba のレイトレース内部追跡が必要（時間 vs 効果が合わないので深入りせず）．
- **解釈**:
  - **形状指標**については仮説（点光源近似）が **実証成立**: CoV/勾配/C/P/max-min/radial profile すべて 1〜6% 以内（spp=1024 の MC ノイズ範囲程度）．
  - **絶対値**については仮説が **不成立**: mean が 2.83× も動いた．発光面サイズと **LED 周辺幾何（カバー）の縮退**で，両者は分離できない．
  - 校正値 2807 は「2.8 × 3.5 mm 発光面 + 現カバー幾何」の組み合わせで決まる縮退値．発光面サイズだけ変えると mean が大きく動くが，それを校正で吸収させれば形状指標は変わらない．
- **学び**:
  - 「点光源近似で発光面サイズは結果に効かない」は **不完全な命題**：**形状指標**については成立，**絶対値**については局所幾何との縮退で不成立．
  - 現実装は「発光面が物理的には不正確（パッケージ外形を使用）」だが，**シミュ目的（相対分布評価）の妥当性は守られている**．
  - 厚みゼロ面光源と固体の coplanar/near-coplanar 配置は，**Mitsuba 上での挙動が直感に反する**ことがある．将来 LED 周辺幾何（カバー設計）を変更する場合は，発光面サイズも同時に見直す必要がある．
  - 完全機序解明より「**確認できた事実を正直に記録**」を優先する判断は，時間 vs 効果のトレードオフで妥当．
- **次のアクション**:
  - SPEC_03 LED セクションに「発光面サイズの近似と検証」記述を追加（本ドキュメント完成後）．
  - 検証用ファイル `configs/scene_baseline_emitter_real.yaml`, `configs/eval_baseline_linear.yaml`, `output/emitter_real/`, `output/baseline_linear_npy/` は **検証アーティファクト**として保持（後から再現できるように）．
  - 本筋 LSC モデル化（[Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)）に進む．

### Step 8-8: linear 評価モードへの mean 揃え正規化導入

- **日付**: 2026-05-27
- **背景・問題意識**: Step 8-7 で size 1.5×1.5 検証時，linear ドメインでの絶対値 mean が 429.99（baseline は 152.02）まで跳ね上がった．**形状指標は不変だったが，輝度マップを画像で並べると color scale が桁違いで「形」の比較が阻害される**．[TEST_03 輝度マップ形状追跡](TEST_03_輝度マップ形状追跡.md) で問題化．
- **仮説（物理動機）**: OETF 順方向適用（[Step 8-3](#step-8-3-oetf-順方向適用手法訂正)）の露出アンカーと同じ思想を linear ドメインに対称展開する．線形ゲイン `α = target_mean / mean` は形状指標 (CoV / 勾配 / C/P / max-min) に対し **厳密に不変** なので，「絶対値スケールだけ揃える」操作として安全に適用できる．
- **試した変更**: `sm-evaluate` に `normalization` セクションを追加実装．
  - 新規モジュール `src/sm_tias_lightsim/evaluation/normalize.py` の `apply_mean_anchor(values, target_mean) -> (normalized, alpha)`．
  - `EvaluationConfig` スキーマに `NormalizationConfig`（enabled / type Literal["mean_anchor"] / target_mean）追加．
  - `model_validator` で OETF + normalization 同時有効化を **ValidationError** として禁止（露出アンカー二重適用回避）．
  - ROI 抽出後・OETF 前段に正規化ステージを挿入（パイプライン [4] に該当）．
  - `configs/eval_baseline_linear.yaml` に `normalization.enabled: true / target_mean: 146.7146` を設定．
- **期待した効果**: linear 評価結果の mean が常に 146.7146 に揃い，形状指標は変更前と一致．
- **実際の結果**（`output/baseline/luminance.npy` で動作確認）:

  | 指標 | 正規化前 (mean=152.52) | 正規化後 (mean=146.71) | 差 |
  | --- | --- | --- | --- |
  | mean | 152.5204 | **146.7146** | target_mean に厳密一致 |
  | CoV | 0.1826 | 0.182577 | ≈ 不変（誤差レベル） |
  | max/min | 4.2759 | 4.2759 | 厳密一致 |
  | C/P | 1.3271 | 1.3271 | 厳密一致 |
  | 勾配 % | 24.65 | 24.65 | 不変 |
  | std | 27.85 | 26.7868 | α=0.962 倍にスケール（想定通り） |

  α = target_mean / src_mean = 146.7146 / 152.52 = **0.961934**．
- **解釈**: 線形ゲイン正規化の物理的不変性が**実証された**．形状指標は誤差レベルで一致し，mean は厳密に target_mean に揃う．後段の TEST_03 比較パネル再生成に向けた評価本体の対称化が完了．
- **学び**:
  - **「データに合わせて回す係数ゼロ」の操作は，linear / sRGB 両ドメインに対称に展開できる**．OETF 露出アンカー（Step 8-3）と本 Step は同じ思想で，適用ドメインが違うだけ．
  - 排他制御をスキーマレベル（`model_validator`）で実装することで，二重適用のリスクを使用時点ではなく設定時点で防げる．
  - 単体テスト・スキーマテスト・CLI 統合テストの 62 件追加で挙動の厳密性（mean 一致・形状指標不変）が保証された．
- **次のアクション**:
  - TEST_03 の比較パネル生成スクリプト (`scripts/build_luminance_evolution_panel.py`) が利用する Step 8-1 / 8-7 の入力を **linear + normalization** 評価結果に揃え，color scale を共有して「形」の比較を強化する（別フェーズ・別コミット）．
  - 本筋 LSC モデル化（[Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)）は引き続き未着手．

### Step 8-9: LED 位置を Fusion 360 設計 STL から抽出して反映

- **日付**: 2026-05-28
- **背景・問題意識**: [既知差分 #2](#既知の差分-実機との不一致)「左右 LED 基板の正確な位置・向き」が未解消だった．現 YAML の LED 18 個の座標は **「下基板を Z 軸まわり ±90° 回転」と推定**で算出していたため，Fusion 360 設計とのズレが残る可能性．特に下基板内の **LED 6 個の X 配置を等間隔 8.7mm と仮定** していたが，実機写真 (`REFERENCE/led_board_closeup.jpg`) を見ると **3 個 + 部品ギャップ + 3 個** の配置と疑われていた．
- **仮説（物理動機）**: Fusion 360 のアセンブリ全体を STL でエクスポートすれば，3 基板分の LED 18 個 + LED 基板カバー 3 枚をワールド座標で取得できる．それを真の値として YAML を更新すれば，既知差分 #2 をクローズできる．形状指標への影響は不明だが「物理表現の正確さ」が向上する．
- **試した変更**:
  - `configs/meshes/SmTIASv3.stl` を Fusion 360 で全体エクスポート（File → Export，ワールド座標系）
  - 抽出スクリプト `scripts/extract_led_positions_from_stl.py` を新規作成: 連結成分分割 (union-find) → LED 候補 (extents ≤4×4×1.5mm) / カバー候補 (extents 細長板状) で分類 → 各 LED に最寄りカバーを紐付け → bottom/right/left 自動命名 + 基板内ソート
  - 抽出結果 `configs/leds_extracted.yaml` を `scene_baseline.yaml` の `lights` セクションへ置換（18 LED）
- **期待した効果**:
  - 既知差分 #2 のクローズ
  - 形状指標は **多重反射が支配的なら微変化のみ**，大きく動かない予想
  - LED 配置の物理的正確性が向上
- **実際の結果**（`output/baseline_v3_leds/`，linear + normalization 評価）:

  | 指標 | 旧 LED（推定値） | 新 LED（Fusion STL） | 差 |
  | --- | --- | --- | --- |
  | mean (pre-normalize) | 152.52 | **167.95** | **+10.1%** |
  | α (mean 揃え係数) | 0.961934 | **0.873423** | -10% |
  | mean (post-normalize) | 146.7146 | 146.7146 | 同（アンカー一致） |
  | CoV | 0.18258 | 0.18151 | -0.6% |
  | 勾配 % | 24.65 | 24.13 | -0.5pt |
  | C/P | 1.327 | 1.318 | -0.7% |
  | max/min | 4.2759 | 4.2713 | ≈ 0 |
  | std | 26.79 | 26.63 | -0.6% |

- **LED 位置の主な変更**:

  | 観点 | 旧 YAML | 新 STL（Fusion） |
  | --- | --- | --- |
  | 下基板 X 配置 | 等間隔 8.7mm × 6（-21.67〜+21.67） | **3+ギャップ+3**（4.2mm 間隔 + 中央 10.8mm + 4.2mm 間隔，-10.0〜+17.6） |
  | 下基板 X 中心 | 0.0 | **+3.8（右オフセット）** |
  | 左右基板 X 距離 | ±70.2 | **±66.0**（4.2mm 内側） |
  | 左右基板 Y 中心 | 0.0 | **-12.0**（やや下寄り） |
  | Z 位置 | -65.3 | **-66.1**（0.8mm スマホ側） |
  | direction（全 LED） | (0, 0, -1) | (0, 0, -1)（不変） |

- **解釈**:
  - **形状指標は 1% 以内のほぼ不変**．多重反射が支配的で，LED 位置の数 mm レベルの誤差は ROI 上で平滑化される（評価板まで 65 mm に対し誤差 ~4 mm は約 6%、多重反射でさらに薄まる）．
  - **絶対 mean が +10% 増加**．新 LED 配置の方が評価板への光量効率が高い（理由: 不明だが，下基板 X 中心が +3.8mm 右オフセットしていて評価板中央への幾何関係が変わった可能性）．mean アンカーで吸収されるため形状指標には影響しない．
  - **形は出発点と同じ Y 軸単調勾配**（[TEST_03 比較パネル](TEST_03_輝度マップ形状追跡.md) で確認）．LED 位置の正確化も「形を変えない変更」の一例．
  - 実機写真 (`REFERENCE/led_board_closeup.jpg`) で LED 配置が「3+ギャップ+3」と一致．これは中央の電流制限抵抗 2 個分のスペース（10.8mm）に対応．
- **学び**:
  - **設計データ (Fusion 360) を真実の源にすると物理表現が正確になる**．手動推定座標はエラーが入りやすい．
  - **形状指標は LED 位置の細かいズレに対し頑健**．多重反射が支配的なシーンでは数 mm の誤差は薄まる．これは Step 8-7 の発光面サイズ検証と同じ「点光源近似」の系の発見．
  - これで既知差分 #2 がクローズ．既存の改善ステップ 8-1〜8-7 + 本 Step 8-8/9 で **「形を変えない変更」の集合が完成**．本筋 LSC モデル化（Step 8-N）に進む準備が整った．
- **次のアクション**:
  - SPEC_03 既知差分 #2 をクローズ
  - 本筋 LSC モデル化 ([Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)) に進む

### Step 8-10: LED 配光を spot emitter で表現（X 方向の部分改善）

- **日付**: 2026-05-28
- **背景・問題意識**: Step 8-1〜8-9 で「形を変えない変更」を網羅し，emitter 指向性が形に効くかどうかを次に検証．データシート LP-2835D90VW の配光角 120° (FWHM) は数学的に厳密 Lambertian（現状の `area` emitter）と整合するが，Mitsuba の `spot` emitter で smoothstep 補間を使うと「中央集中度」が違うため，多重反射経由の評価板への分布が変わる可能性．
- **仮説（物理動機）**:
  - LED の指向性プロファイルが変わると，LED 直下の壁の局所照度が変わる
  - 多重反射経由でも評価板への分布パターンに微変化が出る可能性
  - ただし「Y 軸単調勾配」は LED 配置（下・左・右の U 字型 3 基板，上対応の基板なし）の物理的偏りなので emitter 指向性では変えられない予想
- **試した変更**:
  - `src/sm_tias_lightsim/scene/schema.py` に `SpotLight` クラスを新規追加（type='spot', position, direction, cutoff_angle, beam_width, intensity）．`LightConfig` Union に組み込み
  - `src/sm_tias_lightsim/scene/lights.py` に spot 分岐を追加（look_at で to_world transform 構築 → Mitsuba `spot` emitter dict）
  - `configs/scene_baseline_spot.yaml` を新規作成：18 LED を area → spot に変換（flux Φ=0.0864 W per LED 保存）
  - パラメータ: `cutoff_angle=90°`，`beam_width=30°` （FWHM 120° と一致する最も標準的な設定）．数学的に半値（I/I_0=0.5）は θ=60° に出る
  - intensity `I_0=0.026784 W/sr`（smoothstep 配光積分 K=3.227 sr で `I_0 = Φ/K`）
- **期待した効果**: LED 指向性で X 方向（左右対称）の偏りが変わる可能性．Y 方向は不変予想．
- **実際の結果**（`output/baseline_spot/`，linear + normalization 評価）:

  | 指標 | Step 8-9 (area) | Step 8-10 (spot) | 差 |
  | --- | --- | --- | --- |
  | mean (pre-normalize) | 167.95 | **11.49** | **-93%（spot は約 14.6× 暗い）** |
  | α (mean 揃え係数) | 0.873 | **12.77** | × 14.6 |
  | mean (post-normalize) | 146.71 | 146.71 | 同（アンカー） |
  | CoV | 0.181 | 0.189 | +4.4%（**数値悪化**） |
  | 勾配 % | 24.13 | 27.69 | +14.7%（**数値悪化**） |
  | C/P | 1.318 | 1.383 | +4.9%（**数値悪化**） |
  | max/min | 4.27 | 4.15 | -2.8%（誤差レベル） |

- **目視観察（重要）**: 数値指標は悪化したが，**輝度マップを目視で比較すると下端の明るい領域がやや中央寄りに集中し，左右端は他のシミュより暗い**．X 方向の対称性が部分的に改善された．[TEST_03 比較パネル](TEST_03_輝度マップ形状追跡.md)で「他のシミュ 4 種と spot の 5 番目」を並べると spot のみ「下中央集中型」と判別できる．
- **解釈**:
  - spot の中央集中型配光（cutoff=90, beam=30）で LED 真下の壁が局所的に強く照らされる
  - その結果，ROI 下中央が他より明るく，下端左右は相対的に暗く
  - **X 方向に「中央集中型」のパターン**が形成された（実機の中央ピークの X 方向成分に部分的に符号一致）
  - Y 方向の偏りは LED 配置（下・左・右の U 字型 3 基板配置で上対応の基板がない）の物理的事実なので解消されない（**LSC モデル化が依然必要**）
- **副次的な発見（未解明）**: flux 保存で I_0 を計算したのに mean が 14.6× も暗くなった．仮説：(1) Mitsuba `spot` の falloff 関数が cos ドメインの smoothstep（私の計算は角度ドメイン smoothstep）で I_0 計算が不正確，(2) 点光源 vs 面光源で多重反射の光路長が違う，(3) spot の集中性で「LED 真下の壁」に光が偏り多重反射数が増えて減衰．本筋ではないため深掘りしない．
- **学び**:
  - **数値指標と「形」の改善は別軸**．「同心円状に近づいた」と目視で気付くことは CoV/勾配の集約値だけでは捕捉できない．[TEST_03](TEST_03_輝度マップ形状追跡.md) の「2 軸評価」の妥当性が再確認された
  - **emitter 指向性は形の一部（X 方向）を変える**．これは Step 8-1〜8-9 の「形を変えない変更」とは違う性質の変更
  - ただし **全方向で実機と一致するには LSC モデル化が依然必要**（Y 方向の中央ピーク）．spot は LSC と並列して使える補完手段
- **採用判断**: scene_baseline.yaml の area light はそのまま残し，**`configs/scene_baseline_spot.yaml` を並列保持**．本格採用するかは LSC モデル化との組み合わせ評価後に判断．SpotLight クラス・lights.py 分岐は将来の IES 実装等の基盤として残す．
- **次のアクション**:
  - 本筋 LSC モデル化（[Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)）に進む
  - LSC + spot の組み合わせ評価は LSC 実装後

### Step 8-11: データシート準拠の照明モデル統合（spot cos^1.2 + R=0.89）

- **日付**: 2026-05-28
- **背景・問題意識**: Step 8-10 で `spot` emitter (cutoff=90, beam=30 = FWHM 120° の標準解釈) の試行で X 方向の対称性が部分改善した．これを **データシート LP-2835D90VW + 物理的整合性** の両面で詰めるとどうなるか検証．
- **仮説（物理動機）**:
  - **A. パッケージ整合**: data sheet 規格値 (Φv=17.5 lm @60mA) と LER 280 lm/W から radiance を独立推定 (Φe=0.0625 W/LED)．反射率を Step 8-6 で導出された 0.89（規格 LED + 校正値 mean の物理整合点）に変更
  - **B. spot 配光詳細化**: 同等品 (Cree/Samsung/Lumileds 系 SMD 2835) の典型配光 cos^1.2 (前方凸) を spot で表現．半値 55.86° (FWHM 111.72°，データシート 120° よりやや前方寄り)
- **試した変更** (`configs/scene_baseline_datasheet.yaml` 新規):
  - LED 18 個を spot に変換：cutoff_angle=85°，beam_width=26.72°，I_0=0.021951 W/sr (Φe=0.0625 W を smoothstep 配光積分 K=2.847 sr で割って算出)
  - 反射率 0.85 → **0.89**（5 メッシュ共有の `printer_white`）
- **期待した効果**: 物理的に正確 + Step 8-10 の X 方向改善が継続 + 反射率上昇で多重反射が増えて Y 方向もわずかに均一化される可能性．
- **実際の結果**（`output/baseline_datasheet/`，linear + normalization 評価）:

  | 指標 | Step 8-9 (area, R=0.85) | Step 8-10 (spot 90/30, R=0.85) | **Step 8-11 (spot 85/26.72, R=0.89)** |
  | --- | --- | --- | --- |
  | mean (pre-normalize) | 167.95 | 11.49 | **10.26** |
  | α (mean 揃え係数) | 0.873 | 12.77 | **14.30** |
  | CoV | 0.181 | 0.189 | **0.183** |
  | 勾配 % | 24.13 | 27.69 | **26.79** |
  | C/P | 1.318 | 1.383 | **1.366** |
  | max/min | 4.27 | 4.15 | **4.11** |

- **目視観察**: 形は依然 Y 軸単調勾配．Step 8-10 と 8-11 の差は微小で，X 方向の集中度が**わずかに緩和**された程度（反射率 0.89 の多重反射均一化と cos^1.2 集中度の打ち消し合い）．**実機の中央ピーク楕円には近づかず**．
- **解釈**:
  - データシート従順度を上げ反射率を物理整合点に動かしても，**形は構造的に変わらない**（依然 Y 軸単調勾配）．多重反射と LED 配置の Y 軸偏りが支配的．
  - 数値指標は Step 8-9 area より悪化のまま (CoV +1%, 勾配 +11%, C/P +4%)．数値の意味では「悪化」だが，物理的には「データシート通り」．
  - **「物理的正確性」と「実機形への近づき」は別軸**．データシート準拠は物理正確性を担保するが，形改善には LSC 必要．
- **副次的な発見**:
  - α=14.30 で mean が大きく上がる（pre-norm 10.26）．spot+反射率 0.89 でも area+0.85 ほど評価板に光が届かない．これは LED 単体 flux 0.0625 W (規格) vs 校正値由来 0.0864 W (1.38× 多い) の物理差が表面化したもの．
  - 「データシート規格値」で動かすと **mean は実機 mean に直接合わない**（反射率 0.89 でも届かない）．真の物理を保つには **mean を実機にアンカーする校正値 (radiance=2807)** を依然必要とする．これは [Step 8-6](#step-8-6-led-物性確定-lp-2835d90vw) で議論した「校正値は局所幾何・反射率不確かさの累積吸収」が真であることを再確認．
- **学び**:
  - データシート準拠の物理モデルは正しいが，**実機の校正値 (mean=146.71) を物理パラメータで一意に再現するには反射率以外のレバー (LED 配光・幾何・材料異方性) も同時に動かす必要**がある．
  - 既知差分 #1 (反射率) のクローズは依然 **実フィラメント分光データの実測が必要**．同等品 0.89 の推定値では校正一致しない．
  - **形の改善は依然として LSC モデル化 ([Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)) が唯一の道**．
- **採用判断**: scene_baseline.yaml は area + R=0.85 のまま（Step 8-9 状態）．`configs/scene_baseline_datasheet.yaml` は **「データシート従順版」として並列保持**．LSC モデル化との組み合わせ評価後に本格採用可否を判断．
- **次のアクション**:
  - 本筋 LSC モデル化（[Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)）に進む
  - LSC + データシート従順版の組み合わせは LSC 実装後

### Step 8-12: Helmholtz 相反原理の Mitsuba 上での実証検証

- **日付**: 2026-05-28
- **背景・問題意識**: 「光線追跡の方向 (path/ptracer) で形が変わるか」 という直感に対して，数学的事実 (Helmholtz 相反原理＝光線追跡の方向は無限サンプル極限で同じ結果) を Mitsuba 上で実証するか，例外があるかを実機検証．LSC モデル化に進む前に「方向変更で形を実機に近づける」可能性が無いことを確証するため．
- **仮説（物理動機）**:
  - Helmholtz 相反原理: BRDF は方向対称，光輸送方程式は時間反転対称．バックワード (path) とフォワード (ptracer) は同じ積分の異なるサンプリング順序．**収束先 (真値) は同じ**．
  - 違いは収束速度 (分散) と Mitsuba 実装の正規化の細かい差異だけ．
  - MiniTIAS のような「センサ小・光源分散・拡散主体」シーンでは ptracer が極端に非効率 → spp が大きく必要．
- **試した変更**:
  - `schema.py` の `RenderConfig.integrator` Literal に `ptracer` を追加（4 値: path/direct/volpath/ptracer）
  - `configs/scene_baseline_perspective_path.yaml` / `configs/scene_baseline_perspective_ptracer.yaml` を新規作成（同じシーン，sensor 切替: orthographic → perspective, fov=90°, scalar_rgb, spp=4096）
  - 注意: **orthographic + ptracer は Mitsuba 3 で `Endpoint::sample_direction(): not implemented!` でエラー**．orthographic sensor が ptracer の光子受け取りインタフェースを実装していない仕様．そのため検証は **perspective sensor で実施**．
- **期待した効果**: 両方の結果（同じシーン）が同じ形になることを実証．それで「方向変更では形を変えられない」が確定．
- **実際の結果** (spp=4096, scalar_rgb, perspective):

  | 指標 | path (backward) | ptracer (forward) | 比 |
  | --- | --- | --- | --- |
  | mean | 160.24 | 319.04 | **1.99×（Mitsuba 実装の正規化差）** |
  | std | 29.15 | 74.94 | 2.57× |
  | max | 212 | **4919** | 23×（ptracer の光子集中スパイク残） |
  | **Y プロファイル top** | 67.36 | 110.14 | 1.64× |
  | **Y プロファイル mid (Y=256)** | 190.99 | 380.44 | 1.99× |
  | **Y プロファイル bot** | 137.05 | 220.98 | 1.61× |
  | **bot/top 比（形の指標）** | **2.035** | **2.006** | **0.986 ←ほぼ完全一致** |

- **解釈**:
  - **形の一致**: bot/top 比が誤差 1.4% で一致．Y プロファイルの曲線形状は path と ptracer で **驚くほど一致**．**Helmholtz 相反原理が Mitsuba 上で「形について」実証された**．
  - **絶対値の差**: mean が 1.99× 違う．これは **Mitsuba 3 の path/ptracer 出力 luminance の正規化差** によるもので，形には影響しない（線形ゲイン）．
  - **ptracer のノイズ**: max スパイク 4919 が残る（光子集中の確率的事象）．spp を上げれば収束するが，spp=4096 でも形は明確に見える．
- **学び**:
  - **光線追跡の方向は「形」を変えない**：これが MiniTIAS のような拡散主体シーンでは Mitsuba 上でも数値的に確認された．
  - **絶対値スケールは integrator 実装の正規化差で違う**：物理的には等価でも，Mitsuba の出力単位定義が path/ptracer で違う．これは「形」の議論には影響しない．
  - **orthographic + ptracer は Mitsuba 3 では実行不能**：これは MiniTIAS のシーン構成では path/ptracer を直接比較できない技術的制約．perspective sensor でのみ検証可能だった．
  - **方向変更で形を実機に近づける道は無い**ことが（部分的に）実証された．**LSC モデル化が唯一の道**との結論を強化．
- **次のアクション**:
  - 本筋 LSC モデル化（[Step 8-N](#step-8-n-候補-lsc-順方向モデル未着手)）に進む

## Step 8-N 候補: LSC 順方向モデル（未着手）

- **位置付け**: 8-3 OETF 適用後の残差 **1.6〜1.9×**（CoV 0.089 vs 実測 0.043，勾配 12.57 vs 6.10）の **主因候補**．
- **仮説（物理動機）**: 実測 PNG は実機 ISP の **レンズシェーディング補正**（周辺光量低下の電子補正）が掛かっており，**周辺を持ち上げて中央を相対的に押し下げる**．これは残差の符号（シミュ側の方が勾配・C/P が大きい）と整合．シミュ側で同じ補正を順方向に適用すれば消える可能性が高い．
- **設計方針**: **overfitting 回避**のため，自由多項式ではなく **物理動機づけ低自由度形** に限定する．
  - cos⁴ 則（典型的なレンズ周辺減光則）をベースに，平滑な動径多項式 2〜3 パラメータ
  - 適用順: ROI 抽出後・OETF 順方向適用の **後段** にフックを追加するのが筋（実機 ISP の処理順と整合）
  - パラメータ推定は実測 1 枚での fit ではなく，**物理パラメータ（センサ位置・レンズ F 値・撮像距離）から導出**できる範囲で
- **未確定事項**:
  - 実機カメラ（SH-02M）の正確なレンズ仕様（F 値，焦点距離）
  - ISP のレンズシェーディング補正テーブルの直接取得は不可（メーカー独自）
  - スマホ独自トーンマップ（残差の一部，さらに不確実）も同時に推定するか分離するか
- **想定される結果**:
  - 残差が 1.6〜1.9× → **1.0〜1.2×** まで縮まる可能性
  - 残らない場合: スマホ独自トーンマップ・反射率の実フィラメント精緻化・LED 配光詳細化 などへ
- **要する作業量**: コード（`evaluation/lsc.py` 新規・eval スキーマ拡張・テスト）＋ パラメータ推定（実機写真からの動径フィット）で 1〜2 日相当．

## 改善ストーリーの要約 (Takeaways)

イテレーション全体を俯瞰したときに残る**判断指針**:

- **MC ノイズ vs 物理勾配の切り分けは spp スイープが安価で有効**（8-1）．これを早期に行うとその後の方向性が決まる．
- **弱いレバーで攻めて手詰まりになったら，「評価方法そのもの」を疑う**（8-2 → 8-3）．非線形変換下では無次元指標は不変ではない．
- **標準仕様（OETF, Rec.709 等）の見落としは最大の交絡源になりうる**（8-3）．データに合わせて回す係数ゼロで残差の 2/3 を消した事例．
- **「校正都合」と「物理忠実性」を独立パラメータで分離する**（8-4 max_depth 独立化，8-5 path ベイク独立化）．校正に最適な depth と可視化に最適な depth は違って良い．
- **同じ物理量を異なる手法で計算しない**（8-5）．手法非対称は混乱の源．
- **物理レバーは 1 個ずつ独立化する**．絶対値が動かなくても **不確かさの所在を局所化** する価値がある（8-6 LED 物性，8-7 発光面サイズ）．
- **予想外の結果は仮説より雄弁**．完全機序解明より「確認できた事実を正直に記録」を優先（8-7）．
- **形状指標と絶対値は別物**として扱う．多くのレバーは形状指標には不変（線形ゲイン）だが，絶対値は局所幾何との縮退で動きうる．
- **失敗・予想外の記録は学びの宝庫**．方向性ドリフトを防ぐ核は「失敗を消さずに残す」こと．

## 輝度マップ形状の追跡 (→ TEST_03)

数値指標と独立に **輝度マップの「形」** を実機に近づける観点は [TEST_03_輝度マップ形状追跡](TEST_03_輝度マップ形状追跡.md) に独立化した．要点のみ:

- これまで実施した 7 つの改善ステップ (8-1〜8-7) は **すべて「形を変えない変更」** だった（線形ゲイン・単調変換・局所幾何依存のいずれか）．シミュは初期から **Y 軸単調勾配**のままで，実機の **中央付近ピーク**には近づいていない．
- 実機の形 = シミュの Y 軸勾配 + カメラ系の動径補正．**LSC モデル化（[Step 8-N 候補](#step-8-n-候補-lsc-順方向モデル未着手)）は数値残差縮小だけでなく形の構造的改善を担う**．
- 以後の改善判断は **「数値 + 形」の 2 軸** で行う．

比較パネル・観察事実・物理的解釈の詳細は TEST_03 参照．

## 参照 (References)

- [SPEC_03_基準設計の物理構成](../04_SPEC/SPEC_03_基準設計の物理構成.md)
- [SPEC_04_評価仕様](../04_SPEC/SPEC_04_評価仕様.md)（評価パイプライン・ROI・OETF・メトリクス・可視化の方法論）
- [SPEC_02_シーン定義仕様](../04_SPEC/SPEC_02_シーン定義仕様.md)
- [PLAN_02_開発ステップ](../03_PLAN/PLAN_02_開発ステップ.md)
- [TEST_02_シミュレーション実行記録](TEST_02_シミュレーション実行記録.md)（各 Step に対応する `output/` ディレクトリの索引）
- [TEST_03_輝度マップ形状追跡](TEST_03_輝度マップ形状追跡.md)（数値と独立に「形」を実機に近づける観点）
- 実装エントリ:
  - `src/sm_tias_lightsim/evaluation/oetf.py`（Step 8-3）
  - `src/sm_tias_lightsim/visualize/baker.py`（Step 8-5）
  - `src/sm_tias_lightsim/visualize/viewer.py`（Step 8-5）
- 検証アーティファクト:
  - `configs/scene_baseline_emitter_real.yaml`（Step 8-7）
  - `configs/eval_baseline_linear.yaml`（Step 8-7）
  - `output/emitter_real/`（Step 8-7 検証レンダ）
  - `output/baseline_linear_npy/`（Step 8-7 比較基準）
- 輝度マップ形状の追跡関連は [TEST_03_輝度マップ形状追跡](TEST_03_輝度マップ形状追跡.md) に集約
- 関連コミット: `26904da`（OETF 正規実装），`7181efa` / `c32ccd6` / `a0fe07d`（3D ビュー改善），`f5048a4`（LED 物性反映）
