MCPcopy Create free account
hub / github.com/FastLED/FastLED / nnls3

Function nnls3

tests/fl/gfx/rgbw_colorimetric.cpp:733–760  ·  view source on GitHub ↗

Port of xy_target_rgbw_model.py `_nnls_solve` — projected-gradient NNLS for a 3x3 system. The Python version prefers scipy.optimize.nnls when available; we use the same projected-gradient fallback (500 iters @ step 0.01) since scipy isn't available in this TU. The reference falls back to this code on platforms lacking scipy, so this fidelity matches the reference's actual portable behavior.

Source from the content-addressed store, hash-verified

731// to this code on platforms lacking scipy, so this fidelity matches the
732// reference's actual portable behavior.
733inline void nnls3(const float M[3][3], const float b[3], float t_out[3], float& residual) {
734 float t[3] = {0.0f, 0.0f, 0.0f};
735 for (int it = 0; it < 500; ++it) {
736 // r = M·t − b
737 float r[3];
738 for (int i = 0; i < 3; ++i) {
739 r[i] = M[i][0]*t[0] + M[i][1]*t[1] + M[i][2]*t[2] - b[i];
740 }
741 // grad = Mᵀ·r
742 float grad[3];
743 for (int j = 0; j < 3; ++j) {
744 grad[j] = M[0][j]*r[0] + M[1][j]*r[1] + M[2][j]*r[2];
745 }
746 // t ← max(t − step·grad, 0)
747 const float step = 0.01f;
748 for (int j = 0; j < 3; ++j) {
749 float v = t[j] - step * grad[j];
750 t[j] = v > 0.0f ? v : 0.0f;
751 }
752 }
753 // residual = ‖M·t − b‖₂
754 float r[3];
755 for (int i = 0; i < 3; ++i) {
756 r[i] = M[i][0]*t[0] + M[i][1]*t[1] + M[i][2]*t[2] - b[i];
757 }
758 residual = fl::sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
759 t_out[0] = t[0]; t_out[1] = t[1]; t_out[2] = t[2];
760}
761
762// Port of `_strict_project_target_xyz_to_led_hull`. When target_xy is outside
763// the LED RGB triangle, projects to the nearest in-hull point by trying NNLS

Callers 2

project_to_hull_mirrorFunction · 0.70
project_to_hullFunction · 0.70

Calls 1

sqrtFunction · 0.85

Tested by

no test coverage detected