Add pictures and styling

This commit is contained in:
jaseg 2018-05-13 14:27:57 +02:00
parent 6d8585ea97
commit c6283c2028
13 changed files with 159 additions and 27 deletions

View file

@ -1,4 +1,4 @@
baseURL = "https://jaseg.net/"
languageCode = "en-us"
title = "jaseg.net"
theme = "ananke"
theme = "hugo-classic"

View file

@ -49,14 +49,33 @@ transformation.
An illustration of the HSV color space as a cylinder. `Picture by SharkD
<https://commons.wikimedia.org/wiki/File:HSV_color_solid_cylinder.png>`_ (`CC BY-SA 3.0`_), from Wikimedia Commons.
CIE 1931 XYZ is much larger than any other color space, which is why it is a good basis to express other color spaces
in. In XYZ there are many coordinates that are outside of what the human eye can perceive. Below is an illustration of
the sRGB space within XYZ. The wireframe cube is (0,0,0) to (1,1,1) in XYZ. The colorful object in the middle is what
of sRGB fits inside XYZ, and the lines extending out from it indicate the space that can be expressed in sRGB but not in
XYZ. The fat white curve is a projection of the *monochromatic spectral locus*, that is the curve of points you get in
XYZ for pure visible wavelengths.
As you can see, sRGB is *much* smaller than XYZ or even the part within the monochromatic locus that we can perceive. In
particular in the blues and greens we loose *a lot* of colors to sRGB.
.. raw:: html
<video width="480" controls loop>
<source src="/video/sRGB.mkv" type="video/h264">
<source src="/video/sRGB.webm" type="video/webm">
Your browser does not support the HTML5 video tag.
</video>
`mkv/h264 download </video/sRGB.mkv>`__/`webm download </video/sRGB.webm>`__
The wrong colors I got when fading between colors were caused by this coordinate transformation being askew. Thinking
over the problem, there are several sources for imperfections:
* The LED driver may not be entirely linear. For most modulations such as PWM the brightness will be linear starting
from a certain value, but there is probably an offset caused by imperfect edges of the LED current. This offset can be
compensated with software calibration. I built a calibration setup for driver linearity in the `multichannel LED
driver`_ project.
.. FIXME picture with ringing on edges
driver`_ project. Below are pictures of ringing on the edges of an LED driver's waveform.
* The red, green and blue channels of the LEDs used on the LED tape are not matched. This skews the RGB color space.
In practice, the blue channel of my RGB tape to me *looks* much brighter than the red channel.
@ -65,6 +84,23 @@ over the problem, there are several sources for imperfections:
may be of a slightly different hue compared to the reference red used in `sRGB`_ which would also skew the RGB color
space.
.. raw:: html
<figure>
<figure class="side-by-side">
<img src="/images/driver_ringing_strong.jpg" alt="Strong ringing on the LED voltage waveform edge at about
100% overshoot during about 70% of the cycle time.">
<figcaption>The shift register logic output of the multichannel LED driver directly driving a small mosfet's
gate through an inch or so of PCB trace caused extremely bad ringing at high driving
frequencies.</figcaption>
</figure><figure class="side-by-side">
<img src="/images/driver_ringing_weak.jpg" alt="Weak ringing on the LED voltage waveform edge at about 30%
overshoot during about 20% of the cycle time.">
<figcaption>Adding a resistor dampened the ringing somewhat, but ultimately it cannot be eliminated
entirely.</figcaption>
</figure>
</figure>
These last two errors are tricky to compensate. What I needed for that was basically a model of the *perceived* colors
of the LED tape's color channels. A way of doing his is to record the spectra of all color channels and then evaluate
their respective XYZ coordinates. If all three channels are measured in one go with the same setup the relative
@ -74,7 +110,7 @@ To map any color to the LEDs, the color's XYZ coordinates simply have to be mapp
produced by these three points within XYZ. LEDs are extremely linear in their luminous flux vs. current characteristic
so this model will be adequate. The spectral integrals mapping the channels' measured responses to XYZ need only be
calculated once and their results can be used as scaling factors thereafter.
.. FIXME: Add led/current graph here
.. FIXME Add led/current graph here
Measuring the spectrum
----------------------
@ -110,7 +146,29 @@ specific to the semiconductor used and is quite precise. White LEDs are in fact
and re-emits a broader spectrum of more yellow-ish wavelengths instead. The final LED spectrum is a superposition of
both spectra, with some of the original blue light leaking through the phosphor mixing with the broadband yellow
spectrum of the phosphor.
.. FIXME: Cardboard spectrograph pictures
.. raw:: html
<figure>
<figure class="side-by-side">
<img src="/images/spectrograph_step1_parts.jpg">
<figcaption>The ingredients. The cup of coffee and Madoka Magica DVD set are essential to the eventual
function of the appartus.</figcaption>
</figure><figure class="side-by-side">
<img src="/images/spectrograph_step2.jpg">
<figcaption>Step 1: Cut to size and mark down all holes as described in <a
href="http://www.candac.ca/candacweb/sites/default/files/BuildaSpectroscope.pdf">the manual</a></figcaption>
</figure>
<figure class="side-by-side">
<img src="/images/spectrograph_step3.jpg">
<figcaption>Step 2: Cut out all holes</figcaption>
</figure><figure class="side-by-side">
<img src="/images/spectrograph_step4_complete.jpg">
<figcaption>The finished result with the back side showing. The viewing window is on the bottom of the other
side.</figcaption>
</figure>
</figure>
Now that I had a spectrograph, I needed a somewhat predictable way of measuring the spectrum it gave me.
@ -121,7 +179,7 @@ Pointing a camera at the spectrograph would be the obvious thing to do. This pro
flaw: I wanted to acquire quantitative measurements of brightness across the spectrum. Since I don't have a precise
technical datasheet specifying the spectral response of any of my cameras I can't compare the absolute brightness of
different colors on their pictures. Some other sensor was needed.
.. FIXME: Spectrum picture
.. FIXME Spectrum picture
Measuring light intensity
~~~~~~~~~~~~~~~~~~~~~~~~~
@ -150,7 +208,38 @@ rejection and a regular non-inverting amplifier using another op-amp from the sa
transimpedance amplifier output. I put all the passives setting amplifier response (the gain-setting resistors and the
filter resistor and capacitors) on a small removable adapter so I could easily change them if necessary. I put a small
trimpot on the virtual ground both amplifers use as a reference so I could trim that if necessary.
.. FIXME: Add transimp amp schematic and build pics
.. raw:: html
<figure>
<img src="/images/preamp_schematic.jpg" alt="A drawing of the photodiode preamplifier's schematic">
<figcaption>The photodiode preamplifier schematic. Schematic drawn with an unlicensed copy of
DaveCAD.</figcaption>
</figure>
Following are pictures of the preamplifier board. The connectors on the top-left side are two copies of the analog
signal for the ADC and a small panel meter. The SMA connector is used as the photodiode input since coax cables are
generally low-leakage and have built-in shielding. The circuit is powered via the micro-USB connector and the analog
ground bias voltage can be adjusted using the trimpot.
For easy replacement, all passives setting gain and frequency response are on a small, pluggable carrier PCB made from a
SMD-to-DIP adapter.
Flying-wire construction is just fine for this low-frequency circuit. In a high-speed photodiode preamp, the
transimpedance amplifier circuit would be highly sensitive to stray capacitance, but we're not aiming at high speed
here.
.. raw:: html
<figure>
<figure class="side-by-side">
<img src="/images/preamp_front.jpg">
<figcaption>The front side of the preamplifier board.</figcaption>
</figure><figure class="side-by-side">
<img src="/images/preamp_back.jpg">
<figcaption>The wiring of the photodiode preamp.</figcaption>
</figure>
</figure>
Given a way to measure intensity what remains missing is a way to scan a single photodiode across the spectrum.
@ -164,8 +253,6 @@ was an `A4988`_ module that required at least 8V motor drive voltage. I used a s
module to generate a stable 10V supply for the motor driver, with the USB's 5V rail used as a logic supply for the motor
driver.
.. FIXME: Add picture of photodiode stage here
The `SFH2701`_ can easily be mounted to the linear stage using a small SMD breakout board glued in place with thin wires
connecting it to the transimpedance amplifier. The DVD drive linear stage is not very strong so it is important that
this wire does not put too much strain on it.
@ -176,7 +263,20 @@ parallel to the linear stage allowing precise alignment.
The whole unit with photodiode preamplifier, linear stage, photodiode and stepper motor driver finally looks like this:
.. FIXME: pics of linear stage unit electronics
.. raw:: html
<figure>
<img src="/images/electronics_whole.jpg" alt="The complete electronics setup of the spectrograph. In the back
there is the DVD drive stepper stage. In front of it, mounted on a piece of wood are a small USB-to-12V
switching-regulator module to power the stepper motor in the top left, below on the bottom left is the
photodiode preamp and on the right is a breadboard with the stepper driver module and lots of jumper wires
interconnecting everything. On the right of the breadboard, a buspirate is attached to interface everything to a
computer. On the bottom edge of the piece of wood, two LED panel meters are mounted for readout of the preamp
output and the stepper supply voltages.">
<figcaption>The complete electronics setup. The buspirate on the right interfaces to a computer and controls the
stepper driver and ADC'es the preamp output. The two panel meters show the preamp output and stepper voltage for
setup.</figcaption>
</figure>
The projection of the spectrum can be adjusted by moving the light source relative to the entry slot and by moving
around the grating DVD.
@ -211,6 +311,8 @@ check for when I made some mistake easy to spot in the resulting data.
After one color channel is captured, the LED tape has to be manually set to the next color and the next measurement can
begin.
.. FIXME raw measurement plot
Data analysis
~~~~~~~~~~~~~
@ -244,7 +346,9 @@ estimate is produced by a least-squares fit of a linear function. This fine esti
sensitivity correction of all original measurements and the scale is changed from stepper motor step count to
wavelength in nanometers.
.. FIXME: calibration for brightness imbalance due to wedge-shaped projection of spectrum
.. FIXME processed spectrum plot
.. FIXME calibration for brightness imbalance due to wedge-shaped projection of spectrum
Color space mapping
*******************
@ -258,31 +362,58 @@ The result are three color coordinates X, Y and Z for each channel R, G and B yi
written as a matrix conversion between XYZ color space and LED-RGB color space is as simple as multiplying that matrix
(or its inverse) and a vector from one of the color spaces.
If you view the three channels' color coordinates as vectors in XYZ space, the set of colors that can be produced with
this LED tape is described by the `parallelepiped`_ spanned by the three channel vectors.
In XYZ space, the set of colors that can be produced with this LED tape is described by the `parallelepiped`_ spanned by
the three channel's XYZ vectors. In the following figures, you can see a three-dimensional model of the RGB LED's color
space (colorful) as well as sRGB (white) for comparison plotted within CIE 1931 XYZ. There is no natural map to scale
both so for this illustration the LED color space has been scaled to fit. These figures were made with blender and a few
lines of python. The blender project file including all settings and the python script to generate the color space
models can be found in the `project repo`_.
The last task is to decide on a scaling factor to map XYZ space to RGB space. Both are limited to values between 0.0 and
1.0. The LEDs cannot go below off or above fully on. For any LED tape there will be a set of colors that are outside
the range that this tape can produce.
.. raw:: html
A scaling factor can be used to increase the number of XYZ coordinates that can be mapped to RGB colors the tape *can*
produce by stretching the RGB parallelepiped along its major axis. Up to a point the number of possible colors (the
gamut) increases at expense of maximum brightness. When the parallelepiped is stretched far enought for all three
channel vectors to be outside the 1,1,1 XYZ-cube, maximum brightness continues to decrease but the gamut stays constant.
<video width="480" controls loop>
<source src="/video/led_within_srgb_scale=1.0.mkv" type="video/h264">
<source src="/video/led_within_srgb_scale=1.0.webm" type="video/webm">
Your browser does not support the HTML5 video tag.
</video>
`mkv/h264 download </video/led_within_srgb_scale=1.0.mkv>`__/`webm download </video/led_within_srgb_scale=1.0.webm>`__
As you can see, the result is pretty disappointing. The LED's color space parallepiped is very narrow, which is because
the blue channel is much brighter than the other two channels. An easy fix for this is to scale-up the RGB space and
drop any values outside XYZ. The scaling factor is a trade-off between color space coverage and brightness. You can
produce the most colors when you clip all channels to brightness of the weakest channel (green in this case), but that
will make the result very dim. Scaling brightness like that stretches the RGB parallelepiped along its major axis. Up to
a point the number of possible colors (the gamut) increases at expense of maximum brightness. When the parallelepiped is
stretched far enought for all three channel vectors to be outside the 1,1,1 XYZ-cube, maximum brightness continues to
decrease but the gamut stays constant. I don't know a simple scientific way to solve this problem, so I just played
around with a couple of factors and settled on 2.5 as a reasonable compromise. Below is an illustration.
.. raw:: html
<video width="480" controls loop>
<source src="/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv" type="video/h264">
<source src="/video/led_within_srgb_fancy_camera_path_scale=2.5.webm" type="video/webm">
Your browser does not support the HTML5 video tag.
</video>
`mkv/h264 download </video/led_within_srgb_fancy_camera_path_scale=2.5.mkv>`__/`webm download </video/led_within_srgb_fancy_camera_path_scale=2.5.webm>`__
Firmware implementation
-----------------------
In the end, the above measurements yield two matrices: One for mapping XYZ to RGB, and one for mapping RGB to XYZ. I
chose the CIE 1931 XYZ color space as a basis for the firmware because it is most popular. Mapping a color coordinate in
one color space to the other is as simple as performing nine floating-point multiplications and six additions. Mapping
Lab or Lch to RGB is done by first mapping Lab/Lch to XYZ, then XYZ to RGB. Lab to XYZ is somewhat complex since it
requires a floating-point power for gamma correction, but any self-respecting libc will have one of those so this is
still no problem. Lch also requires floating-point sine and cosine functions, but these should still be no problem on
most hardware.
In the end, the above measurements yield two matrices: One for mapping XYZ to RGB, and one for mapping RGB to XYZ. Of
the several versions of CIE XYZ I chose the CIE 1931 XYZ color space as a basis for the firmware because it is most
popular. Mapping a color coordinate in one color space to the other is as simple as performing nine floating-point
multiplications and six additions. Mapping Lab or Lch to RGB is done by first mapping Lab/Lch to XYZ, then XYZ to RGB.
Lab to XYZ is somewhat complex since it requires a floating-point power for gamma correction, but any self-respecting
libc will have one of those so this is still no problem. Lch also requires floating-point sine and cosine functions, but
these should still be no problem on most hardware.
My implementation of these conversions in the ESP8266 firmware of my `Wifi LED driver`_ can be found `on Github`_.
.. _`on Github`: https://github.com/jaseg/esp_led_drv/blob/master/user/led_controller.c
.. _`project repo`: https://github.com/jaseg/led_drv
.. _`Wifi LED driver`: {{<ref "posts/wifi-led-driver.rst">}}
.. _`small driver`: {{<ref "posts/wifi-led-driver.rst">}}
.. _`multichannel LED driver`: {{<ref "posts/multichannel-led-driver.rst">}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

1
themes/hugo-classic Submodule

@ -0,0 +1 @@
Subproject commit e28d1cb6083bbe0be304650ec1122b4be7862a97