# SmTIAS-LightSim

MiniTIAS（スマートフォン舌画像撮影装置）の照明均一性を実機制作前に検討するための光散乱シミュレーションツール．
LED 配置・ディフューザー形状を仮想的に変えながら，MiniTIAS-Evaluation と同じ指標（CoV／3 ゾーン分析等）で均一性を定量評価できるようにする．

## 開発進捗

現在の進捗: フェーズ 7（実装）— Step 1〜7 完了，Step 8（基準設計キャリブレーション）進行中．
Step 8 進捗: spp 校正（128→1024、ノイズ/物理差を切り分け）→ 反射率スイープ（0.75〜0.92、弱い二次レバーと判明）→ **手法訂正**: シミュ linear と実測 sRGB を直接突合していた交絡を発見．標準 sRGB OETF 順方向適用＋実測 mean アンカーで見かけ差の **約 2/3 が符号化ドメイン不一致**だったと判明．寄与順は OETF（最大）＞ ISP レンズシェーディング（残差主因候補）＞ 反射率（小）．残差 1.6〜1.9 倍は調整せず正直に保持．副次: max_depth=8 は勾配を過大評価（キャリブは depth≥12）．→ **OETF 順方向適用を sm-evaluate へ正規実装完了**（`evaluation/oetf.py` + `EvaluationConfig.oetf`、baseline 有効化・real 非適用、後方互換、参照実装と数値一致テスト済み）．[SPEC_03「キャリブレーション経過」参照](docs/04_SPEC/SPEC_03_基準設計の物理構成.md)．
補足: 内部キャリブ調整は一旦中断し、**シミュ結果の見せ方（3D ビュー）改善**を実施．評価板実レンダ投影 → **path ベイク（`baker.py` mode="path"、多重反射込み per-face、scalar_rgb）** 追加 → 全メッシュ統一着色（共有 lit-clim・log・単一カラーバー）を既定化、`--render` は任意のテクスチャ投影オプション（評価板 E=π·L/ρ で同一スケール）、`--bake-cache` で 1 回計算→以後即時、`--opacity`/`--hide-below`/`--bake-smooth`/`--bake-scale` を追加．さらに **path ベイク max_depth を render 設定から独立（`--bake-max-depth`、既定 16）**＝後段多重反射を積分、**幾何カリング（`--cull-outward` 既定 ON、外向き ≈0 面を非描画）**＝暗殻の濁り/見かけ段差を解消、マーカー個別非表示フラグ、を追加．実装完了．
既知の制約（受容済み）: per-face ベイクはメッシュ境界の継ぎ目・粗メッシュのブロック感・低 samples の MC ノイズ・scalar_rgb の遅さ（高 samples 非現実的）あり．精細な評価は 2D `sm-evaluate` で行う（不変）．隣接内壁の見かけ段差は調査の結果「外向き ≈0 面の混在」が主因と判明＝幾何カリングで解消（内壁照度自体は物理どおりほぼ均一）．
次のアクション（可視化・コミット後の別タスク）: シーム/粒状感の解消には全メッシュ UV 統合＋シームレスライトマップベイク（別プロジェクト規模）．必要時に別途 `/implement`．path ベイク高速化（wavefront/GPU）も別タスク．
補足: **実機搭載 LED の物性確定**（LED Paradise LP-2835D90VW / Ra98 SunLightLED 2835 4000K、Vf 3.1V・If 60mA・Φv 16–19 lm @60mA・配光角 120°・規格通り 60mA 駆動前提）．規格値から独立推定した radiance ≈ 2030 W/(m²·sr) は現状校正値 2807 と 1.38× 差で、反射率 0.85→0.89 への調整で物理範囲内に説明可能．既知差分 #3（LED 実 W 値未検証）クローズ．**形状指標への影響なし**（線形ゲイン）．配光は厳密 Lambertian 仮定継続（詳細 IES 未提供、実 SMD 2835 のやや前方凸性は ISP LSC と打ち消し合う近似として現状妥当）．詳細: [SPEC_03 LED セクション](docs/04_SPEC/SPEC_03_基準設計の物理構成.md#led光源)．
補足: **輝度マップ「形」の追跡を導入**（[TEST_03 輝度マップ形状追跡](docs/06_TEST/TEST_03_輝度マップ形状追跡.md) + `scripts/build_luminance_evolution_panel.py`）．重要な発見: **これまでの全 7 改善ステップ (8-1〜8-7) で輝度マップの「形」は全く変わっていない**．OETF は単調変換で形を変えず，発光面サイズ変更も形を変えない．**実機は中央付近にピークを持つ楕円状，シミュは下端のみ明の Y 軸単調勾配**．**LSC モデル化は「数値残差縮小」と「形の構造的改善」の両方を担う唯一の改善候補**．以後の改善判断は「数値 + 形」の 2 軸で行う．
補足: **Step 8-8 完了**．linear 評価モードに mean 揃え正規化を導入（`evaluation/normalize.py` の `apply_mean_anchor` + `EvaluationConfig.normalization` スキーマ + CLI 統合 + OETF 排他バリデーション）．OETF 露出アンカー（Step 8-3）と同じ思想を linear ドメインに対称展開．`configs/eval_baseline_linear.yaml` で有効化（target_mean=146.7146）．形状指標 (CoV/勾配/C/P/max-min) は厳密不変，mean のみ target_mean に揃う．動作確認: α=0.961934 で baseline luminance.npy が mean=146.7146, CoV=0.182577 で評価可能．テスト 62 件追加（既存 441 + 新規 62 = 503 件全通過）．
補足: **Step 8-9 完了**．LED 18 個の位置を Fusion 360 設計 STL (`configs/meshes/SmTIASv3.stl`) から抽出して `scene_baseline.yaml` を更新．`scripts/extract_led_positions_from_stl.py` で連結成分分割→ LED/カバー識別→ bottom/right/left 自動命名．主な変更: 下基板 LED 配置を「等間隔 8.7mm」→「3+ギャップ+3 (4.2mm+10.8mm+4.2mm)」へ訂正（実機写真の中央電流制限抵抗 2 個と整合）．左右基板も実位置に修正．**形状指標は ~1% 以内のほぼ不変**（多重反射が支配的，LED 数 mm 誤差は ROI 上で平滑化）．絶対 mean は +10% 増加（α 値 0.962→0.873）．既知差分 #2 をクローズ．TEST_03 比較パネルに Step 8-9 を追加（5 枚並列）．
補足: **LED 基板カバーを 3 枚構成に展開**．従来は下基板用 `LED基板カバー.stl` 1 枚のみだったが，`scripts/extract_led_positions_from_stl.py --export-covers configs/meshes/` で SmTIASv3.stl から `LED基板カバー下/右/左.stl` の 3 ファイルを書き出し，`scene_baseline.yaml` の geometry を `led_cover_bottom/right/left` の 3 メッシュエントリに展開．右・左基板の LED が「カバーなしで浮く」状態を解消．多重反射計算への影響は軽微だが物理的に正確．
補足: **Step 8-10 完了**．LED 配光を `spot` emitter (cutoff=90°/beam=30°，FWHM 120° 一致，flux 保存 I_0=0.026784 W/sr) で表現する試行．`SpotLight` クラスを `schema.py` に追加，`lights.py` に spot 分岐実装，`configs/scene_baseline_spot.yaml` を並列保持．**目視で X 方向の対称性が部分改善**（下端の明るい領域が中央寄りに集中）だが，数値指標は微悪化（CoV +4%, 勾配 +15%）．LED 指向性は形の一部（X 方向）を変えるが，Y 方向の中央ピークは LSC モデル化（Step 8-N）が必要．本格採用は LSC との組み合わせ評価後に判断．付随発見: spot で mean が 14.6× 暗くなる（理由は spot falloff 関数の cos vs 角度ドメイン smoothstep の解釈差等を仮説）．
補足: **Step 8-11 完了**．データシート LP-2835D90VW 準拠の照明モデルを統合．`configs/scene_baseline_datasheet.yaml` に並列保持．spot を cos^1.2 相当の前方凸 (cutoff=85°/beam=26.72°，FWHM 111.72°) に詳細化 + 反射率を Step 8-6 で導出した物理整合点 0.89 に変更 + I_0 を規格値 Φv=17.5 lm から導出 (I_0=0.021951 W/sr)．**形は依然 Y 軸単調勾配**で Step 8-10 と Step 8-9 の中間値．**データシート従順度を上げても形は実機に近づかない**ことを確定．副次的に「規格値だけで mean を実機に合わせることはできず，校正値には他のレバーの累積吸収が含まれる」が再確認された．本筋 LSC モデル化が依然必要．
補足: **Step 8-12 完了**．Helmholtz 相反原理を Mitsuba 上で実証検証．`schema.py` の RenderConfig に `ptracer` integrator を追加，`configs/scene_baseline_perspective_{path,ptracer}.yaml` で perspective sensor + scalar_rgb + spp=4096 で比較．**bot/top 比が path 2.035 vs ptracer 2.006 で誤差 1.4% で一致**＝形は方向独立．絶対値は Mitsuba 実装の正規化差で 1.99× 違うが形（空間パターン）は同じ．副次的発見: **orthographic + ptracer は Mitsuba 3 では実行不能**（`Endpoint::sample_direction()` 未実装）．これにより「方向変更で形を実機に近づける道は無い」が確定し，**LSC モデル化が唯一の道**である結論が強化された．
次のアクション（キャリブ再開時）: 残差に **LSC（ISP レンズシェーディング）順方向モデル**を当てる（物理動機づけ低自由度形、overfitting 回避・取得パラメータ数明記）．

