MiniTIAS(スマートフォン舌画像撮影装置)の照明均一性を実機制作前に検討するための光散乱シミュレーションツール. LED 配置・ディフューザー形状を仮想的に変えながら,MiniTIAS-Evaluation と同じ指標(CoV/3 ゾーン分析等)で均一性を定量評価できるようにする.
最新: フェーズ 7(実装)— Step 8 基準設計キャリブレーションの Step 8-14(物理モデル精緻化) 進行中.面光源スケール軸バグを発見・修正(lights.py が LED の高さを潰れた Z 軸に入れ縦 Y を無補正→全 LED が幅3mm×高さ2mの巨大ストリップ化).実機単灯実測との突合で 下灯 2.1× がこのバグのアーティファクトと判明(バグは Mitsuba bbox() で 2.8×2000mm と独立検証済,3D 確認ツール scripts/show_led_geometry.py 追加),修正後は 3 灯均等・下灯最暗で実機一致.ただし合成 CoV は 0.1815→0.1641 の小改善にとどまり,残る不一致は各単灯フットプリントの形(拡散不足)(シミュ peak/mean≈1.7 vs 実機≈1.2)=形の一致を最優先に方針転換(TEST_08).実機にディフューザー無しを確認(むき出し LED+白筐体),実機の平らさは筐体多重反射由来.bottom 単灯 spp=1024 で max_depth 分解(実験1)と反射率スイープ(実験2)を実施→いずれも形を平らにできず(実機 1.22 に対し d16 で 1.65・R0.98 で 1.44 止まり,NCC 改善せず)=混ぜ具合は本筋でなく,形の残差は B1 筐体幾何(箱の閉じ漏れ)に絞り込み.さらに修正後シミュは 3 灯ほぼ同形(NCC≈0.92)で実機の相補性(各灯が別方向を照らす)を再現できず=形が筐体で決まり LED 位置の効きが弱い(板が間接光のみ+Lambertian 拡散壁のため光源形状が洗い流される).次は幾何の漏れ点検(実験3)(TEST_09).A1 非 Lambertian / A8 反射率 / A9 max_depth はクリア(数値改善のみ or 逆効果,ただし旧結論はバグ込みのため要再検証).詳細な経緯・設計判断・失敗パターンは docs/PROGRESS.md.
実装済みモジュール:
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 両対応.materials は DiffuseMaterial / RoughConductorBSDFConfig (alpha + distribution=ggx/beckmann,material="none" 固定で完全反射体) / BlendBSDFConfig (weight + components×2,再帰ネスト可能,forward reference + model_rebuild()) を Union として並列サポート.後方互換維持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 を追加,Step 8-14 β で materials.py に _build_bsdf_dict 再帰ヘルパを追加して blendbsdf ネスト対応)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 フォールバック).発表スライド向け表示機能(Step 8-14 期に追加): style("default"/"slide".slide=白背景・座標軸/bounds 非表示・アンチエイリアス・黒文字スカラーバー _build_scalar_bar_args・センサマーカー自動非表示.未知値は warning で default フォールバック)/ cmap(None で style 既定を解決:default→viridis・slide→hot=照明均一性評価と同一.未知名は warning で style 既定にフォールバック,_make_irradiance_texture(cmap_name=) も同一 cmap)/ subdivide_max_edge(m 単位.ベイク前に三角形を均一分割→巨大三角形のブロック感解消)/ bake_denoise(denoise_face_scalars_median 頂点経由メディアン近似でMCノイズ/firefly除去,エッジ保存.log変換後・smooth前に適用,_get_triangle_faces で PolyData/UnstructuredGrid 両対応)/ bake_smooth_radius(m 単位.smooth_face_scalars_radius ボクセル splat/gather 物理半径ガウス平滑化=メモリ有界・純NumPy・sigma=radius/2.denoise後・bake_smooth前に適用,三角形スケールのチェッカーノイズ除去)/ backface_cull(VTK 背面カリング culling="back",opacity=1.0 併用で手前壁が隠れ混色なし)src/sm_tias_lightsim/geometry/subdivide.py — 三角形メッシュ均一分割の純関数(新規).subdivide_mesh_to_max_edge(vertices, faces, max_edge)=trimesh.remesh.subdivide_to_size で「最大辺長 ≤ max_edge」まで決定論的に三角形分割(同一入力→同一出力,baker と viewer が独立呼び出しでも face 配列一致).単位は呼び出し側座標系に従う(m 系で呼べば m).STL の三角形サイズが極端に不均一(曲面 ~1mm² vs 平面壁 最大 4794mm²)でも均一な空間解像度の per-face ベイクを可能にする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回計算→以後即時.--bake-subdivide 設定値も npz に記録し不一致なら自動再ベイク)/ --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>(任意・テクスチャ投影).発表スライド向け(Step 8-14 期に追加): --style {default,slide} / --cmap NAME(既定: style に応じ viridis/hot)/ --bake-subdivide MM(三角形を最大辺長 MM mm 以下に均一分割)/ --bake-denoise N(メディアンデノイズ反復)/ --bake-smooth-radius MM(物理半径 MM mm のガウス平滑化)/ --backface-cull(背面カリング).mm 引数は内部で ×0.001 して m 系で show_scene/baker へ.--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.0src/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 で返す)src/sm_tias_lightsim/evaluation/shape_metrics.py — 輝度分布「形」評価指標モジュール(新規).現状 CoV/勾配/C/P/動径 min/max は不均一性の絶対量しか測れず,Y 軸単調勾配と中央ピーク楕円を構造的に区別できない問題を解決する 5 つの純関数: calc_intensity_centroid(輝度重心,5 値)/ calc_angular_radial_decomposition(極座標分解,angular_ratio が 0=同心円〜1=方向依存,3 値)/ calc_ssim(構造的類似度,scikit-image 依存,shape_reference 指定時のみ)/ calc_ncc(正規化相関係数,絶対輝度不変)/ calc_intensity_pca(weighted PCA で主軸角度と eccentricity,4 値).mask 省略可能,完全均一画像で angular_ratio/NCC は NaN を返す.MetricsConfig.shape_metrics=true / shape_reference フィールドで有効化,後方互換保持.依存追加: scikit-image>=0.21.0.詳細: TECH_11 形状指標の見直し
※ 本欄は最新ステップ 1 行のみ上書き更新.詳細な進捗履歴(動機・設計判断・失敗パターン)は docs/PROGRESS.md に追記する.運用ルールは .claude/rules/progress-log.md を参照(該当ファイル編集時に自動ロードされる)..claude/rules/git-conventions.md に従う(常時ロードされる)/commit を使用する(push・PR 作成は /commit push)/commit はユーザーが明示的に指示した時のみ実行する.Claude が自発的に /commit や git commit を呼んではならない(/implement 完了後も,案内するだけで自分ではコミットしない./commit skill は disable-model-invocation によりユーザー起動限定として強制されている)
main への操作はしない(取り込みは人間が /commit push 等で行う)
/auto-refactor(リファクタ/ドキュメント整理ループ)→ refactor/ 専用ブランチ/auto-audit(バグ/脆弱性の巡回監査ループ)→ fix/ 専用ブランチ/implement <タスク> で開始する(コーディング → テスト → リファクタリング → ドキュメント更新)docs/02_ENV/ENV_04_開発コマンド.md にまとめる.存在する場合は実行前に必ず参照し,推測でコマンドを試さない/implement の Phase 4 でも見直される)以下は実装完了後にユーザーへ報告し,確認・実施を依頼すること.
設計・規約に関する情報は docs/ にある. コードを書く前に関連するファイルを読むこと.
.claude/rules/(coding-style / testing / project-structure / error-handling / git-conventions / markdown-style / docs-naming / progress-log)に path-scoped rule として定義されている(git-conventions は常時,他は該当ファイル編集時に自動ロード)