diff --git "a/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" "b/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" index c0b0a69..18a2a5d 100644 --- "a/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" +++ "b/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" @@ -91,7 +91,7 @@ | `output/cube_size_sweep/_anchor_check_mitsuba371/L120/` | TEST_16 | `configs/_tmp_cube_size/scene_board_baffle_L120.yaml`(本体スイープと同一.mitsuba **3.7.1** でレンダ) | 同上 | 3.8.0 版と比較して構造 CoV 一致(0.0379)・輪帯 min/max 差 +0.0002・輪帯プロファイル最大差 1.17σ | mitsuba 3.8.0→3.7.1 固定(SAC が `IlmThread-mitsuba.dll` をブロック)の等価性検証アンカー.バージョン混在の妥当性の根拠 | | `output/offaxis_led_sweep/` (10 ディレクトリ) | TEST_17 | `configs/_tmp_offaxis/scene_offaxis_*.yaml`(`scripts/sweep_offaxis_led.py` が生成.LED を**深さ方向軸の中点の高さ・+X 側の壁面**に置き板中心 (0,0,-4.5) へ向けた board_baffle 構成.球 similar_radial r ∈ {88, 100, 135, 170, 250} + 立方体 L ∈ {120, 160, 200, 280, 360}.バッフルは視線上 10mm・数値サイジング.材質・spp=1024・d=16 据え置き・mitsuba 3.7.1) | `configs/eval_baseline_dng_target_shape.yaml` | m=1 符号付き a1 が全条件で負(LED 側が暗い)= -1.6〜-7.2%.サイズとともに約 4 割まで減衰.位置ずれの Δ構造CoV は球 ±0.006 以内・立方体 +0.010〜+0.033 — [TEST_17](TEST_17_オフ軸LED配置の影響とサイズ依存.md) 参照 | **オフ軸頑健性は球 > 立方体(軸上と逆転)**を実証.遮蔽は全 10 条件 55,473 本 100%(傾き追従の LED サンプルに一般化済み) | | `output/offaxis_led_sweep/{summary.csv,offaxis_comparison.png}`・`_placement_check/cutaway_*.png` | TEST_17 | — | — | 条件別集約 CSV/解析図(輝度マップ 2 行 + a1・重心・構造 CoV の内面積依存を軸上と重ね描き)/レンダ前 3D 確認の半割り断面 10 枚 | `scripts/build_offaxis_comparison.py`・`show_scene_cutaway.py` の出力.レンダ前 3D 確認(CLAUDE.md 必須ルール)の記録を兼ねる | -| `output/led_placement_sweep/` (255 ディレクトリ) | TEST_18 | `configs/_tmp_led_placement/scene_*.yaml`(`scripts/sweep_led_placement.py` が生成.同内面積ペア 球 r ∈ {100,135,170,250} ↔ 立方体 L ∈ {141,187,234,340} で,LED をキャビティ中心から見た極角 θ=0〜120°(13 段階)に置く位置スイープ・θ=60/90/120° の向き 3 通り(板向き+バッフル/壁法線向き+バッフル/真下向き)・θ=90° の輪に N=1〜4 灯(総光束保存)・seed 違いの再レンダ,追加実験の方位角 φ=15〜40°(立方体)と真下向き N=2/4/8 灯.材質・spp=1024・d=16 据え置き.Newton cuda_ad_rgb・mitsuba 3.7.1・`--workers 2` で 1 条件 5〜6 秒) | `configs/eval_baseline_dng_target_shape.yaml` | 配置依存の幅(θ 全域の構造 CoV max−min)は球 0.015〜0.023・立方体 0.025〜0.071.球は θ≈30° が軸上より均一(r=170: 0.0193→0.0057).対向 2 灯で構造 CoV 0.005〜0.010 と形状差が消える.真下向きはバッフル無しで板向きと同等 — [TEST_18](TEST_18_照明配置依存性の球と立方体の比較.md) 参照 | **配置依存は球が立方体の 1/2〜1/3**(仮説成立).図なし評価(`--no-figures`)なので各条件に figures/ は無い.`row.json` が条件ごとの集約行(並列・再開用) | +| `output/led_placement_sweep/` (255 ディレクトリ) | TEST_18 | `configs/_tmp_led_placement/scene_*.yaml`(`scripts/sweep_led_placement.py` が生成.同内面積ペア 球 φ ∈ {200,270,340,500}(r ∈ {100,135,170,250}) ↔ 立方体 L ∈ {141,187,234,340} で,LED をキャビティ中心から見た極角 θ=0〜120°(13 段階)に置く位置スイープ・θ=60/90/120° の向き 3 通り(板向き+バッフル/壁法線向き+バッフル/真下向き)・θ=90° の輪に N=1〜4 灯(総光束保存)・seed 違いの再レンダ,追加実験の方位角 φ=15〜40°(立方体)と真下向き N=2/4/8 灯.材質・spp=1024・d=16 据え置き.Newton cuda_ad_rgb・mitsuba 3.7.1・`--workers 2` で 1 条件 5〜6 秒) | `configs/eval_baseline_dng_target_shape.yaml` | 配置依存の幅(θ 全域の構造 CoV max−min)は球 0.015〜0.023・立方体 0.025〜0.071.球は θ≈30° が軸上より均一(φ340: 0.0193→0.0057).対向 2 灯で構造 CoV 0.005〜0.010 と形状差が消える.真下向きはバッフル無しで板向きと同等 — [TEST_18](TEST_18_照明配置依存性の球と立方体の比較.md) 参照 | **配置依存は球が立方体の 1/2〜1/3**(仮説成立).図なし評価(`--no-figures`)なので各条件に figures/ は無い.`row.json` が条件ごとの集約行(並列・再開用) | | `output/led_placement_sweep_rho081/` (60 ディレクトリ + 解析出力) | TEST_18 | `configs/_tmp_led_placement_rho081/scene_*.yaml`(`sweep_led_placement.py --material calibrated --key-subset` が生成.内壁を TEST_14 の校正材質 純 diffuse ρ=0.81 に置き換えた主要 60 条件=位置スイープ ペア 1・3,多灯 N=2/4・真下向き ペア 3) | 同上 | 配置依存の幅 球 0.030 vs 立方体 0.077〜0.098.軸上は両形状とも大きく改善(旧材質の光沢が作るリングが消える)— [TEST_18](TEST_18_照明配置依存性の球と立方体の比較.md) 結果 7 | 主結論が材質に依らないことの確認.解析は `build_led_placement_comparison.py --material calibrated` | | `output/led_placement_sweep/{summary.csv,analysis.csv,position_summary.csv,position_sensitivity.png,position_maps.png,direction_comparison.png,count_comparison.png,azimuth_comparison.png,ring_comparison.png,analysis_report.txt}`・`_placement_check/cutaway_*.png` | TEST_18 | — | — | 条件別集約 CSV/方位フーリエ m=1〜4・構造 CoV・重心の解析 CSV/位置・向き・灯数・方位角・真下向き多灯の解析図 6 枚/レンダ前 3D 確認の半割り断面 23 枚 | `scripts/build_led_placement_comparison.py`・`show_scene_cutaway.py` の出力.レンダ前 3D 確認(CLAUDE.md 必須ルール)の記録を兼ねる | | `output/cube_size_sweep/board_baffle/{summary.csv,cube_vs_sphere.png,fourfold_component.png}`・`output/cube_size_sweep/_placement_check/cutaway_L*.png` | TEST_16 | — | — | 条件別集約 CSV/球との比較図(輝度マップ 5 枚 + 輪帯プロファイル + 内面積軸の指標カーブ + 直接ペア 3 組)/m=4(cos 4φ)成分の定量図/レンダ前 3D 確認の半割り断面 5 枚 | `scripts/build_cube_sphere_comparison.py`・`analyze_fourfold_component.py`・`show_scene_cutaway.py` の出力.m=4 は全条件 \|a4\| ≤ 0.26%(系統誤差床 ~0.1%)=四隅の写り込みは実質ゼロ.レンダ前 3D 確認(CLAUDE.md 必須ルール)の記録を兼ねる | diff --git "a/docs/06_TEST/TEST_18_\347\205\247\346\230\216\351\205\215\347\275\256\344\276\235\345\255\230\346\200\247\343\201\256\347\220\203\343\201\250\347\253\213\346\226\271\344\275\223\343\201\256\346\257\224\350\274\203.md" "b/docs/06_TEST/TEST_18_\347\205\247\346\230\216\351\205\215\347\275\256\344\276\235\345\255\230\346\200\247\343\201\256\347\220\203\343\201\250\347\253\213\346\226\271\344\275\223\343\201\256\346\257\224\350\274\203.md" index 4fadaec..4831032 100644 --- "a/docs/06_TEST/TEST_18_\347\205\247\346\230\216\351\205\215\347\275\256\344\276\235\345\255\230\346\200\247\343\201\256\347\220\203\343\201\250\347\253\213\346\226\271\344\275\223\343\201\256\346\257\224\350\274\203.md" +++ "b/docs/06_TEST/TEST_18_\347\205\247\346\230\216\351\205\215\347\275\256\344\276\235\345\255\230\346\200\247\343\201\256\347\220\203\343\201\250\347\253\213\346\226\271\344\275\223\343\201\256\346\257\224\350\274\203.md" @@ -32,12 +32,15 @@ ### 同内面積ペア -| ペア | 球 r [mm] | 立方体 L [mm] | 内面積 [mm²] | +| ペア | 球 内径 φ [mm] | 立方体 内寸 L [mm] | 内面積 [mm²] | | --- | --- | --- | --- | -| 1 | 100 | 141 | 120,607 / 119,880 | -| 2 | 135 | 187 | 211,286 / 210,408 | -| 3 | 170 | 234 | 328,508 / 329,130 | -| 4 | 250 | 340 | 696,005 / 694,194 | +| 1 | 200 | 141 | 120,607 / 119,880 | +| 2 | 270 | 187 | 211,286 / 210,408 | +| 3 | 340 | 234 | 328,508 / 329,130 | +| 4 | 500 | 340 | 696,005 / 694,194 | + +球のサイズは内径 φ で表す(TEST_15/17 の半径 r との対応: φ200=r100,φ270=r135,φ340=r170, +φ500=r250.条件名・出力ディレクトリ名は内部識別子として `sphere_r100` 等の半径表記のまま). ### LED 位置の定義(両形状共通) @@ -84,10 +87,10 @@ | 形状・サイズ | 構造 CoV 軸上 | θ 全域の平均 | 最大(最悪 θ) | 幅 max−min | max\|a1\| | min 軸上 | min 最良(θ) | min 最悪(θ) | min の幅 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 球 r=100 | 0.0311 | 0.0244 | 0.0311(0°) | 0.0153 | 4.1% | 0.866 | 0.922(40°) | 0.866(0°) | 0.056 | -| 球 r=135 | 0.0231 | 0.0199 | 0.0321(110°) | 0.0229 | 4.1% | 0.909 | 0.958(30°) | 0.886(110°) | 0.072 | -| 球 r=170 | 0.0193 | 0.0164 | 0.0289(120°) | 0.0232 | 3.8% | 0.931 | 0.978(30°) | 0.898(120°) | 0.080 | -| 球 r=250 | 0.0145 | 0.0121 | 0.0244(120°) | 0.0202 | 3.1% | 0.951 | 0.980(20°) | 0.905(120°) | 0.075 | +| 球 φ200 | 0.0311 | 0.0244 | 0.0311(0°) | 0.0153 | 4.1% | 0.866 | 0.922(40°) | 0.866(0°) | 0.056 | +| 球 φ270 | 0.0231 | 0.0199 | 0.0321(110°) | 0.0229 | 4.1% | 0.909 | 0.958(30°) | 0.886(110°) | 0.072 | +| 球 φ340 | 0.0193 | 0.0164 | 0.0289(120°) | 0.0232 | 3.8% | 0.931 | 0.978(30°) | 0.898(120°) | 0.080 | +| 球 φ500 | 0.0145 | 0.0121 | 0.0244(120°) | 0.0202 | 3.1% | 0.951 | 0.980(20°) | 0.905(120°) | 0.075 | | 立方体 L=141 | 0.0280 | 0.0513 | 0.0951(120°) | 0.0671 | 9.6% | 0.887 | 0.887(0°) | 0.646(120°) | 0.240 | | 立方体 L=187 | 0.0178 | 0.0403 | 0.0888(120°) | 0.0710 | 11.2% | 0.932 | 0.932(0°) | 0.732(120°) | 0.200 | | 立方体 L=234 | 0.0139 | 0.0293 | 0.0652(120°) | 0.0514 | 8.3% | 0.948 | 0.948(0°) | 0.790(120°) | 0.158 | @@ -101,8 +104,8 @@ 構造 CoV も全ペアで立方体が悪い(1.5〜2.1 倍) - **立方体は θ とともに単調に悪化**し,板の直下(θ=120°)で軸上の 3.4〜5.0 倍.底面上 (θ≤40°)でも a1 は既に −2〜−6% ある(平らな床に置いた LED は近い側壁を強く照らす) -- **球は(旧材質では)軸上が最良ではない**.θ=20〜40° で構造 CoV が最小(r=170: 0.0193 → - 0.0057,r=250: 0.0145 → 0.0043)になり,軸上の同心円状のリング構造(TEST_15 のドーム)が +- **球は(旧材質では)軸上が最良ではない**.θ=20〜40° で構造 CoV が最小(φ340: 0.0193 → + 0.0057,φ500: 0.0145 → 0.0043)になり,軸上の同心円状のリング構造(TEST_15 のドーム)が 崩れて平坦になる.θ≥90° で軸上と同程度に戻り,最悪でも軸上の 1.0〜1.7 倍. **ただしこのリング構造は旧材質の光沢成分が作るもので,校正材質では消える**(結果 7) - 立方体の軸上の優位(TEST_16)は確認できる(ペア 2〜4 で球の 0.66〜0.77 倍)が, @@ -116,16 +119,16 @@ `direction_comparison.png`.θ=60/90/120° × 3 向き × 4 ペア × 2 形状. - **真下向き(−Z・バッフル無し)は板中心向き+バッフルと同等**(構造 CoV の比 0.6〜1.3. - 球の大サイズではむしろ良く,r=250・θ=120° で 0.0244 → 0.0138).生 mean も 5〜30% + 球の大サイズではむしろ良く,φ500・θ=120° で 0.0244 → 0.0138).生 mean も 5〜30% 明るい(バッフルが吸う分が無い).**LED を板と反対側へ向けるだけで,バッフル無しで 板向きバッフル構成と同じ均一性が得られる** - **壁法線向き(キャビティ中心向き)は最悪**.構造 CoV は板向きの 2〜5 倍(立方体 L=141 で 0.19〜0.23).反対側の壁にできる一次照射キャップが板から正面に見えるうえ,それを 遮るバッフルが大きく(半径がキャビティ寸法の 5〜44%),キャビティ内に影を作る. - 球 r=100・θ=120° の壁法線向きはバッフル半径が r の 59% になり板への光がほぼ消えた + 球 φ200・θ=120° の壁法線向きはバッフル半径が球の半径の 59% になり板への光がほぼ消えた (生 mean 0.000)ため無効条件として除外する - 向きの影響は形状差より大きい: 同じ位置でも向きで 2〜5 倍変わる -- min で見ても同じ: ペア 3(r=170 / L=234)の θ=90° で板向き 0.933 / 0.897,真下向き 0.922 / 0.869, +- min で見ても同じ: ペア 3(φ340 / L=234)の θ=90° で板向き 0.933 / 0.897,真下向き 0.922 / 0.869, 壁法線向き 0.856 / 0.721.立方体 L=141 の壁法線向きは 0.47〜0.52 まで落ちる ## 結果 3 — 個数: 対向 2 灯以上で形状差は消える (Count) @@ -134,9 +137,9 @@ | 形状・サイズ | N=1 | N=2 | N=3 | N=4 | 参考: 軸上 1 灯 | | --- | --- | --- | --- | --- | --- | -| 球 r=100 | 0.0308 | 0.0084 | 0.0057 | 0.0059 | 0.0311 | -| 球 r=170 | 0.0202 | 0.0053 | 0.0044 | 0.0043 | 0.0193 | -| 球 r=250 | 0.0136 | 0.0054 | 0.0052 | 0.0054 | 0.0145 | +| 球 φ200 | 0.0308 | 0.0084 | 0.0057 | 0.0059 | 0.0311 | +| 球 φ340 | 0.0202 | 0.0053 | 0.0044 | 0.0043 | 0.0193 | +| 球 φ500 | 0.0136 | 0.0054 | 0.0052 | 0.0054 | 0.0145 | | 立方体 L=141 | 0.0554 | 0.0098 | 0.0208 | 0.0089 | 0.0280 | | 立方体 L=234 | 0.0323 | 0.0049 | 0.0089 | 0.0047 | 0.0139 | | 立方体 L=340 | 0.0208 | 0.0067 | 0.0062 | 0.0064 | 0.0096 | @@ -145,9 +148,9 @@ | 形状・サイズ | N=1 | N=2 | N=3 | N=4 | 参考: 軸上 1 灯 | | --- | --- | --- | --- | --- | --- | -| 球 r=100 | 0.884 | 0.961 | 0.959 | 0.967 | 0.866 | -| 球 r=170 | 0.933 | 0.958 | 0.976 | 0.988 | 0.931 | -| 球 r=250 | 0.942 | 0.975 | 0.976 | 0.979 | 0.951 | +| 球 φ200 | 0.884 | 0.961 | 0.959 | 0.967 | 0.866 | +| 球 φ340 | 0.933 | 0.958 | 0.976 | 0.988 | 0.931 | +| 球 φ500 | 0.942 | 0.975 | 0.976 | 0.979 | 0.951 | | 立方体 L=141 | 0.822 | 0.959 | 0.926 | 0.969 | 0.887 | | 立方体 L=234 | 0.897 | 0.978 | 0.962 | 0.974 | 0.948 | | 立方体 L=340 | 0.905 | 0.982 | 0.943 | 0.970 | 0.964 | @@ -201,9 +204,9 @@ | 構造 CoV | N=1 | N=2 | N=4 | N=8 | 板向き N=8(バッフル付き) | 単灯軸上 | | --- | --- | --- | --- | --- | --- | --- | -| 球 r=100 | 0.0268 | 0.0118 | 0.0100 | 0.0093 | 0.0052 | 0.0311 | -| 球 r=170 | 0.0183 | 0.0101 | 0.0078 | 0.0072 | 0.0045 | 0.0193 | -| 球 r=250 | 0.0145 | 0.0118 | 0.0110 | 0.0092 | 0.0050 | 0.0145 | +| 球 φ200 | 0.0268 | 0.0118 | 0.0100 | 0.0093 | 0.0052 | 0.0311 | +| 球 φ340 | 0.0183 | 0.0101 | 0.0078 | 0.0072 | 0.0045 | 0.0193 | +| 球 φ500 | 0.0145 | 0.0118 | 0.0110 | 0.0092 | 0.0050 | 0.0145 | | 立方体 L=141 | 0.0494 | 0.0239 | 0.0220 | 0.0186 | 0.0076 | 0.0280 | | 立方体 L=234 | 0.0332 | 0.0106 | 0.0095 | 0.0075 | 0.0053 | 0.0139 | | 立方体 L=340 | 0.0242 | 0.0109 | 0.0098 | 0.0094 | 0.0066 | 0.0096 | @@ -212,9 +215,9 @@ | min | N=1 | N=2 | N=4 | N=8 | 板向き N=8(バッフル付き) | | --- | --- | --- | --- | --- | --- | -| 球 r=100 | 0.889 | 0.942 | 0.956 | 0.950 | 0.981 | -| 球 r=170 | 0.922 | 0.958 | 0.979 | 0.970 | 0.978 | -| 球 r=250 | 0.902 | 0.928 | 0.929 | 0.956 | 0.983 | +| 球 φ200 | 0.889 | 0.942 | 0.956 | 0.950 | 0.981 | +| 球 φ340 | 0.922 | 0.958 | 0.979 | 0.970 | 0.978 | +| 球 φ500 | 0.902 | 0.928 | 0.929 | 0.956 | 0.983 | | 立方体 L=141 | 0.821 | 0.912 | 0.910 | 0.915 | 0.972 | | 立方体 L=234 | 0.869 | 0.957 | 0.954 | 0.973 | 0.973 | | 立方体 L=340 | 0.900 | 0.941 | 0.945 | 0.953 | 0.977 | @@ -237,8 +240,8 @@ | 位置スイープ(θ 全域) | 旧材質 → 校正材質 | | --- | --- | -| 球 r=100: 軸上 / 平均 / 幅 / max\|a1\| | 0.0311 / 0.0244 / 0.0153 / 4.1% → **0.0117** / 0.0267 / 0.0296 / 5.7% | -| 球 r=170 | 0.0193 / 0.0164 / 0.0232 / 3.8% → **0.0039** / 0.0172 / 0.0298 / 4.5% | +| 球 φ200: 軸上 / 平均 / 幅 / max\|a1\| | 0.0311 / 0.0244 / 0.0153 / 4.1% → **0.0117** / 0.0267 / 0.0296 / 5.7% | +| 球 φ340 | 0.0193 / 0.0164 / 0.0232 / 3.8% → **0.0039** / 0.0172 / 0.0298 / 4.5% | | 立方体 L=141 | 0.0280 / 0.0513 / 0.0671 / 9.6% → 0.0199 / 0.0522 / 0.0975 / 11.3% | | 立方体 L=234 | 0.0139 / 0.0293 / 0.0514 / 8.3% → **0.0056** / 0.0294 / 0.0773 / 10.8% | @@ -246,8 +249,8 @@ | 位置スイープ | 旧材質 → 校正材質 | | --- | --- | -| 球 r=100 | 0.866 / 0.907 / 0.884 / 0.907 / 0.056 → **0.940** / 0.923 / 0.864 / 0.866 / 0.085 | -| 球 r=170 | 0.931 / 0.978 / 0.933 / 0.898 / 0.080 → **0.987** / 0.968 / 0.913 / 0.884 / 0.103 | +| 球 φ200 | 0.866 / 0.907 / 0.884 / 0.907 / 0.056 → **0.940** / 0.923 / 0.864 / 0.866 / 0.085 | +| 球 φ340 | 0.931 / 0.978 / 0.933 / 0.898 / 0.080 → **0.987** / 0.968 / 0.913 / 0.884 / 0.103 | | 立方体 L=141 | 0.887 / 0.849 / 0.822 / 0.646 / 0.240 → 0.913 / 0.862 / 0.797 / 0.593 / 0.320 | | 立方体 L=234 | 0.948 / 0.925 / 0.897 / 0.790 / 0.158 → **0.980** / 0.952 / 0.866 / 0.751 / 0.230 | @@ -257,10 +260,10 @@ - **配置依存の幅は球 0.030 vs 立方体 0.077〜0.098(2.6〜3.3 倍),max\|a1\| は 4.5〜5.7% vs 10.8〜11.3%(2〜2.4 倍)で,球の優位はむしろ広がる**(ρ が下がり多重反射の混合が弱まる分, 立方体の劣化が大きい) -- **軸上の構造 CoV は両形状で大きく下がる**(球 r=170: 0.0193 → 0.0039,立方体 L=234: +- **軸上の構造 CoV は両形状で大きく下がる**(球 φ340: 0.0193 → 0.0039,立方体 L=234: 0.0139 → 0.0056).旧材質の軸上にあったリング構造は光沢 5% の roughconductor 成分が作って いたもので,純 diffuse では消える.その結果,**校正材質では両形状とも軸上が最良**になり, - 球の「θ≈30° が最良」は消える(r=170: θ=0° 0.0039 → 30° 0.0075 → 90° 0.0250). + 球の「θ≈30° が最良」は消える(φ340: θ=0° 0.0039 → 30° 0.0075 → 90° 0.0250). オフ軸の悪化は球のほうが緩やか(θ=90° で軸上の 6 倍 vs 立方体 7 倍,絶対値で 0.025 vs 0.039) - **多灯は材質に依らない**: 対向 2 灯・4 灯(板向き)は球 0.0057/0.0039,立方体 0.0055/0.0053, 真下向き 4 灯は球 0.0079・立方体 0.0116 と旧材質と同じ水準 diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 05b9f62..848bef0 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -101,4 +101,4 @@ - **スイープの高速化 — レンダ/評価の関数化・プロセス内実行・cuda 遮蔽検証・2 並列 (2026-09-14)**: ユーザー指示「効率化を先に」を受け,`scripts/profile_sweep_step.py` で 1 条件の内訳を実測してから手を入れた.**計測結果**: GPU のレンダ本体(spp=1024・512²)が 4.4〜5.2 秒で床.その上に `uv run sm-render`/`sm-evaluate` の起動・import・YAML・PLY 書き出しで約 2.5 秒,図の描画で約 2 秒,さらに遮蔽検証を YAML の llvm で回していたため球で約 25 秒(頂点 21 万個のメッシュを CPU で読み直す)が乗り,球 1 条件 40 秒・立方体 13 秒だった.**対策**: ① `sm-evaluate`/`sm-render` の本体を `evaluation/pipeline.py:evaluate_image`・`render/pipeline.py:render_yaml` に関数化し CLI は引数パースと例外変換だけに(CLI 挙動は不変)/ ② `--no-figures`(`save_figures=False`)/ ③ `runner.ensure_variant` を切り出し,遮蔽検証の前に cuda を確定(25 秒 → 0.5 秒)/ ④ スイープはサブプロセスをやめプロセス内で呼ぶ / ⑤ `--workers N`(spawn のプロセスプール).**実測**: 立方体 13 → 5.5 秒,球 40 → 約 6 秒.`--workers` は GPU 律速のため 1→5.5・2→5.0・3→4.5〜5.8 秒でほぼ変わらず,**2 を推奨**(CPU 側処理を隠す分だけ).残り 75 条件が 8 分で終わった.**発見**: 同一 seed の再レンダは集計指標が 4 桁まで一致し(画素はノイズ程度に変わるが集計で消える)ノイズフロアにならない → `RenderConfig.seed` を追加し `mi.render` に渡す(再現性条件は rep ごとに seed を変えた YAML).`/implement` の 4 フェーズ(coder → tester 101 件追加 → refactorer → docs)を,ユーザー就寝中の指示に基づき Phase 1 の動作確認をサーバ実走で代行して完走.GPU は 0 番のみ使用(ユーザー指示). -- **TEST_18 照明配置依存性の球と立方体の比較 — 配置依存は球が立方体の 1/2〜1/3 (2026-09-14)**: ユーザーの仮説「積分球が使われる理由は照明配置への依存が小さいから」を,同内面積 4 ペア(球 r=100/135/170/250 ↔ 立方体 L=141/187/234/340)で **LED の位置(キャビティ中心から見た極角 θ=0〜120° を 13 段階)・向き(板向き+バッフル/壁法線向き+バッフル/真下向き)・個数(θ=90° の輪に N=1〜4)・再現性(seed 違い)** の 198 条件で検証した(Newton cuda・1 条件 5〜6 秒).**結果 ①**: θ 全域での構造 CoV の幅は球 0.015〜0.023・立方体 0.025〜0.071(1.2〜3.1 倍),max\|a1\| は 3〜4% vs 4.5〜11%.立方体は θ とともに単調に悪化し板の直下で軸上の 3.4〜5 倍.**球は θ≈30° が軸上より均一**(r=170: 0.0193 → 0.0057.軸上のリング構造が崩れる)で「どこに置いてもそこそこ」.立方体の優位は軸上の 1 点だけ.**結果 ②**: 真下向き(板が背後=バッフル無し)は板向き+バッフルと同等で 5〜30% 明るい.壁法線向き(キャビティ中心向き)は最悪(2〜5 倍).**結果 ③**: 対向 2 灯で m=1 は ≤0.3% に消え構造 CoV は 0.005〜0.010=単灯軸上より均一で形状差が消える.立方体は N=3 で崩れる(3 回対称が 4 回対称の壁と噛み合わない).**ノイズフロア**: 構造 CoV ±0.0007・a1 ±0.08%.設計への含意は「単灯なら球,多灯にできるなら側壁の対向 2〜4 灯・真下向き・バッフル無しで立方体でも球と同等」.**方法論**: 極角 θ を両形状共通のパラメータにし,立方体の稜(45°)は外す.板の近くのバッフルは外殻の貫通を許容し食い込み量を記録(壁法線向きは半径がキャビティ寸法の 0.6 を超えたら無効).解析は TEST_16/17 の方位フーリエ(m=1〜4)+構造 CoV+重心.**追加実験(同日夜)**: ① 方位角: 立方体は面の中央が最良で稜へ寄せるほど構造 CoV が 1.3〜1.75 倍に悪化(球は方位に依らない)/ ② 真下向き多灯(バッフル無し): 2 灯以上で非対称は消え単灯軸上より均一だが,板向き+バッフルの多灯には 1.5〜2.5 倍劣り N を増やしても頭打ち(一次照射が壁の下半分に集中し動径構造が残る).③ 校正材質(純 diffuse ρ=0.81)で主要 60 条件を引き直し: 配置依存の幅は球 0.030 vs 立方体 0.077〜0.098 と結論は不変(むしろ差が広がる).ただし旧材質の光沢 5% が作っていた軸上のリング構造が消え,**校正材質では両形状とも軸上が最良**(「球は θ≈30° が最良」は旧材質の産物).全 255 + 60 条件(TEST_18 結果 5〜7).**失敗パターン**: spawn のワーカーには主プロセスで切り替えた出力ディレクトリ(材質)が伝わらず,旧材質の row.json を再利用して 60 条件が空振りした → 材質を run_job の引数で渡す. +- **TEST_18 照明配置依存性の球と立方体の比較 — 配置依存は球が立方体の 1/2〜1/3 (2026-09-14)**: ユーザーの仮説「積分球が使われる理由は照明配置への依存が小さいから」を,同内面積 4 ペア(球 φ200/270/340/500(r=100/135/170/250)↔ 立方体 L=141/187/234/340)で **LED の位置(キャビティ中心から見た極角 θ=0〜120° を 13 段階)・向き(板向き+バッフル/壁法線向き+バッフル/真下向き)・個数(θ=90° の輪に N=1〜4)・再現性(seed 違い)** の 198 条件で検証した(Newton cuda・1 条件 5〜6 秒).**結果 ①**: θ 全域での構造 CoV の幅は球 0.015〜0.023・立方体 0.025〜0.071(1.2〜3.1 倍),max\|a1\| は 3〜4% vs 4.5〜11%.立方体は θ とともに単調に悪化し板の直下で軸上の 3.4〜5 倍.**球は θ≈30° が軸上より均一**(φ340: 0.0193 → 0.0057.軸上のリング構造が崩れる)で「どこに置いてもそこそこ」.立方体の優位は軸上の 1 点だけ.**結果 ②**: 真下向き(板が背後=バッフル無し)は板向き+バッフルと同等で 5〜30% 明るい.壁法線向き(キャビティ中心向き)は最悪(2〜5 倍).**結果 ③**: 対向 2 灯で m=1 は ≤0.3% に消え構造 CoV は 0.005〜0.010=単灯軸上より均一で形状差が消える.立方体は N=3 で崩れる(3 回対称が 4 回対称の壁と噛み合わない).**ノイズフロア**: 構造 CoV ±0.0007・a1 ±0.08%.設計への含意は「単灯なら球,多灯にできるなら側壁の対向 2〜4 灯・真下向き・バッフル無しで立方体でも球と同等」.**方法論**: 極角 θ を両形状共通のパラメータにし,立方体の稜(45°)は外す.板の近くのバッフルは外殻の貫通を許容し食い込み量を記録(壁法線向きは半径がキャビティ寸法の 0.6 を超えたら無効).解析は TEST_16/17 の方位フーリエ(m=1〜4)+構造 CoV+重心.**追加実験(同日夜)**: ① 方位角: 立方体は面の中央が最良で稜へ寄せるほど構造 CoV が 1.3〜1.75 倍に悪化(球は方位に依らない)/ ② 真下向き多灯(バッフル無し): 2 灯以上で非対称は消え単灯軸上より均一だが,板向き+バッフルの多灯には 1.5〜2.5 倍劣り N を増やしても頭打ち(一次照射が壁の下半分に集中し動径構造が残る).③ 校正材質(純 diffuse ρ=0.81)で主要 60 条件を引き直し: 配置依存の幅は球 0.030 vs 立方体 0.077〜0.098 と結論は不変(むしろ差が広がる).ただし旧材質の光沢 5% が作っていた軸上のリング構造が消え,**校正材質では両形状とも軸上が最良**(「球は θ≈30° が最良」は旧材質の産物).全 255 + 60 条件(TEST_18 結果 5〜7).**失敗パターン**: spawn のワーカーには主プロセスで切り替えた出力ディレクトリ(材質)が伝わらず,旧材質の row.json を再利用して 60 条件が空振りした → 材質を run_job の引数で渡す. diff --git a/scripts/build_fullimage_minmax.py b/scripts/build_fullimage_minmax.py index 6fb7d55..0cb4560 100644 --- a/scripts/build_fullimage_minmax.py +++ b/scripts/build_fullimage_minmax.py @@ -153,10 +153,11 @@ def draw(rows: list[dict], output: Path) -> None: """定義ごとの min/max 比とノイズ床をサイズに対して描く.""" fig, axes = plt.subplots(2, 2, figsize=(15, 10)) - for col, (shape, xlabel) in enumerate((("sphere", "球 内半径 r [mm]"), + for col, (shape, xlabel) in enumerate((("sphere", "球 内径 φ [mm]"), ("cube", "立方体 内寸 L [mm]"))): sel = [r for r in rows if r["shape"] == shape] - sizes = [r["size_mm"] for r in sel] + scale = 2.0 if shape == "sphere" else 1.0 # 球は内径で描く + sizes = [r["size_mm"] * scale for r in sel] ax = axes[0, col] for d in DEFINITIONS: ax.plot(sizes, [r[d] for r in sel], label=DEF_LABEL[d], ms=5, lw=1.4, **DEF_STYLE[d]) @@ -194,7 +195,8 @@ for shape, items in conditions().items(): for label, path in items: roi = load_roi(path) - row = {"shape": shape, "size_mm": float(label.split("=")[1]), + size = float(label[1:]) / 2.0 if label.startswith("φ") else float(label.split("=")[1]) + row = {"shape": shape, "size_mm": size, "raw_mean": float(roi.mean())} row.update(min_max_all(roi, rng)) row.update(noise_floor(roi, rng)) diff --git a/scripts/build_led_placement_comparison.py b/scripts/build_led_placement_comparison.py index ee3b65c..ec57ea1 100644 --- a/scripts/build_led_placement_comparison.py +++ b/scripts/build_led_placement_comparison.py @@ -62,6 +62,8 @@ write_summary, ) +from sm_tias_lightsim.evaluation.fullimage import calc_fullimage_min_max_ratio # noqa: E402 + OUTPUT_BASE = sweep.OUTPUT_BASE plt.rcParams["font.family"] = ["Yu Gothic", "MS Gothic", "DejaVu Sans"] @@ -72,13 +74,13 @@ SHAPE_STYLE = {"sphere": dict(marker="o", ls="-"), "cube": dict(marker="s", ls="--")} AIM_LABEL = {"board": "板中心向き", "normal": "壁法線向き", "down": "真下向き"} MAP_THETAS = [0.0, 30.0, 60.0, 90.0, 120.0] -MAP_PAIR_INDEX = 2 # 輝度マップに使う代表ペア(r=170 / L=234) +MAP_PAIR_INDEX = 2 # 輝度マップに使う代表ペア(球 φ340 / 立方体 L=234) ANALYSIS_COLUMNS = [ "name", "group", "shape", "size_mm", "pair", "theta_deg", "aim", "n_led", "rep", "azimuth_deg", "cavity_area_mm2", "baffle_radius_mm", "baffle_ratio", "occlusion_blocked_frac", - "raw_mean_roi", "cov", "structure_cov", "noise_cov", "ring_min_max", + "raw_mean_roi", "cov", "structure_cov", "noise_cov", "ring_min_max", "fullimage_min_max", "centroid_x", "centroid_y", "centroid_offset", "a1", "b1", "se1", "m1_abs", "a1_led", "a2", "b2", "se2", "a3", "b3", "se3", "a4", "b4", "se4", "a8", "b8", "se8", @@ -87,12 +89,12 @@ def size_label(shape: str, size: float) -> str: - """条件ラベル用のサイズ表記.""" - return f"{'r' if shape == 'sphere' else 'L'}={size:g}" + """条件ラベル用のサイズ表記(球は内径 φ=2r で表す.内部パラメータは半径のまま).""" + return f"φ{2 * size:g}" if shape == "sphere" else f"L={size:g}" def pair_size(pair: tuple[float, float], shape: str) -> float: - """同内面積ペアから該当形状のサイズ(球=内半径 / 立方体=内寸)を取り出す.""" + """同内面積ペアから該当形状のサイズ(球=内半径 r / 立方体=内寸 L)を取り出す(表示は φ=2r).""" return pair[SHAPES.index(shape)] @@ -138,6 +140,9 @@ result["structure_cov"] = structure result["noise_cov"] = noise result["ring_min_max"] = ring_min_max_ratio(centers, means) + # 輪帯平均は方位方向に平均するのでオフ軸の非対称を打ち消す.画像全体の定義を併記する + result["fullimage_min_max"] = calc_fullimage_min_max_ratio( + load_roi(lum))["fullimage_min_max_ratio"] result["centroid_x"] = row.get("intensity_centroid_x_norm", float("nan")) result["centroid_y"] = row.get("intensity_centroid_y_norm", float("nan")) result["centroid_offset"] = row.get("intensity_centroid_offset_norm", float("nan")) @@ -330,7 +335,7 @@ ax.set_title(f"θ={theta:g}°: {ylabel}", fontsize=11) ax.grid(alpha=0.3, axis="y") handles = [plt.Rectangle((0, 0), 1, 1, color=colors[i], - label=f"ペア{i + 1}: r={p[0]:g} / L={p[1]:g}") + label=f"ペア{i + 1}: φ{2 * p[0]:g} / L={p[1]:g}") for i, p in enumerate(SIZE_PAIRS)] handles += [ plt.Rectangle((0, 0), 1, 1, fc="white", ec=SHAPE_COLOR["sphere"], label="球(枠青)"), diff --git a/scripts/build_led_placement_maps.py b/scripts/build_led_placement_maps.py index bea177f..3133ca8 100644 --- a/scripts/build_led_placement_maps.py +++ b/scripts/build_led_placement_maps.py @@ -63,7 +63,7 @@ CMAP = "hot" # 共通スケールの下限(最大=1.0 に対する比).全パネルで固定して見比べられるようにする VMIN = 0.80 -REP_PAIR = 2 # 代表ペア(r=170 / L=234) +REP_PAIR = 2 # 代表ペア(球 φ340 / 立方体 L=234) # 正規化の方式(--normalize): # robust_peak: 平滑化後の 99 パーセンタイルを 1.0 にする(既定).方位に依らず「最も明るい所 @@ -157,7 +157,9 @@ def row_label(shape: str, size: float) -> str: """行見出し(形状とサイズ).""" - return f"{SHAPE_LABEL[shape]} {'r' if shape == 'sphere' else 'L'}={size:g}" + if shape == "sphere": + return f"{SHAPE_LABEL[shape]} φ{2 * size:g}" # 内径で表す(内部パラメータは半径) + return f"{SHAPE_LABEL[shape]} L={size:g}" def pair_sizes(pair: int) -> dict[str, float]: @@ -233,7 +235,7 @@ cells.append(row) labels.append(f"{SHAPE_LABEL[shape]}\n{AIM_LABEL[aim]}") draw_grid(cells, labels, - f"向きの比較(1 灯・ペア{REP_PAIR + 1}: r={sizes['sphere']:g} / " + f"向きの比較(1 灯・ペア{REP_PAIR + 1}: 球 φ{2 * sizes['sphere']:g} / " f"L={sizes['cube']:g}).LED は画像右側", out_dir / "maps_direction.png", cell_size=2.6) diff --git a/scripts/build_minmax_asymmetry_comparison.py b/scripts/build_minmax_asymmetry_comparison.py new file mode 100644 index 0000000..e5785d1 --- /dev/null +++ b/scripts/build_minmax_asymmetry_comparison.py @@ -0,0 +1,201 @@ +"""輪帯平均と画像全体の最小/最大比を,非対称な照明配置(TEST_18)で比較する. + +輪帯平均の min/max(`ring_min_max`)は方位方向に平均するので,LED をオフ軸に置いて +生じる「片側だけ明るい」非対称を打ち消してしまう.画像全体のノイズ補正付き min/max +(`fullimage_min_max`,`evaluation/fullimage.py`)は方位方向に平均しないので, +その非対称が値に乗るはずである.本スクリプトはその差が実際に非対称の大きさ |a1| +(m=1 方位フーリエ成分)とともに開くことを,位置スイープ(4 ペア × 13 θ)で確かめる. + +入力は `build_led_placement_comparison.py` が書いた analysis.csv(両定義の列を含む). +luminance.npy の読み直しはしない. + +出力(output/led_placement_sweep/): + minmax_asymmetry.png / minmax_asymmetry.csv + +実行方法: + uv run python scripts/build_minmax_asymmetry_comparison.py +""" + +from __future__ import annotations + +import argparse +import csv +import sys +from pathlib import Path + +import matplotlib +import numpy as np + +matplotlib.use("Agg") +import matplotlib.pyplot as plt # noqa: E402 + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) + +import build_led_placement_comparison as placement # noqa: E402 +import sweep_led_placement as sweep # noqa: E402 +from sweep_led_placement import MATERIALS, SHAPES, SIZE_PAIRS, set_material # noqa: E402 + +plt.rcParams["font.family"] = ["Yu Gothic", "MS Gothic", "DejaVu Sans"] + +CSV_COLUMNS = [ + "name", "shape", "size_mm", "theta_deg", "m1_abs", + "ring_min_max", "fullimage_min_max", "diff", "structure_cov", +] + +# θ=0 は軸上(対称)・θ=120 は板の直下(最も非対称).標準出力で対比する +THETA_SYMMETRIC = 0.0 +THETA_OFFAXIS = 120.0 + + +def load_rows(analysis_csv: Path) -> list[dict]: + """analysis.csv から位置スイープの行を読み,両定義と差を持つ dict のリストを返す.""" + rows: list[dict] = [] + with analysis_csv.open(encoding="utf-8", newline="") as fh: + for raw in csv.DictReader(fh): + if raw.get("group") != "position": + continue + if not raw.get("fullimage_min_max"): + continue + ring = float(raw["ring_min_max"]) + full = float(raw["fullimage_min_max"]) + rows.append({ + "name": raw["name"], + "shape": raw["shape"], + "size_mm": float(raw["size_mm"]), + "theta_deg": float(raw["theta_deg"]), + "m1_abs": float(raw["m1_abs"]), + "ring_min_max": ring, + "fullimage_min_max": full, + "diff": ring - full, + "structure_cov": float(raw["structure_cov"]), + }) + return sorted(rows, key=lambda r: (r["shape"], r["size_mm"], r["theta_deg"])) + + +def series(rows: list[dict], shape: str, size: float) -> list[dict]: + """同じ形状・サイズの系列を θ 昇順で取り出す.""" + return [r for r in rows if r["shape"] == shape and r["size_mm"] == size] + + +def draw(rows: list[dict], output: Path) -> None: + """θ に対する両定義の比較(形状ごと)と,差 vs 非対称の大きさの散布図を描く.""" + fig, axes = plt.subplots(1, 3, figsize=(19, 5.6)) + colors = placement.size_colors(len(SIZE_PAIRS)) + + for ax, shape in zip(axes[:2], SHAPES, strict=False): + for i, pair in enumerate(SIZE_PAIRS): + size = placement.pair_size(pair, shape) + sel = series(rows, shape, size) + if not sel: + continue + theta = [r["theta_deg"] for r in sel] + label = placement.size_label(shape, size) + ax.plot(theta, [r["fullimage_min_max"] for r in sel], color=colors[i], + marker="o", ms=4, lw=1.6, ls="-", label=f"{label} 画像全体") + ax.plot(theta, [r["ring_min_max"] for r in sel], color=colors[i], + marker="x", ms=4, lw=1.2, ls=":", alpha=0.75, label=f"{label} 輪帯平均") + ax.set_xlabel("LED 極角 θ [deg](0=底の中心・90=側壁の中段・120=板の直下)") + ax.set_ylabel("最小/最大比(1 が理想)") + ax.set_title(f"{placement.SHAPE_LABEL[shape]}:実線=画像全体(ノイズ補正)" + "/点線=輪帯平均", fontsize=11) + ax.grid(alpha=0.3) + ax.legend(fontsize=7, ncol=2) + + ax = axes[2] + for shape in SHAPES: + for i, pair in enumerate(SIZE_PAIRS): + size = placement.pair_size(pair, shape) + sel = series(rows, shape, size) + if not sel: + continue + ax.scatter([r["m1_abs"] * 100 for r in sel], [r["diff"] for r in sel], + color=colors[i], marker=placement.SHAPE_STYLE[shape]["marker"], + s=26, alpha=0.8, + label=f"{placement.SHAPE_LABEL[shape]} {placement.size_label(shape, size)}") + ax.axhline(0.0, color="gray", lw=0.8, ls="--") + ax.set_xlabel("非対称の大きさ |a1|(輪帯平均比 %)") + ax.set_ylabel("輪帯平均 − 画像全体(差)") + ax.set_title("方位非対称が大きいほど輪帯平均は均一に見える(差が開く)", fontsize=11) + ax.grid(alpha=0.3) + ax.legend(fontsize=7, ncol=2) + + fig.suptitle("最小/最大比の定義比較 — 輪帯平均は方位方向に平均するため" + "オフ軸 LED の非対称を過小評価する(TEST_18 位置スイープ)", fontsize=14) + fig.tight_layout() + output.parent.mkdir(parents=True, exist_ok=True) + fig.savefig(output, dpi=110) + plt.close(fig) + print(f"出力: {output}") + + +def report(rows: list[dict]) -> None: + """形状ごとに軸上/オフ軸での差と,差と |a1| の相関係数を表示する.""" + print("\n=== 輪帯平均 − 画像全体(差)===") + print(f"{'形状':>6} {'サイズ':>7} {'θ=0 の差':>10} {'θ=120 の差':>11} " + f"{'差の最大':>9} {'相関 r(差, |a1|)':>16}") + for shape in SHAPES: + for pair in SIZE_PAIRS: + size = placement.pair_size(pair, shape) + sel = series(rows, shape, size) + if len(sel) < 3: + continue + diffs = np.array([r["diff"] for r in sel]) + m1 = np.array([r["m1_abs"] for r in sel]) + at_sym = next((r["diff"] for r in sel if r["theta_deg"] == THETA_SYMMETRIC), np.nan) + at_off = next((r["diff"] for r in sel if r["theta_deg"] == THETA_OFFAXIS), np.nan) + corr = float(np.corrcoef(diffs, m1)[0, 1]) if diffs.std() > 0 else float("nan") + print(f"{placement.SHAPE_LABEL[shape]:>6} {size:7g} {at_sym:10.4f} {at_off:11.4f} " + f"{diffs.max():9.4f} {corr:16.3f}") + + for shape in SHAPES: + sel = [r for r in rows if r["shape"] == shape] + if len(sel) < 3: + continue + diffs = np.array([r["diff"] for r in sel]) + m1 = np.array([r["m1_abs"] for r in sel]) + corr = float(np.corrcoef(diffs, m1)[0, 1]) + print(f"{placement.SHAPE_LABEL[shape]}(全サイズ {len(sel)} 条件): " + f"差と |a1| の相関係数 r={corr:.3f}") + + +def write_csv(rows: list[dict], output: Path) -> None: + """比較表を CSV に書き出す.""" + output.parent.mkdir(parents=True, exist_ok=True) + with output.open("w", newline="", encoding="utf-8") as fh: + writer = csv.DictWriter(fh, fieldnames=CSV_COLUMNS) + writer.writeheader() + for r in rows: + writer.writerow({k: r[k] for k in CSV_COLUMNS}) + print(f"出力: {output}") + + +def main() -> int: + """位置スイープについて両定義の min/max 比を比較する図と表を出す.""" + parser = argparse.ArgumentParser(description="輪帯平均と画像全体の min/max 比を比較") + parser.add_argument("--material", choices=tuple(MATERIALS), default="legacy", + help="解析する材質系列(スイープの --material と同じ)") + args = parser.parse_args() + set_material(args.material) + output_base = sweep.OUTPUT_BASE + + analysis_csv = output_base / "analysis.csv" + if not analysis_csv.exists(): + print(f"エラー: {analysis_csv} がありません." + "先に build_led_placement_comparison.py を実行してください") + return 1 + + rows = load_rows(analysis_csv) + if not rows: + print(f"エラー: {analysis_csv} に fullimage_min_max 列の入った位置スイープの行が" + "ありません.build_led_placement_comparison.py を再実行してください") + return 1 + + write_csv(rows, output_base / "minmax_asymmetry.csv") + draw(rows, output_base / "minmax_asymmetry.png") + report(rows) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/build_minmax_definition_comparison.py b/scripts/build_minmax_definition_comparison.py index 2ac2a3d..f7ad308 100644 --- a/scripts/build_minmax_definition_comparison.py +++ b/scripts/build_minmax_definition_comparison.py @@ -88,10 +88,11 @@ def draw(rows: list[dict], output: Path) -> None: """定義ごとの最小/最大比をサイズに対して描く(球・立方体で 1 枚ずつ + 定義間の差).""" fig, axes = plt.subplots(1, 3, figsize=(19, 5.5)) - for ax, shape, xlabel in ((axes[0], "sphere", "球 内半径 r [mm]"), + for ax, shape, xlabel in ((axes[0], "sphere", "球 内径 φ [mm]"), (axes[1], "cube", "立方体 内寸 L [mm]")): sel = [r for r in rows if r["shape"] == shape] - sizes = [r["size_mm"] for r in sel] + scale = 2.0 if shape == "sphere" else 1.0 # 球は内径で描く + sizes = [r["size_mm"] * scale for r in sel] for d in DEFINITIONS: ax.plot(sizes, [r[d] for r in sel], label=DEF_LABEL[d], ms=5, lw=1.4, **DEF_STYLE[d]) ax.set_xlabel(xlabel) @@ -137,7 +138,7 @@ rows = [] for shape, items in conditions().items(): for label, path in items: - size = float(label.split("=")[1]) + size = float(label[1:]) / 2.0 if label.startswith("φ") else float(label.split("=")[1]) area = (sphere_geo(size, "similar_radial") if shape == "sphere" else cube_geo(size))["cavity_area_mm2"] row = {"shape": shape, "size_mm": size, "area": area} diff --git a/scripts/build_normalization_comparison.py b/scripts/build_normalization_comparison.py index a6cecb0..f4a9cf4 100644 --- a/scripts/build_normalization_comparison.py +++ b/scripts/build_normalization_comparison.py @@ -71,7 +71,7 @@ def conditions() -> dict[str, list[tuple[str, Path]]]: """形状 → [(ラベル, luminance.npy)] を返す(存在するものだけ).""" sphere_dir = SPHERE_OUTPUT_BASE / SPHERE_RUN_DIR - sphere = [(f"r={r:g}", sphere_dir / sphere_job_name(r) / "luminance.npy") + sphere = [(f"φ{2 * r:g}", sphere_dir / sphere_job_name(r) / "luminance.npy") for r in SPHERE_RADII] cube = [(f"L={size:g}", CUBE_OUTPUT_BASE / CUBE_RUN_DIR / cube_job_name(size) / "luminance.npy") for size in CUBE_SIZES]