Bulk acoustic diffusion screening for panel geometry given as depth maps. Computes ISO 17497-2 directional diffusion coefficients across 1/3-octave bands (250 Hz – 4 kHz) with a Fraunhofer–Kirchhoff scattering integral, fast enough to triage 1000+ panels before high-fidelity simulation (~0.6 s/panel on a desktop CPU; 800 panels in about a minute with 8 worker processes — no GPU needed).
Developed for the paper "Visual and Performance Impacts of AI-Generated Diffusion Panels" (Forum Acusticum 2026, paper FA2026/778), where it screens AI-generated (diffusion model + Marigold monocular depth) acoustic panel candidates against a modulated-QRD algorithmic baseline. The method itself is generic: any 1×1 m relief expressed as a grayscale depth map can be screened.
| Input | folder of 768×768 PNG depth maps (16-bit preferred, 8-bit accepted with --allow-8bit), Marigold convention: pixel 0 = deepest |
| Output | CSV with per-panel, per-band raw + normalized diffusion coefficients d, d_n, geometric heuristics, validity flags; optional per-panel polar responses (NPZ); full run metadata JSON |
| Physics | Fraunhofer–Kirchhoff (physical optics) integral over the height field, rigid surface, single bounce, single frequency per band (Cox & Lam 1994 precedent) |
| Metric | ISO 17497-2 directional diffusion coefficient over a 648-receiver hemisphere with solid-angle weights, flat-plate normalized |
pip install -e .[plots,test]
Python ≥ 3.10. Core deps: numpy, scipy, pillow, pandas, tqdm (matplotlib only for the figure scripts).
python -m kirchhoff_panels.cli --input-dir path/to/depth_maps --output-dir results/run_001 \
--z-method rms --z-value 0.05 --integration-res 256 --workers 8
Key options:
--z-method {rms,max_depth}+--z-value— Marigold depth is affine-invariant, so an absolute Z scale must be imposed: either RMS roughness (default σ = 5 cm, Rayleigh criterion → scattering onset ≈ 860 Hz, hard cap 20 cm) or a fixed maximum depth.--multi-incidence— run 0°/30°/60° incidence instead of normal-only.--save-polar [--save-polar-all-bands]— write per-panel hemispherical responses as NPZ.--allow-8bit— accept 8-bit (quantized) depth maps with a warning.--workers N— panels are embarrassingly parallel across processes.
The output CSV contains one row per panel × incidence angle: panel_id, typology
(parsed from the filename), achieved normalization values, d_norm_<band> /
d_raw_<band> / validity_<band> per 1/3-octave band, RMS surface slope, feature
correlation length, and compute time.
python run_validation.py reproduces the four-case suite (plots + numbers under
results/validation/):
- Flat plate — normalized coefficient is 0 in every band by construction (passes exactly).
- Hemispherical bump vs. Mie series — backscatter compared against the rigid-sphere analytical solution via the image principle (|f(π)+f(0)|). The error decays as the classic physical-optics O(1/ka): ~3 dB at ka = 5, < 1 dB above ka ≈ 22.
- QRD N = 7 — Schroeder diffuser signatures: diffusion rises above the design frequency (single-plane-arc plateau ≈ 0.46) and dips at the critical frequency N·f₀.
- Mesh convergence — 256² vs 512² integration agree within 0.5 % on d_n (2 % tolerance).
See docs/METHOD.md for formulation, conventions, limits of validity,
and the fast-kernel derivation; kirchhoff_bulk_analysis_spec.json is the original
machine-readable implementation spec.
make_figures.py builds the paper's figure set (pipeline diagram, per-typology d_n
curves vs. baseline, heuristic scatter, distribution violins, polar gallery) from run
outputs. Sequence:
python make_baseline.py # modulated-QRD baseline depth map -> baseline_input/
python -m kirchhoff_panels.cli --input-dir baseline_input --output-dir results/run_baseline_rms \
--z-method rms --z-value 0.05 --save-polar --save-polar-all-bands
python -m kirchhoff_panels.cli --input-dir baseline_input --output-dir results/run_baseline_native \
--z-method max_depth --z-value 0.2806 --save-polar --save-polar-all-bands
python -m kirchhoff_panels.cli --input-dir <your_depth_maps> --output-dir results/run_production \
--z-method rms --z-value 0.05 --workers 8
python make_figures.py
The AI-generated panel dataset itself (800 depth maps, 8 typologies) is not part of this repository; figures that need it are skipped gracefully.
The full input dataset — 800 rendered panel images (FLUX.2-klein-9B, LLM-assisted prompting) plus their 800 paired Marigold depth maps across 8 aesthetic typologies — is published separately on Zenodo under CC BY 4.0:
AI-Generated Acoustic Diffusion Panels: Image and Depth-Map Dataset DOI: 10.5281/zenodo.22028626
Unzip Depth_maps.zip anywhere and point --input-dir at it to reproduce the
production screening run.
kirchhoff_panels/ the package (io, preprocessing, kernel, diffusion metric, batch runner, CLI)
tests/ pytest suite incl. fast-kernel vs brute-force regression
run_validation.py validation suite (Task B of the paper spec)
make_baseline.py generates the modulated-QRD (N1=7/N2=11) baseline depth map
make_figures.py paper figure set from run outputs
grasshopper/ GhPython source of the original Rhino/Grasshopper QRD generator
docs/METHOD.md physics, conventions, validation, performance notes
kirchhoff_bulk_analysis_spec.json machine-readable implementation spec
- T. J. Cox, Y. W. Lam, Prediction and evaluation of the scattering from quadratic residue diffusers, JASA 95(1), 1994.
- T. J. Cox, P. D'Antonio, Acoustic Absorbers and Diffusers, 3rd ed., CRC Press, 2017.
- ISO 17497-2:2012 — Sound-scattering properties of surfaces, Part 2: directional diffusion coefficient.
- N. Tsingos et al., Instant Sound Scattering, EGSR 2007.
- K. Ke et al., Marigold: Repurposing Diffusion-Based Image Generators for Monocular Depth Estimation, CVPR 2024.
MIT — see LICENSE.