補足: **速度最適化ワーク開始**（キャリブ作業を一旦中断）．[TEST_04 シミュレーション速度最適化履歴](docs/06_TEST/TEST_04_シミュレーション速度最適化履歴.md) に試行を集約．**Speed-0 ベースライン計測完了**（`configs/scene_baseline.yaml`，3 回中央値）: **B1 sm-render = 507.86 s（≈8.46 分）/ B2 sm-visualize path bake (samples=16) = 55.97 s**．**副次発見**: `DRJIT_LIBLLVM_PATH` 環境変数の消失で sm-render が ImportError でクラッシュしていたことを発見．`C:\Program Files\LLVM\bin\LLVM-C.dll` を発見し **User scope に永続化**して復旧．sm-visualize の direct bake は内部 scalar_rgb 固定のため過去ログでも警告は出ていたが完走していた．**方向修正**: Speed-1 当初の「JIT 有効化で高速化」は既に JIT 経路に乗っているため不成立 → 「LLVM-C.dll 自動検出と診断ログ」に再定義（再発防止）．**本命の高速化レバーは Speed-2 path bake wavefront 化**（10× 以上見込み）．GPU は Intel HD Graphics 520 のみで CUDA 不可，CPU 側完結方針．精度（spp/max_depth）は不変．
補足: **Speed-1 完了**．`src/sm_tias_lightsim/runtime/llvm_init.py` に `ensure_drjit_libllvm_path()`（標準パス自動探索→ `os.environ` 設定）と `log_variant_status()`（llvm_/cuda_/scalar_ 経路を INFO 明示，要求 llvm_* で実 scalar_* なら WARNING 追加）を新規実装．`render/runner.py` で variant=llvm_* 時に自動検出を呼び、`ImportError` 時は原因明示ログ→ re-raise．`visualize/baker.py` でも `log_variant_status` 呼び出し追加＋ Speed-2 wavefront 化用に LLVM 自動探索の分岐を先取り．`cli/render.py` で import 順を制御（`sensors.py`/`lights.py` のモジュールレベル `import mitsuba` 前に検出を確実に通す）．`docs/02_ENV/ENV_02_環境構築手順.md` に LLVM インストール手順・DRJIT_LIBLLVM_PATH 説明・動作確認コマンドを追記．**速度は不変**（コード経路同等）．新規テスト 51 件追加で **606 件全通過**（仕様 A1〜E1 すべてカバー）．数値同等性: SHA256 は MC 内部シードで異なるが平均相対誤差 7.23e-05（5σ 閾値 0.4508 に対し差 0.011）で統計同等性パス．これで「環境変数が消えて沈黙クラッシュ」する事故が再発しない土台が整備された．
補足: **速度最適化ワーク一旦中断**（Speed-2 path bake wavefront 化は未着手）．**実時間の改善は実質ゼロ**（B1=508s／B2=56s で不変）．副次的成果として環境破綻問題の発見と恒久対処，JIT 診断ログ，ベンチ条件のドキュメント，テスト 51 件追加が得られた．中断理由: B2 は現状ボトルネックではなく，B1 は CPU 完結・精度据置の制約下で取れる打ち手が限定的．本筋のキャリブ作業（LSC モデル化）に戻ることがプロジェクト目的により近い．再開条件: path bake samples を増やすユースケース発生／NVIDIA GPU 利用可／クラウド計算活用判断／キャリブ反復回数増加でバッチ時間が研究進度を圧迫した場合．詳細・Speed-2 テンプレ保持は [TEST_04 中断記録](docs/06_TEST/TEST_04_シミュレーション速度最適化履歴.md#中断記録-suspension-note--2026-05-28) 参照．次のアクション: キャリブ作業（LSC モデル化）に戻る．
補足: **キャリブ方針の根本見直し（2026-05-28）**．「シミュ vs 実機 PNG の比較」を再検討した結果，**実機 PNG 自体が定量データとして揺らいでいる**ことが判明．MiniTIAS の現行撮影は AE/AWB/NR/EDGE/TONEMAP/SHADING がすべて Camera2 API のオート/デフォルトで，撮影ごとに露光・WB・補正量が変動する．既存 baseline `MiniTIAS_20260408_144434` もこのモードで取得されており，シミュ側でいくらモデルを精緻化しても比較対象が不安定．**当初考えていた「LSC モデル化」より上位の問題**として「**定量撮影モード**」を MiniTIAS 側に追加することを優先する．Android Camera2 API には `STATISTICS_LENS_SHADING_CORRECTION_MAP` (LSC ゲインマップ取得)・`SHADING_MODE=OFF` (LSC 無効化)・`MANUAL_SENSOR`/`MANUAL_POST_PROCESSING` 能力フラグが存在し，これらを活用すれば「ISP 介入を最小化した再現性ある撮影」が可能．要求仕様を [TECH_01 定量撮影モード要求仕様](docs/05_TECH/TECH_01_定量撮影モード要求仕様.md) に，MiniTias 側 Claude セッションで作業着手するためのハンドオフ手順を [TECH_02 MiniTIAS 引き継ぎ手順](docs/05_TECH/TECH_02_MiniTIAS引き継ぎ手順.md) にそれぞれ新規作成．データ受け渡しは `reference_measurement/quantitative/` 配下（gitignore 対象）で `MiniTIAS_QM_YYYYMMDD_HHmmss.{png,meta.json,lsc.npz}` 命名規則．MiniTIAS 側で実装後，定量モードで再撮影した baseline で改めてキャリブを進める方針．SmTIAS-LightSim 側のキャリブ作業は本仕様書を MiniTIAS に渡した時点で一旦停止．
補足: **MiniTIAS 側で定量モード実装完了（2026-06-01）**．[TECH_03 実装報告 (MiniTIAS 側原稿)](docs/05_TECH/TECH_03_定量モード実装報告とSHADING_MODE相談.md) と [TECH_04 SmTIAS-LightSim 側回答](docs/05_TECH/TECH_04_MiniTIASへの回答.md) を取り込み．**AQUOS sense3 (SH-02M) は `LEVEL_3`（最上位）でハードウェア能力フル**．Phase 1〜5 全完了で **DNG (RAW_SENSOR) 経路を第 1 優先採用**．撮影設定: 1/60s + ISO 40 + AWB/NR/EDGE/AF/AE OFF + TONEMAP 線形 + BLACK_LEVEL_LOCK + SHADING_MODE=HIGH_QUALITY (★) + STATISTICS_LENS_SHADING_MAP_MODE=ON．LSC マップは 13×17．保存ファイルは `MiniTIAS_QM_*.{dng, meta.json, preview.jpg}` 3 種，meta.json に LSC マップ・実適用値・センサ特性も埋め込み．**SHADING_MODE 判断**: HIGH_QUALITY を本流維持（Mitsuba orthographic 出力 ≒「ISP が完璧に補正できた場合の理想値」で HIGH_QUALITY DNG と直接比較が物理整合）．OFF 切替は将来のフォールバック条件 C1-C3 発動時のみ．データ転送は **adb pull 推奨**（MTP は大容量 DNG で不整合リスク）．既存実機 PNG の Y' 抽出は BT.601 係数（Rec.709 ではない）も判明．
補足: **作業フェーズを A/B に分割（2026-06-01）**．「連射再現性が確保できてもシミュとの対応が取れなければ意味が薄い」という研究上の判断から，**フェーズ A: 1 ショット撮影でシミュ vs 実機対応を先に検証** → **フェーズ B: 対応が取れたら連射 V1 再現性検証**の二段階方式に変更．フェーズ A で MiniTIAS 側に依頼するのは **画素統計・Hot pixel map（高優先 2 件）と白板 1 ショット試し撮りのみ**．**連射 UI は高優先→フェーズ B に降格**．SmTIAS-LightSim 側は DNG/meta.json/LSC マップ読み込み I/F・新規 baseline config を実装し，1 ショット突合で既存通常モード baseline 残差 2.1× が定量モードで変化するかを観察．結果次第でフェーズ B 移行 or SHADING_MODE フォールバック条件 C1 検討 or 物理モデル見直しを判断．[TEST_01](docs/06_TEST/TEST_01_キャリブレーション検証履歴.md) に **Step 8-13: 定量モード 1 ショット対応検証** として記録予定．
補足: **DNG 対応を MiniTias-Evaluation 側にも依頼（2026-06-01）**．PNG から DNG への撮影フォーマット変更に伴い，MiniTias-Evaluation も実機データの一次窓口として DNG 読み込み I/F の追加が必要．既存パターン（`uniformity.py` を MiniTias-Evaluation から SmTIAS-LightSim にコピー）を踏襲する役割分担を採用：**MiniTias-Evaluation 側で正規実装 → SmTIAS-LightSim 側にコピー**．[TECH_05 MiniTias-Evaluation DNG 対応要求仕様](docs/05_TECH/TECH_05_MiniTiasEvaluation_DNG対応要求仕様.md) に要求書を作成．主要 I/F: `load_image_dng(path, demosaic, black_level, output_format)` / `load_metadata(path)` / `load_lsc_map(path)` / `load_hot_pixel_list(path)` / `mask_hot_pixels` / `apply_lsc_inverse`（将来検証用）．既存 PNG 経路と並列対応（後方互換）．依存追加: `rawpy>=0.21.0`．想定実装工数 ~3.5 日（6 Phase）．完了後 SmTIAS-LightSim 側 Claude セッションで `src/sm_tias_lightsim/evaluation/dng_loader.py` 等にコピー．次のアクション: MiniTias-Evaluation 側 Claude セッションで TECH_05 を受領 → Phase 1 から `/implement`．SmTIAS-LightSim 側のフェーズ A 受け入れ実装は MiniTias-Evaluation 完了後に着手．
補足: **MiniTias-Evaluation 側 Phase 1 完了とハンドオフ受領（2026-06-01）**．MiniTias-Evaluation 側で TECH_05 Phase 1 (DNG 読み込み I/F) と LSC 順適用プロトタイプ・新指標 (動径 min/max 比) が完成し，ハンドオフパッケージとして SmTIAS-LightSim 側に渡された．受領記録は [TECH_06 MiniTias-Evaluation 引き継ぎ受領](docs/05_TECH/TECH_06_MiniTias-Evaluation引き継ぎ受領.md)，関連分析は [TEST_05 PNG/DNG 評価比較](docs/06_TEST/TEST_05_PNG_DNG評価比較.md) と [TEST_06 外乱光影響評価](docs/06_TEST/TEST_06_外乱光影響評価.md)．**5 つの重要発見**: (1) **TECH_05 の `apply_lsc_inverse` は誤り**（DNG は LSC 未補正で逆ではなく順方向適用が正しい．TECH_05 §4 を訂正済）．(2) **過去 Step 8 キャリブの残差 2.1× はドメイン不一致**（実機 PNG sRGB 0.0423 vs シミュ sRGB/linear 比較）：正しい linear 比較では DNG linear+LSC 0.0689 vs シミュ linear 0.183 = **真の残差 2.66×**．(3) **新実機ターゲット = `MiniTIAS_QM_20260601_124500`（暗闇撮影）**: CoV=0.0695, 勾配=8.35%, 中心/周辺=1.0911, 動径 min/max=0.860．Step 8-13 以降の正規 baseline．(4) **外乱光ロバスト確認**: 室内灯 ON/OFF で指標差 < 1%．SmTIAS 自前照明が支配的で外乱光モデル化不要．(5) **新指標 `calc_radial_min_max_ratio`** (20 点輪帯平均 min/max 比) を追加．次フェーズ: S2 (dng_loader.py コピー + 新指標マージ + rawpy 依存追加) と S3 (sm-evaluate DNG 対応 + Step 8-13 突合) を別 `/implement` パイプラインで実施．
補足: **S2 完了 (2026-06-01)**．`src/sm_tias_lightsim/evaluation/dng_loader.py` を `handoff_smtias_lightsim/src/dng_loader.py` の完全コピーで新規作成 (docstring のみ差し替え)．`src/sm_tias_lightsim/evaluation/radial.py` に `calc_radial_min_max_ratio` をマージ追加 (nan ビン除外を移植時に補強)．`pyproject.toml` に `rawpy>=0.21.0` 追加 (実 rawpy==0.27.0)．新規テスト 32 件追加 (`tests/evaluation/test_dng_loader.py` 341 行)．既存 537 + 新規 32 = **569 件全通過** (slow 除外)．**検証 V4 が完全一致**: 実 DNG (`MiniTIAS_QM_20260601_124500.dng`) を読み込んで LSC 順方向適用 + 白板 ROI で評価指標 6 件 (CoV/std/max-min/mean/max/min) が **相対誤差 < 1e-6 で期待値完全一致**，空間指標 3 件 (中心/周辺/勾配/動径 min/max) も絶対誤差 < 0.003．Refactorer 判断: `dng_loader.py` 内部の `_apply_srgb_oetf` は既存 `evaluation/oetf.py:apply_srgb_oetf` と実装重複だが「コピー方針優先」「用途が異なる」「違反基準 (3 箇所以上) 未満」の理由でそのまま放置．次フェーズ: S3 (sm-evaluate に DNG 入力経路追加 + 新規 baseline config + シミュ vs 実機 DNG 突合 → TEST_01 Step 8-13 記録) を別 /implement パイプラインで実施．
補足: **S3 方針見直しと Step D 完了 (2026-06-01)**．ユーザー指摘により「sm-evaluate に DNG 入力経路を追加する」当初案は **不採用**．理由: 実機 DNG 評価は MiniTias-Evaluation の本業で完結．SmTIAS-LightSim 側で重複実装する必要なし．S3 の作業範囲を **3 項目に絞り込み**: Step D (動径 min/max 比を sm-evaluate に統合)・Step C' (新規シミュ用 baseline config 作成)・Step G (シミュ再評価 → Step 8-13 として TEST_01 に記録)．**Step D 完了**: `MetricsConfig.radial_min_max: bool = False` をスキーマ追加 (`schema.py`)，`cli/evaluate.py` で `_run_radial_min_max` 関数追加して有効時に metrics.csv に 4 列 (radial_min_max_ratio / radial_min_distance / radial_min / radial_max) を末尾追加，コンソールサマリに 2 行追加．`radial_profile` を再利用 (重複算出回避)，未算出時は内部算出．後方互換維持 (既存 3 configs は無修正で動作)．新規テスト 39 件追加 (`tests/scene/test_metrics_radial_min_max_schema.py` 250 行 + `tests/cli/test_evaluate_radial_min_max.py` 740 行) で仕様 A1-D2 全カバー．既存 569 + 新規 39 = **608 件全通過**．SPEC_04 §動径 min/max 比 セクションを追記．次: Step C' (configs/eval_baseline_dng_target.yaml 作成: 既存 eval_baseline_linear.yaml ベース，target_mean=207.82，radial_min_max=true) → Step G (Step 8-13 計測)．
補足: **Step C' 完了と Step G 計測 (2026-06-02)**．`configs/eval_baseline_dng_target.yaml` を新規作成（eval_baseline_linear.yaml ベース，target_mean=207.82，metrics.radial_min_max=true，OETF なし）．動作確認で既存シミュ baseline (output/baseline/luminance.npy) を新 config で評価した結果，Step 8-13 数値が判明: シミュ CoV=0.1826, 勾配=24.65%, 中心/周辺=1.3271, 動径 min/max=0.6151．実機 DNG+LSC 補正 (CoV=0.0695, 勾配=8.35%, C/P=1.0911, 動径 min/max=0.860) と比較して **残差 2.63×**．これは TECH_06 で予想した「真の残差 2.66×」とほぼ一致．過去 Step 8-3 OETF 順方向適用時の「2.1×」は PNG sRGB ガンマ圧縮による楽観値であり，真の linear 比較では大きい．**LSC 取り扱いの結論を [TECH_07 LSC 取り扱い方針](docs/05_TECH/TECH_07_LSC取り扱い方針.md) として一元化**: 3 プロジェクト役割分担 (MiniTias=SHADING_MODE=HIGH_QUALITY 撮影 / MiniTias-Evaluation=lscMap 順方向適用 / SmTIAS-LightSim=一切扱わない)，シミュ側で LSC を扱わない物理的根拠 (Mitsuba orthographic = LSC 完璧補正後相当)，検討した代替案 3 つ (A: シミュに LSC モデル化追加・B: perspective+thinlens で物理 cos⁴・C: ISP 補正残差を物理導出) すべて却下，限界と注意点，フォールバック条件 C1-C3 (SHADING_OFF 撮影)，Step 8-13 残差 2.63× の解釈 (LSC 由来ではない別要因，物理モデル誤差の可能性) を明文化．残差 2.63× の解消は今後の課題 (物理モデル精緻化 or SHADING_OFF 撮影で切り分け or 形状相対比較に絞る) ．S3 残作業: TEST_01 への Step 8-13 正式記録・handoff_smtias_lightsim/ 削除．
補足: **実機変更とシミュ側対応の整合マッピングを明文化 (2026-06-02)**．[TECH_08 実機変更とシミュ側対応](docs/05_TECH/TECH_08_実機変更とシミュ側対応.md) として作成．実機側 8 項目変更 (PNG→DNG / AWB OFF / AE OFF / ガンマなし / NR OFF / EDGE OFF / LSC 維持 / LSC 順方向適用) に対するシミュ側 3 層 (Mitsuba シーン定義 α / sm-render β / sm-evaluate γ) の対応をマッピング．**結論: シミュ側で実際に対応が必要だったのは sm-evaluate の config レベルでの OETF 無効化 (#4) と mean アンカー調整 (#3) の 2 項目のみで，他はすべて対応不要 (Mitsuba は per-channel 独立計算で AWB/AE/NR/EDGE 概念なし，orthographic で LSC 自然対応)**．計 15 項目以上で網羅チェック，対応漏れなしを確認．特にガンマ補正は `configs/eval_baseline_dng_target.yaml` で OETF セクションを意図的に書かない形で Step C' にて対応済．**残差 2.63× は ISP 関連の対応漏れではなく，シミュ物理モデル誤差 (反射率精度・LED 配光モデル・メッシュ幾何精度等) が主因**と推定．詳細な切り分けは Step 8-14 以降の物理モデル精緻化として残す．
補足: **「対応不要」を 2 タイプに細分化 (TECH_08 §許容している構造的差異 追加)**．「対応不要」の理由を **タイプ I (本質構造同一・対応概念なし)** = AWB/NR/EDGE/LSC 等と，**タイプ II (構造的差異あり・白板で許容)** = AF (焦点モデル)/絞り口径食/ピクセル積分/センサノイズ/QE 波長依存/シャッター方式/温度依存 に分類．特に AF は実機 perspective+固定焦点 vs シミュ orthographic 無限遠相当という **シミュと実機の構造的な違い**を明示．白板撮影では影響軽微で許容しているが「ゼロ影響」ではない．舌模型評価時や残差精緻化フェーズで再評価対象．Step 8-13 残差 2.63× の主因はタイプ II ではなくシミュ物理モデル誤差と推定する従来結論は維持．
補足: **S3 全体完結 — TEST_01 に Step 8-13 正式記録 + handoff 整理 (2026-06-02)**．[TEST_01 §Step 8-13](docs/06_TEST/TEST_01_キャリブレーション検証履歴.md) に新方針 (実機 DNG+LSC linear) でのシミュ突合を Step 8-1〜8-12 と同フォーマットで正式記録．俯瞰サマリ表に新ターゲット (CoV=0.0695) と Step 8-13 結果 (CoV=0.1826, 残差 2.63×) を追加，過去 2.1× が PNG sRGB ガンマ圧縮による楽観値だった旨も明記．§Step 8-N 候補 (LSC 順方向モデル) を「不採用 — Step 8-13 で方針確定」のヘッダに更新し冒頭注記で経緯を残す (歴史的記録として保持)．`handoff_smtias_lightsim/` ディレクトリは S3 完結のため整理: 参考スクリプト `run_uniformity_dng.py` のみ `reference_measurement/quantitative/reference_scripts/` に移動 (MiniTias-Evaluation 側の正規評価実装 = LSC 順方向適用 + portrait 向き合わせ + ROI 抽出の参考．将来 SHADING_OFF フォールバック発動時の独立検証用)，他は全て SmTIAS-LightSim 側に取り込み済みのため削除．S3 全体 (S2 DNG ローダコピー + Step D radial_min_max 統合 + Step C' 新規 baseline config + TECH_07 LSC 方針 + TECH_08 対応マッピング + Step 8-13 計測 + handoff 整理) 完結．次のキャリブ作業は Step 8-14 以降の物理モデル精緻化 (反射率精度・LED 配光・メッシュ幾何) と TECH_04 フォールバック条件 C1 (SHADING_OFF 撮影) の並行検討．
補足: **LED データシート調査結果を [TECH_09](docs/05_TECH/TECH_09_LEDデータシート調査結果.md) として明文化 (2026-06-02)**．過去 SPEC_03 で「LED Paradise 商品ページにデータシート PDF 掲載なし」「詳細 IES 未提供」と記述していたが，**実は OEM 元 HONGLITRONIC (中国広州，鸿利智汇集团股份有限公司) のデータシートが存在**することが判明．LED Paradise LP-2835D90VW は HONGLITRONIC の HL-A-2835D90VW シリーズ (本命 PDF: lcsc.com/datasheet/C5362368.pdf, SPEC NO B-18-A-0831, 2022-01) の OEM 再販品．Vf 3.1V / 配光角 120° / 単チップ 2835 で物性整合．**配光図 (Page 6) から数値読み取り: ほぼ厳密 Lambertian (cos θ) と一致** (0°→1.0, 30°→0.87, 60°→0.50 FWHM, 80°→0.15, 90°→0)．分光分布 SPD も Page 6 に掲載 (NeutralWhite 4000K, 420nm 鋭ピーク + 500-650nm 蛍光体ブロード)．**重要な含意**: (1) 現状の area light Lambertian モデルはデータシート実測と整合．配光モデル精緻化余地は限定的．(2) **過去 Step 8-11「データシート従順版」(cos^1.2) は実態はデータシート不整合**だった (同等品 Cree/Samsung/Lumileds の典型配光を借用していた)．道理で形状指標が悪化．(3) **Step 8-14 候補 B (LED 配光詳細化) の意義は限定的**．残差 2.63× の主因は配光以外 (反射率精度・幾何・タイプ II 構造的差異・内壁の非 Lambertian 性等)．SPEC_03 の「やや前方凸」記述は HONGLITRONIC データシートでは確認できないので訂正対象．取得 PDF (a3b8d448*.pdf) と PNG (13 ページ) はリポジトリトップに一時保存．REFERENCE/ への正式取り込みは別タスク．

実装済みモジュール:
- `src/sm_tias_lightsim/uniformity.py` — Rec.709 輝度変換 + CoV/std/max-min（MiniTias-Evaluation コピー）
- `src/sm_tias_lightsim/evaluation/zones.py` — 正規化楕円距離マップ + 3 ゾーン分類 + ゾーン別統計
- `src/sm_tias_lightsim/evaluation/radial.py` — 20 ビン放射状輝度プロファイル
- `src/sm_tias_lightsim/evaluation/roi.py` — `image_pixel` 型矩形 ROI 抽出（2D/3D 配列対応）
- `src/sm_tias_lightsim/evaluation/oetf.py` — 標準 sRGB OETF（IEC 61966-2-1）+ 露出ソルバ（OETF 後 ROI mean を実測値に対数二分でアンカー）+ 順方向適用．シミュ linear を実測 sRGB ドメインへ変換
- `src/sm_tias_lightsim/evaluation/normalize.py` — linear mean anchor 正規化（`apply_mean_anchor`）．OETF と排他適用，形状指標は厳密不変で mean のみ target_mean に揃う．`configs/eval_baseline_linear.yaml` で有効化
- `src/sm_tias_lightsim/evaluation/visualize.py` — matplotlib 可視化（輝度マップ / ヒストグラム / 放射プロファイル / ゾーンマップ）．MiniTias-Evaluation 互換スタイル（hot cmap，zone_map は luminance 背景 + 境界線）
- `src/sm_tias_lightsim/scene/schema.py` — Pydantic ベース YAML スキーマ + ローダ．SensorConfig は perspective / orthographic 両対応
- `src/sm_tias_lightsim/geometry/loader.py` — STL 読込（trimesh）+ `LoadedMesh` データクラス
- `src/sm_tias_lightsim/geometry/transforms.py` — mm⇄m 単位スケール変換
- `src/sm_tias_lightsim/scene/{lights,materials,sensors}.py` — Mitsuba emitter / BSDF / sensor dict 変換（sensors は orthographic 対応，lights は `area` / `point` / `directional` / `spot` 対応．Step 8-10 で `SpotLight` を追加）
- `scripts/select_white_board.py` — 実測 PNG で白色板境界を OpenCV GUI で選択（Step 8 キャリブ用）
- `scripts/visualize_roi_3d.py` — 評価板 STL に ROI を 3D 投影（PyVista，Step 8 キャリブ用）
- `src/sm_tias_lightsim/scene/builder.py` — SceneConfig → Mitsuba scene dict（PLY 一時ファイル経由）
- `src/sm_tias_lightsim/render/runner.py` — variant 管理 + `mi.render` 実行
- `src/sm_tias_lightsim/render/output.py` — PNG / luminance.npy 出力
- `src/sm_tias_lightsim/cli/render.py` — `sm-render` CLI（YAML → PNG / luminance.npy）
- `src/sm_tias_lightsim/cli/evaluate.py` — `sm-evaluate` CLI（PNG / luminance.npy → metrics.csv + figures/）．`oetf.enabled` 時は ROI 抽出後・指標算出前に sRGB OETF を順方向適用，`normalization.enabled` 時は OETF 前段に linear mean 揃え正規化（OETF と排他）．後方互換、シミュ用設定のみ
- `src/sm_tias_lightsim/visualize/baker.py` — face 中心の照度ベイク．`mode="direct"`（shadow ray + cosine + 距離減衰、直接光のみ、後方互換）/ `mode="path"`（scalar_rgb・完全シーン・コサイン重点 hemisphere MC、多重反射込み per-face、`exclude_mesh_ids` 対応）．`max_depth` 引数で path ベイクの反射回数を render 設定から独立設定（None で render 継承＝後方互換）
- `src/sm_tias_lightsim/visualize/projection.py` — orthographic センサ投影の純関数（評価板メッシュ特定 / `project_luminance_to_vertices` 頂点 bilinear 投影 / `compute_orthographic_uv` テクスチャ UV / `compute_face_camera_mask` 幾何 Z ベース巻き順非依存の評価面選択 / `compute_inward_face_mask` 法線がシーン中心側を向く内向き面判定＝幾何カリング用）．`sensors.py` look_at@scale 規約と整合（SPEC_03「画像↔物理の向き」検証済）
- `src/sm_tias_lightsim/visualize/viewer.py` — PyVista 3D ビューア．既定＝全メッシュ統一ベイク着色（**lit のみ共有 clim**・log/linear・単一カラーバー・`bake_opacity` 半透明・`hide_below` 非表示・`bake_smooth` 平滑化・depth peeling・viridis）＋**`cull_outward`（既定 ON）で外向き ≈0 面を非描画**＝暗殻の濁り/見かけ段差を解消・clim も可視内向き面に密着；`hide_sensor_marker`/`hide_led_markers` でマーカー個別非表示；`luminance_map` 指定時＝評価板 512² テクスチャ投影（E=π·L/ρ で壁と同一 W/m² スケール、内側カメラ向き face のみ、外側ニュートラル、マスク無効時 per-vertex フォールバック）
- `src/sm_tias_lightsim/cli/visualize.py` — `sm-visualize` CLI（YAML → 3D 表示 / screenshot）．`--bake-mode {direct,path}` / `--bake-samples` / `--bake-max-depth`（path ベイクの反射回数、既定 16、render 設定から独立）/ `--bake-cache <npz>`（1回計算→以後即時）/ `--cull-outward|--no-cull-outward`（既定 ON）/ `--opacity` / `--hide-below` / `--bake-smooth` / `--bake-scale {linear,log}` / `--clip-percentile` / `--no-sensor-marker`・`--no-led-markers`・`--no-markers` / `--render <luminance.npy>`（任意・テクスチャ投影）．`--render` 無し＝全面統一ベイク（既定）
- `src/sm_tias_lightsim/runtime/llvm_init.py` — LLVM JIT 初期化ヘルパ．`ensure_drjit_libllvm_path()` で `DRJIT_LIBLLVM_PATH` 未設定時に Windows/POSIX 標準パスを自動探索して `os.environ` 設定．`log_variant_status()` で variant 経路（llvm_/cuda_/scalar_）を INFO 明示，要求 llvm_* で実 scalar_* なら WARNING 追加．`runner.py` / `baker.py` から呼ばれ環境変数未設定時のサイレントクラッシュを防ぐ
- `src/sm_tias_lightsim/evaluation/dng_loader.py` — DNG 読み込みモジュール．MiniTias-Evaluation `src/io/dng_loader.py` を SmTIAS-LightSim にコピーしたもの (オリジナルは MiniTias-Evaluation 側で管理．バグ修正・機能追加はそちらで反映)．主要 API: `load_image_dng(path, demosaic, black_level, output_format)`．`output_format` は `rgb_float32` / `luma_float32` / `rgb_uint8`．linear 系出力 (`rgb_float32` / `luma_float32`) は `output_color=raw` でカラーマトリクス非適用・per-channel 比例性保持．`gamma=(1,1) + no_auto_bright=True + use_camera_wb=False + user_wb=[1,1,1,1]` で linear raw を保つ．依存: `rawpy>=0.21.0`
- `src/sm_tias_lightsim/evaluation/radial.py` — 20 ビン放射状輝度プロファイル．既存 `calc_radial_profile` に加えて MiniTias-Evaluation `src/analysis/spatial.py:calc_radial_min_max_ratio` をマージ．動径 min/max 比 (20 点輪帯平均) は画素単位 max/min よりノイズに対しロバスト．nan ビン除外を移植時に補強 (既存 `calc_radial_profile` は空ビンを nan で返す)
※ ステップ完了時にここを更新すること．

## 必須ルール（コード実装時）

<!-- プロジェクト立ち上げ後，規約整備フェーズで追加する -->

### Git 運用（GUIDE_04 準拠）

- ブランチ名・コミットメッセージの書式は GUIDE_04 に従う
- コミットは `/commit` を使用する（push・PR 作成は `/commit push`）

### エージェントチーム（GUIDE_05 準拠）

- 実装は `/implement <タスク>` で開始する（コーディング → テスト → リファクタリング → ドキュメント更新）
- Phase 1 後に人間が動作確認，Phase 2 でテスト失敗時のみ方針判断
- Phase 2 成功後は Phase 3 → Phase 4 まで自動で進む（Phase 4 で更新がある場合のみ確認）
- テスト・リファクタリングをスキップしない

### 手動確認が必要な作業（自分で完了させないこと）

以下は実装完了後にユーザーへ報告し，確認・実施を依頼すること．

- 外部サービスの設定（コンソール操作，セキュリティルール変更等）
- 実機・ブラウザでの動作確認
- ストアへのアップロード・リリース作業

## ドキュメント

設計・規約に関する情報は docs/ にある．
コードを書く前に関連するファイルを読むこと．

### 01_GUIDE（規約・ルール）

- プロジェクト立ち上げフロー: docs/01_GUIDE/GUIDE_01_プロジェクト立ち上げフロー.md
- ドキュメント作成規約: docs/01_GUIDE/GUIDE_02_ドキュメント作成ガイド.md
- ファイル命名規則: docs/01_GUIDE/GUIDE_03_ファイル命名規則.md
- Git 運用ルール: docs/01_GUIDE/GUIDE_04_Git運用ルール.md
- エージェント運用ルール: docs/01_GUIDE/GUIDE_05_エージェント運用ルール.md
- コーディング規約: docs/01_GUIDE/GUIDE_06_コーディング規約.md
- テスト方針: docs/01_GUIDE/GUIDE_08_テスト方針.md

### 02_ENV（環境）

- 技術スタック: docs/02_ENV/ENV_01_技術スタック.md
- 環境構築手順: docs/02_ENV/ENV_02_環境構築手順.md
- 管理者用環境構築手順: docs/02_ENV/ENV_03_管理者用環境構築手順.md

### 03_PLAN（計画）

- 要件定義書: docs/03_PLAN/PLAN_01_要件定義書.md
- 開発ステップ: docs/03_PLAN/PLAN_02_開発ステップ.md

### 04_SPEC（仕様・設計）

- アーキテクチャ設計: docs/04_SPEC/SPEC_01_アーキテクチャ設計.md
- シーン定義仕様: docs/04_SPEC/SPEC_02_シーン定義仕様.md（シーン YAML + 評価 YAML のスキーマ）
- 基準設計の物理構成: docs/04_SPEC/SPEC_03_基準設計の物理構成.md（評価関連は SPEC_04 に分離済み）
- 評価仕様: docs/04_SPEC/SPEC_04_評価仕様.md（評価パイプライン・ROI・OETF・メトリクス・可視化・キャリブ目標と経過要約）

### 05_TECH（技術設計）

<!-- 必要に応じて実装フェーズで追加する -->

### 06_TEST（テスト）

- キャリブレーション検証履歴: docs/06_TEST/TEST_01_キャリブレーション検証履歴.md（Step 8 イテレーション 8-1〜8-7 のフル記録．仮説／変更／数値／解釈／学びを時系列で）
- シミュレーション実行記録: docs/06_TEST/TEST_02_シミュレーション実行記録.md（output/ 各サブディレクトリの索引．Step との対応・シーン/評価 config・主要指標・再現コマンド・削除推奨）
- 輝度マップ形状追跡: docs/06_TEST/TEST_03_輝度マップ形状追跡.md（数値とは独立に「形」を実機に近づける観点．比較パネル画像と LSC モデル化の構造的意義）
