Skip to content

Optimization#

Spectrally tunable lighting is naturally an optimization problem. A source has multiple emitters, each emitter has a measured spectral distribution, and a target defines what the mixed spectrum should become.

At a high level:

  1. Read emitter spectra into a matrix.
  2. Choose one weight per emitter.
  3. Mix the spectra with matrix multiplication.
  4. Compare the mixed spectrum to a target.
  5. Update weights with an optimizer.
  6. Apply the final weights with manual mode.

Rust-first workflow#

Use the CLI to capture reproducible emitter data:

enody download-spectral-data -o spectral-data.json

Then build and test the optimizer against that file in Rust. Once the optimizer returns one relative flux value per emitter, apply those weights with the Rust SDK:

use enody::message::{Configuration, Flux};

for (emitter, value) in source.emitters().await?.iter().zip(weights) {
    emitter.set_flux(Flux::Relative(value)).await?;
}

fixture
    .display(Configuration::Manual, Flux::Relative(1.0))
    .await?;

This keeps the hardware-control path in the Rust SDK while allowing optimizer experiments to run offline against captured spectral data.

Python helper bindings#

The Python bindings include tinygrad-based response and color helpers:

Function Input shape
melanopic_response(t) (n, 401)
rhodopic_response(t) (n, 401)
s_cone_response(t) (n, 401)
m_cone_response(t) (n, 401)
l_cone_response(t) (n, 401)
cie_x_response(t) (n, 401)
cie_y_response(t) (n, 401)
cie_z_response(t) (n, 401)
cie_1931_chromaticity(t) (n, 401)
ssi(test, reference) (n, 301)

JavaScript helpers#

The JavaScript SDK includes typed-array response and optimizer helpers:

Function / type Input shape
melanopicResponse(distributions) 401 or (n, 401)
rhodopicResponse(distributions) 401 or (n, 401)
sConeResponse(distributions) 401 or (n, 401)
mConeResponse(distributions) 401 or (n, 401)
lConeResponse(distributions) 401 or (n, 401)
cie1931Chromaticity(distributions) 401 or (n, 401)
computeSSI(test301, reference301) 301
SpectralOptimizer SPD matrix as numEmitters * 401