It's not going to win any design contests, but I've updated my AS7341 web app's stylesheet so at least its layout is no longer confusing and no longer an embarrassing eyesore. It's the first of several things I wanted to do for polish. My next challenge is to interpret AS7341 spectrum information into to a color hue a human eye would perceive from looking at the same thing. This is not a trivial conversion, as human color perception has been a long-running area of research. After a few minutes of trying to get my bearings on Wikipedia, I've reached the conclusion that doing a good job with my own implementation would take more time than I'm willing to spend on it.

What about somebody else's implementation? A search for spectrum math library in JavaScript led me to a color picker control named Spectrum, which is not helpful to my current project. Looking on NPM, I found a CIE color conversion library, but I don't see how to make it perform the type of conversion I seek. Casting my net wider than JavaScript, I found this article titled "Converting a spectrum to a colour" that opens with "This article presents a Python script to map a spectrum of wavelengths to a representation of a colour." This is exactly what I want! Unfortunately, I struggled to understand the Python code, certainly not enough to convert it to JavaScript for my use. Maybe I can come back later to try again, but in the short term I will try a hack.

AS7341 datasheet tells us which wavelengths each sensors F1-F8 are designed to be sensitive to. Looking online, I found Academo's "Wavelength to Colour Relationship" page that lets me input a wavelength and translate that to RGB value. Taking a table of RGB values for wavelengths corresponding to AS7341 sensors F1-F8, I added up each column: all the red in one value, all the green, then all the blue.

Wavelength Red Green Blue
415 118 0 237
445 0 40 255
480 0 213 255
515 31 255 0
555 179 255 0
590 255 223 0
630 255 79 0
680 255 0 0
Sum 1093 1065 747

We see the highest sum for red, followed by green a bit behind, and blue is significantly lower. This is consistent with datasheet telling us the silicon underneath each wavelength filter is naturally more sensitive to red. Since white (and shades of gray) is represented by equal portions of red, green, and blue, getting there required boosting the blue-focused colors a bit to even things out. I didn't put in rigorous mathematics to make them balanced since I don't even know if this action makes sense in color science. As a quick hack, I used a spreadsheet and fiddled with numbers via trial and error. I found that if I multiplied 415nm by 1.72, 445nm by 1.6, and 480nm by 1.4, I would get red/green/blue within 1% of each other. From here I can multiply them by F1-F8 readings and calculate each of their contribution to red/green/blue channels and generate a color value.

This is an empirically derived formula with no basis in color science, but it does generate a color value that is vaguely in the right general ballpark. I piped that color into Chart.js to be used as my chart background color, following instructions on their documentation. This is most of what I wanted, and maybe the best I can do without investing the work to understand human color perception. Not great, but good enough for a quick hack project so I can move on to the next feature.


Code for this project is publicly available on GitHub