From 24ad9ee7a0a8095d56c330a39321f40dee020dcb Mon Sep 17 00:00:00 2001 From: jaseg Date: Mon, 14 May 2018 00:47:52 +0200 Subject: Content reorg --- content/posts/led-characterization.rst | 491 ---- .../images/daylight_spectrum_dvd.jpg | Bin 0 -> 79150 bytes .../images/driver_ringing_strong.jpg | Bin 0 -> 285952 bytes .../images/driver_ringing_weak.jpg | Bin 0 -> 292100 bytes .../images/electronics_whole.jpg | Bin 0 -> 438776 bytes .../led-characterization/images/hsv_cylinder.png | Bin 0 -> 293981 bytes .../led-characterization/images/preamp_back.jpg | Bin 0 -> 340446 bytes .../led-characterization/images/preamp_front.jpg | Bin 0 -> 308167 bytes .../images/preamp_schematic.jpg | Bin 0 -> 277414 bytes .../images/processed_plot_cheap_rgb.svg | 2366 +++++++++++++++++ .../images/raw_plot_cheap_rgb.svg | 2739 ++++++++++++++++++++ .../posts/led-characterization/images/rgb_cube.svg | 222 ++ .../images/spectrograph_step1_parts.jpg | Bin 0 -> 284254 bytes .../images/spectrograph_step2.jpg | Bin 0 -> 277234 bytes .../images/spectrograph_step3.jpg | Bin 0 -> 256192 bytes .../images/spectrograph_step4_complete.jpg | Bin 0 -> 303777 bytes .../images/zeus_hammer_breadboard.jpg | Bin 0 -> 445768 bytes .../images/zeus_hammer_breadboard_original.jpg | Bin 0 -> 2474273 bytes .../images/zeus_hammer_schematic.jpg | Bin 0 -> 148056 bytes .../images/zeus_hammer_schematic_original.jpg | Bin 0 -> 1893757 bytes content/posts/led-characterization/index.rst | 491 ++++ ...led_within_srgb_fancy_camera_path_scale=2.5.mkv | Bin 0 -> 2676955 bytes ...ed_within_srgb_fancy_camera_path_scale=2.5.webm | Bin 0 -> 1822963 bytes .../video/led_within_srgb_scale=1.0.mkv | Bin 0 -> 1223799 bytes .../video/led_within_srgb_scale=1.0.webm | Bin 0 -> 789099 bytes .../video/led_within_srgb_scale=2.5.mkv | Bin 0 -> 1559120 bytes .../video/led_within_srgb_scale=2.5.webm | Bin 0 -> 920089 bytes .../video/led_within_srgb_scale=3.mkv | Bin 0 -> 1709475 bytes .../video/led_within_srgb_scale=3.webm | Bin 0 -> 925593 bytes content/posts/led-characterization/video/sRGB.mkv | Bin 0 -> 1269287 bytes content/posts/led-characterization/video/sRGB.webm | Bin 0 -> 791821 bytes .../posts/led-characterization/video/scale=1.mkv | Bin 0 -> 1011548 bytes .../posts/led-characterization/video/scale=1.webm | Bin 0 -> 758345 bytes .../posts/led-characterization/video/scale=2.5.mkv | Bin 0 -> 1296564 bytes .../led-characterization/video/scale=2.5.webm | Bin 0 -> 882674 bytes .../posts/led-characterization/video/scale=5.mkv | Bin 0 -> 1571645 bytes .../posts/led-characterization/video/scale=5.webm | Bin 0 -> 879476 bytes content/posts/multichannel-led-driver.rst | 6 - content/posts/multichannel-led-driver/index.rst | 5 + content/posts/wifi-led-driver.rst | 6 - content/posts/wifi-led-driver/index.rst | 5 + content/posts/zeus-hammer.rst | 43 - content/posts/zeus-hammer/index.rst | 42 + 43 files changed, 5870 insertions(+), 546 deletions(-) delete mode 100644 content/posts/led-characterization.rst create mode 100644 content/posts/led-characterization/images/daylight_spectrum_dvd.jpg create mode 100644 content/posts/led-characterization/images/driver_ringing_strong.jpg create mode 100644 content/posts/led-characterization/images/driver_ringing_weak.jpg create mode 100644 content/posts/led-characterization/images/electronics_whole.jpg create mode 100644 content/posts/led-characterization/images/hsv_cylinder.png create mode 100644 content/posts/led-characterization/images/preamp_back.jpg create mode 100644 content/posts/led-characterization/images/preamp_front.jpg create mode 100644 content/posts/led-characterization/images/preamp_schematic.jpg create mode 100644 content/posts/led-characterization/images/processed_plot_cheap_rgb.svg create mode 100644 content/posts/led-characterization/images/raw_plot_cheap_rgb.svg create mode 100644 content/posts/led-characterization/images/rgb_cube.svg create mode 100644 content/posts/led-characterization/images/spectrograph_step1_parts.jpg create mode 100644 content/posts/led-characterization/images/spectrograph_step2.jpg create mode 100644 content/posts/led-characterization/images/spectrograph_step3.jpg create mode 100644 content/posts/led-characterization/images/spectrograph_step4_complete.jpg create mode 100644 content/posts/led-characterization/images/zeus_hammer_breadboard.jpg create mode 100644 content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg create mode 100644 content/posts/led-characterization/images/zeus_hammer_schematic.jpg create mode 100644 content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg create mode 100644 content/posts/led-characterization/index.rst create mode 100644 content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv create mode 100644 content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm create mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv create mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm create mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv create mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm create mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=3.mkv create mode 100644 content/posts/led-characterization/video/led_within_srgb_scale=3.webm create mode 100644 content/posts/led-characterization/video/sRGB.mkv create mode 100644 content/posts/led-characterization/video/sRGB.webm create mode 100644 content/posts/led-characterization/video/scale=1.mkv create mode 100644 content/posts/led-characterization/video/scale=1.webm create mode 100644 content/posts/led-characterization/video/scale=2.5.mkv create mode 100644 content/posts/led-characterization/video/scale=2.5.webm create mode 100644 content/posts/led-characterization/video/scale=5.mkv create mode 100644 content/posts/led-characterization/video/scale=5.webm delete mode 100644 content/posts/multichannel-led-driver.rst create mode 100644 content/posts/multichannel-led-driver/index.rst delete mode 100644 content/posts/wifi-led-driver.rst create mode 100644 content/posts/wifi-led-driver/index.rst delete mode 100644 content/posts/zeus-hammer.rst create mode 100644 content/posts/zeus-hammer/index.rst diff --git a/content/posts/led-characterization.rst b/content/posts/led-characterization.rst deleted file mode 100644 index e3c03e6..0000000 --- a/content/posts/led-characterization.rst +++ /dev/null @@ -1,491 +0,0 @@ ---- -title: "Led Characterization" -date: 2018-05-02T11:18:38+02:00 -draft: true ---- - -Preface -------- - -Recently, I have been working on a `small driver`_ for ambient lighting using 12V LED strips like you can get -inexpensively from China. I wanted to be able to just throw one of these somewhere, stick down some LED tape, hook it up -to a small transformer and be able to control it through Wifi. When I was writing the firmware, I noticed that when -fading between different colors, the colors look *all wrong*! This observation led me down a rabbit hole of color -perception and LED peculiarities. - -The idea of the LED driver was that it can be used either with up to eight single-color LED tapes or, much more -interesting, with up to two RGB or RGBW (red-green-blue-white) LED tapes. For ambient lighting high color resolution was -really important so you could dim it down a lot without flickering. I ended up using the same driver stage I used in the -`multichannel LED driver`_ project for its great color resolution and low hardware requirements. - -.. raw:: html - -
- An illustration of the RGB color cube. -
An illustration of the RGB color cube. - Picture by - Maklaan from Wikimedia Commons, - CC-BY-SA 3.0 -
-
- -To make setting colors over Wifi more intuitive I implemented support for HSV colors. RGB is fine for communication -between computers, but I think HSV is easier to work with when manually inputting colors from the command line. RGB is -close to how most monitors, cameras and the human visual apparatus work on a very low level but doesn't match -higher-level human color perception very well. When we describe a color we tend to think in terms of "hue" or -"brightness", and computing a measure of those from RGB values is not easy. - -Colors and Color Spaces ------------------------ - -`Color spaces`_ are a mathematical abstraction of the concept of color. When we say "RGB", most of the time we actually -mean `sRGB`_, a standardized notion of how to map three numbers labelled "red", "green" and "blue" onto a perceived -color. `HSV`_ is an early attempt to more closely align these numbers with our perception. After HSV, a number of other -*perceptual* color spaces such as `XYZ (CIE 1931)`_ and `CIE Lab/LCh`_ were born, further improving this alignment. In -this mathematical model, mapping a color from one color space into another color space is just a coordinate -transformation. - -.. raw:: html - -
- An illustration of the HSV color space as a cylinder. -
An illustration of the HSV color space as a cylinder. - Picture by - SharkD from Wikimedia Commons, - CC-BY-SA 3.0 -
-
- -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 - -
- -
Illustration of the measured sRGB color space within XYZ. The thick, white line is the spectral - locus. - - mkv/h264 download / - webm download -
-
- -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. 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. - -* The precise colors of the red, green and blue channels of the LEDs are unknown. Though the red channel *looks* red, it - 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 - -
-
- Strong ringing on the LED voltage waveform edge at about
-            100% overshoot during about 70% of the cycle time. -
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.
-
- Weak ringing on the LED voltage waveform edge at about 30%
-            overshoot during about 20% of the cycle time. -
Adding a resistor dampened the ringing somewhat, but ultimately it cannot be eliminated - entirely.
-
-
- -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 -magnitudes of the channels in XYZ will be accurate. - -To map any color to the LEDs, the color's XYZ coordinates simply have to be mapped onto the linear coordinate system -produced by these three points within XYZ. LEDs are mostly 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. - -Measuring the spectrum ----------------------- - -In order to compensate for the cheap LED tape's non-ideal performance I had to measure the LED's red, green and blue -channels' spectra. The obvious thing would be to go out and buy a `spectrograph`_, or ask someone to borrow theirs. The -former is kind of expensive, and I did not want to wait two weeks for the thing to arrive. The latter I could probably -not do every time I got new LED tape. Thus the only choice was to build my own. - -Luckily, building your own spectrometer is really easy. The first thing you need is something that splits incident light -into its constituent wavelengths. In professional devices this is called the *`monochromator`_*, since it allows extraction -of small color bands from the spectrum. The second thing is some sort of optics that project the incident light onto a -screen behind the monochromator. In professional devices lenses or curved mirrors are used. In a simple homebrew job a -pinhole as you would use in a `camera obscura`_ does a remarkably nice job. - -For the monochromator component several things could be used. A prism would work, but I did not have any. The -alternative is a `diffraction grating`_. Professional gratings are quite specialized pieces of equipment and thus -rather expensive. Luckily, there is a common household item that works almost as well: A regular CD or DVD. The -microscopic grooves that are used to record data in a CD or DVD work the same as the grooves in a professional -diffraction grating. - -Household spectra ------------------ - -From this starting point, a few seconds on my favorite search engine yielded an `article by two researchers from the -National Science Museum in Tokyo`_ providing a nice blueprint for a simple cardboard-and-DVD construction for use in -classrooms. I replicated their device using a DVD and it worked beautifully. Daylight and several types of small LEDs I -had around did show the expected spectra. Small red, yellow, green, and blue LEDs showed narrow spectra, daylight one -continuous broad one, and white LEDs a continuous broad one with a distinct bright spot in the blue part. The -single-color LED spectra are quite narrow since they are determined by the LED's semiconductor's band gap, which is -specific to the semiconductor used and is quite precise. White LEDs are in fact a blue LED chip covered with a so-called -*phosphor*. This phosphor is not elementary phosphorus but an anorganic compound that absorbs the LED chip's blue light -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. - -.. raw:: html - -
-
- -
The ingredients. The cup of coffee and Madoka Magica DVD set are essential to the eventual - function of the appartus.
-
- -
Step 1: Cut to size and mark down all holes as described in the manual
-
-
- -
Step 2: Cut out all holes
-
- -
The finished result with the back side showing. The viewing window is on the bottom of the other - side.
-
-
- - -Now that I had a spectrograph, I needed a somewhat predictable way of measuring the spectrum it gave me. - -Measuring a spectrum --------------------- - -Pointing a camera at the spectrograph would be the obvious thing to do. This produces pretty images but has one critical -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. - -.. raw:: html - -
- -
The daylight spectrum as seen using a DVD as a grating. - Picture by - Xofc from Wikimedia Commons, - CC-BY-SA 4.0 -
-
- - -Measuring light intensity -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Looking around my lab, I found a bag of `SFH2701`_ visible-light photodiodes. Their -datasheet includes their spectral response so I can compensate for that, allowing precise-ish absolute intensity -measurements. Just like LEDs, photodiodes are extremely linear across several orders of magnitude. The datasheet of the -classic `BPW34`_ photodiode shows that this photodiode's light current is exactly proportional to illuminance over at -least three orders of magnitude. The `SFH2701`_ datasheet does not include a similar graph but its performance will be -similar. The `SFH2701`_ photodiodes I had at hand were perfect for the job compared to the vintage `BPW34`_ since their -active sensing area is really small (0.6mm by 0.6mm) compared to the BPW34 (a whopping 3mm by 3mm). If I were to use a -`BPW34`_ I would have to insert some small apterture in front of it so it does not catch too broad a part of the -spectrum at once. The `SFH2701`_ is small enough that if I just point it at the projected spectrum directly I will -already get only a small part of the spectrum inside its 0.6mm active area. - -To convert the photodiode's tiny photocurrent into a measurable voltage I built another copy of the `transimpedance -amplifier`_ circuit I already used in the `multichannel LED driver`_. A `transimpedance amplifier`_ is an -amplifiert that produces a large voltage from a small current. The weird name comes from the fact that it works kind of -like an amplified resistor (which can be generalized as an *impedance* electrically). Apply a current to a resistor and -you get a voltage. A transimpedance amplifiert does the same with the difference that its input always stays at 0V, -making it look like an ideal current sink to the connected current source. - -Transimpedance amplifiers are common in optoelectronics to convert small photocurrents to voltages. In this instance I -built a very simple circuit with a dampened transimpedance amplifier stage followed by a simple RC filter for noise -rejection and a regular non-inverting amplifier using another op-amp from the same chip to further boost the filtered -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. - -.. raw:: html - -
- A drawing of the photodiode preamplifier's schematic -
The photodiode preamplifier schematic. Schematic drawn with an unlicensed copy of - DaveCAD.
-
- -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 - -
-
- -
The front side of the preamplifier board.
-
- -
The wiring of the photodiode preamp.
-
-
- -Given a way to measure intensity what remains missing is a way to scan a single photodiode across the spectrum. - -Scanning the projection -~~~~~~~~~~~~~~~~~~~~~~~ - -A cheap linear stage can be found in any old CD or DVD drive. These drives use a small linear stage based on a -stepper-driven screw to move the laser unit radially. Removing the laser unit and connecting a leftover stepper driver -module I was left with a small linear stage with about 45 steps per cm without microstepping enabled. The driver I used -was an `A4988`_ module that required at least 8V motor drive voltage. I used a small micro USB-input boost converter -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. - -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. - -Above the photodiode, I mounted a small piece of paper on the linear stage to be used as a projection screen to align -the linear stage in front of the spectrometer viewing window. A line on the screen paper points to the photodiode die in -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: - -.. raw:: html - -
- 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. -
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.
-
- -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. - -The capture process -~~~~~~~~~~~~~~~~~~~ - -To capture a spectrum, first the light source has to be mounted near the spectrograph's entry slot. The LED tape I -tested I just taped face-down directly into it. Next, the grating DVD has to be adjusted to make sure the spectrum -covers a sensible part of the photodiode's path. Mostly, this boils down to adjusting the photodiode distance and height -to match the vertical extent and wiggling the grating DVD to adjust the projection's horizontal position. - -After the optics are set-up, the photodiode preamplifier has to be adjusted. In my experiments, most LED tape at 5GΩ -required a high-ish amplification. The goal in this step is to maximize the peak response of the preamp to be just -shy of its VCC rail to make best use of its dynamic range. To adjust the pre-amp, I took several very coarsely-spaced -measurements to give me an estimate of the peak while I did not yet know its precise location. - -Since stray daylight totally swamped out the weak projection of the LED's spectrum I shielded the entire setup with a -small box made of black cardboard and two black t-shirts on top. This shielding proved adequate for all my measurements -but I had to be careful not to accidentially move the DVD that was stuck into the spectrograph with the shielding -t-shirts. - -For capturing a single spectrum I wrote a small python script that will automatically move the stepper in adjustable -intervals and take two measurements at each point, one with the LED tape off that can be used for offset calibration and -one with the LED tape on. All measurements are stored in a sqlite database that can then be accesssed from other -scripts. - -I built a small script that shows the progress of the current run and an jupyter notebook for data analysis. The jupyter -notebook is capable of live-updating a graph with the in-progress spectrum's data. This was quite useful as a sanity -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. - -.. raw:: html - -
- A plot with three wide peaks, two large peaks on both sides and
-        one smaller one in the middle. The middle one overlaps the two on the sides. The large ones are about 2.5V in
-        amplitude. Overall, the plot is about 300 stepper steps wide with each peak being around 130 steps wide. -
A plot of the raw preamp output voltage versus stepper position. From left to right, the three peaks - are blue, green and red. Step 0 corresponds to the bottommost stepper position and the shortest wavelength. -
-
- - -Data analysis -~~~~~~~~~~~~~ - -Data analysis consists of three major steps: Offset- and stray light removal, wavelength and amplitude calibration and -color space mapping. - -Offset removal -************** -The first task is to remove the offset caused by dark current as well as stray light of the LED's bright primary -reflection on the DVD. The LED is very bright and only a small part of its light gets reflected by the grating towards -the photodiode screen. The remaining part of the light is reflected onto the table in front of the DVD spectrograph. -Though I covered all of this with black cardboard, some of that light ultimately gets reflected onto the photodiode. -This causes a large offset, in particular in the blue part of the spectrum since in this part the photodiode is closest -to the spectrograph's opening. - -The composite offset can be approximated with a second-order polynomial that is fitted to all the data outside of the -main peak's area. Since at this point the wavelength of each data point is still unknown this is done with a rough first -estimate of the three colors' peaks' locations and widths. - -Wavelength- and amplitude calibration -************************************* -The photodiode's response is strongly wavelength-dependent. In particular in the blue band, the photodiode's sensitivity -gets very poor down to about 20% at the edge to ultraviolet. This effect is strong enough to move the apparent location -of the blue peak towards red. - -The problem is that in order to remove this non-linearity, we would already have to know the wavelength of the measured -light. Since I don't, I settled for a two-step process. First, a coarse wavelength calibration is done relative to the -red peak and the short-wavelength edge of the blue peak. The photodiode measurements are then sensitivity-corrected -using this coarse measurement. Then all three channel peaks are measured in the resulting data and a fine wavelength -estimate is produced by a least-squares fit of a linear function. This fine estimate is then used for a second -sensitivity correction of all original measurements and the scale is changed from stepper motor step count to -wavelength in nanometers. - -.. raw:: html - -
- A plot with three wide peaks, all three of different
-        heights. The leftmost peak is highest at 6nA, the middle peak lowest at 1.6nA and the rightmost peak in between
-        at 4nA.  The middle one overlaps the two on the sides.  Overall, the plot spans about 300nm on its x axis with
-        each peak being around 100nm wide. -
A plot of the processed measurements. From left to right, the three peaks are blue, green and red. -
-
- - -.. FIXME re-do these measurements, avoiding clipping -.. FIXME re-do calibration using CCFL -.. FIXME calibration for brightness imbalance due to wedge-shaped projection of spectrum - -Color space mapping -******************* -Finally, to achieve the objective of measuring the LED tape's channels' precise color coordinates the measured spetra -have to be matched against the color spaces' *color matching functions*. The color matching functions describe how -strong the color space's idealized *standard observer* would react to light at a particular wavelength. Going from a -measured spectrum to color coordinates XYZ works by integrating over the product of the measurement and each color -coordinate's color matching function. - -The result are three color coordinates X, Y and Z for each channel R, G and B yielding nine coordinates in total. When -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. - -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`_. - -.. raw:: html - -
- -
Illustration of the measured LED color space scaled to fit within XYZ with sRGB (light gray) for - comparison. The thick, white line is the spectral locus. - - mkv/h264 download / - webm download -
-
- -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 - -
- -
Illustration of the measured LED color space at scale factor 2.5 within XYZ with sRGB (light gray) - for comparison. The thick, white line is the spectral locus. - - mkv/h264 download / - webm download -
-
- -Firmware implementation ------------------------ -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`: {{}} -.. _`small driver`: {{}} -.. _`multichannel LED driver`: {{}} -.. _`sRGB`: https://en.wikipedia.org/wiki/SRGB -.. _`CC BY-SA 3.0`: https://creativecommons.org/licenses/by-sa/3.0 -.. _`Color spaces`: https://en.wikipedia.org/wiki/Color_space -.. _`HSV`: https://en.wikipedia.org/wiki/HSL_and_HSV -.. _`CIE Lab/LCh`: https://en.wikipedia.org/wiki/Lab_color_space -.. _`XYZ (CIE 1931)`: https://en.wikipedia.org/wiki/CIE_1931_color_space -.. _`camera obscura`: https://en.wikipedia.org/wiki/Pinhole_camera -.. _`article by two researchers from the National Science Museum in Tokyo`: http://www.candac.ca/candacweb/sites/default/files/BuildaSpectroscope.pdf -.. _`spectrograph`: https://en.wikipedia.org/wiki/Ultraviolet%E2%80%93visible_spectroscopy -.. _`monochromator`: https://en.wikipedia.org/wiki/Monochromator -.. _`diffraction grating`: https://en.wikipedia.org/wiki/Diffraction_grating -.. _`SFH2701`: https://dammedia.osram.info/media/resource/hires/osram-dam-2495903/SFH%202701.pdf -.. _`BPW34`: http://www.vishay.com/docs/81521/bpw34.pdf -.. _`transimpedance amplifier`: https://en.wikipedia.org/wiki/Transimpedance_amplifier -.. _`A4988`: https://www.pololu.com/file/0J450/A4988.pdf -.. _`parallelepiped`: https://en.wikipedia.org/wiki/Parallelepiped diff --git a/content/posts/led-characterization/images/daylight_spectrum_dvd.jpg b/content/posts/led-characterization/images/daylight_spectrum_dvd.jpg new file mode 100644 index 0000000..d01242e Binary files /dev/null and b/content/posts/led-characterization/images/daylight_spectrum_dvd.jpg differ diff --git a/content/posts/led-characterization/images/driver_ringing_strong.jpg b/content/posts/led-characterization/images/driver_ringing_strong.jpg new file mode 100644 index 0000000..0419a0e Binary files /dev/null and b/content/posts/led-characterization/images/driver_ringing_strong.jpg differ diff --git a/content/posts/led-characterization/images/driver_ringing_weak.jpg b/content/posts/led-characterization/images/driver_ringing_weak.jpg new file mode 100644 index 0000000..12f9c5d Binary files /dev/null and b/content/posts/led-characterization/images/driver_ringing_weak.jpg differ diff --git a/content/posts/led-characterization/images/electronics_whole.jpg b/content/posts/led-characterization/images/electronics_whole.jpg new file mode 100644 index 0000000..faaf751 Binary files /dev/null and b/content/posts/led-characterization/images/electronics_whole.jpg differ diff --git a/content/posts/led-characterization/images/hsv_cylinder.png b/content/posts/led-characterization/images/hsv_cylinder.png new file mode 100644 index 0000000..265f3e0 Binary files /dev/null and b/content/posts/led-characterization/images/hsv_cylinder.png differ diff --git a/content/posts/led-characterization/images/preamp_back.jpg b/content/posts/led-characterization/images/preamp_back.jpg new file mode 100644 index 0000000..0af495d Binary files /dev/null and b/content/posts/led-characterization/images/preamp_back.jpg differ diff --git a/content/posts/led-characterization/images/preamp_front.jpg b/content/posts/led-characterization/images/preamp_front.jpg new file mode 100644 index 0000000..62fad28 Binary files /dev/null and b/content/posts/led-characterization/images/preamp_front.jpg differ diff --git a/content/posts/led-characterization/images/preamp_schematic.jpg b/content/posts/led-characterization/images/preamp_schematic.jpg new file mode 100644 index 0000000..6be7bbd Binary files /dev/null and b/content/posts/led-characterization/images/preamp_schematic.jpg differ diff --git a/content/posts/led-characterization/images/processed_plot_cheap_rgb.svg b/content/posts/led-characterization/images/processed_plot_cheap_rgb.svg new file mode 100644 index 0000000..9745172 --- /dev/null +++ b/content/posts/led-characterization/images/processed_plot_cheap_rgb.svg @@ -0,0 +1,2366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/posts/led-characterization/images/raw_plot_cheap_rgb.svg b/content/posts/led-characterization/images/raw_plot_cheap_rgb.svg new file mode 100644 index 0000000..895569f --- /dev/null +++ b/content/posts/led-characterization/images/raw_plot_cheap_rgb.svg @@ -0,0 +1,2739 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/posts/led-characterization/images/rgb_cube.svg b/content/posts/led-characterization/images/rgb_cube.svg new file mode 100644 index 0000000..8af7a00 --- /dev/null +++ b/content/posts/led-characterization/images/rgb_cube.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + G+ + + + + + + + + R+ + + + + B+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + R- + + + + B- + + + + + + + + G- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + R : 83 + + + G : 150 + + + B : 60 + + G: 150 + B: 60 + R: 83 + + + + + + + + R + G + B + + + R + G + B + + + R 255 + G 255 + B 255 + + + + + \ No newline at end of file diff --git a/content/posts/led-characterization/images/spectrograph_step1_parts.jpg b/content/posts/led-characterization/images/spectrograph_step1_parts.jpg new file mode 100644 index 0000000..107220a Binary files /dev/null and b/content/posts/led-characterization/images/spectrograph_step1_parts.jpg differ diff --git a/content/posts/led-characterization/images/spectrograph_step2.jpg b/content/posts/led-characterization/images/spectrograph_step2.jpg new file mode 100644 index 0000000..b678372 Binary files /dev/null and b/content/posts/led-characterization/images/spectrograph_step2.jpg differ diff --git a/content/posts/led-characterization/images/spectrograph_step3.jpg b/content/posts/led-characterization/images/spectrograph_step3.jpg new file mode 100644 index 0000000..acd6d5e Binary files /dev/null and b/content/posts/led-characterization/images/spectrograph_step3.jpg differ diff --git a/content/posts/led-characterization/images/spectrograph_step4_complete.jpg b/content/posts/led-characterization/images/spectrograph_step4_complete.jpg new file mode 100644 index 0000000..d23560d Binary files /dev/null and b/content/posts/led-characterization/images/spectrograph_step4_complete.jpg differ diff --git a/content/posts/led-characterization/images/zeus_hammer_breadboard.jpg b/content/posts/led-characterization/images/zeus_hammer_breadboard.jpg new file mode 100644 index 0000000..08efebb Binary files /dev/null and b/content/posts/led-characterization/images/zeus_hammer_breadboard.jpg differ diff --git a/content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg b/content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg new file mode 100644 index 0000000..4f8f34e Binary files /dev/null and b/content/posts/led-characterization/images/zeus_hammer_breadboard_original.jpg differ diff --git a/content/posts/led-characterization/images/zeus_hammer_schematic.jpg b/content/posts/led-characterization/images/zeus_hammer_schematic.jpg new file mode 100644 index 0000000..0e6f483 Binary files /dev/null and b/content/posts/led-characterization/images/zeus_hammer_schematic.jpg differ diff --git a/content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg b/content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg new file mode 100644 index 0000000..b50b3a0 Binary files /dev/null and b/content/posts/led-characterization/images/zeus_hammer_schematic_original.jpg differ diff --git a/content/posts/led-characterization/index.rst b/content/posts/led-characterization/index.rst new file mode 100644 index 0000000..0f6e32b --- /dev/null +++ b/content/posts/led-characterization/index.rst @@ -0,0 +1,491 @@ +--- +title: "Led Characterization" +date: 2018-05-02T11:18:38+02:00 +draft: true +--- + +Preface +------- + +Recently, I have been working on a `small driver`_ for ambient lighting using 12V LED strips like you can get +inexpensively from China. I wanted to be able to just throw one of these somewhere, stick down some LED tape, hook it up +to a small transformer and be able to control it through Wifi. When I was writing the firmware, I noticed that when +fading between different colors, the colors look *all wrong*! This observation led me down a rabbit hole of color +perception and LED peculiarities. + +The idea of the LED driver was that it can be used either with up to eight single-color LED tapes or, much more +interesting, with up to two RGB or RGBW (red-green-blue-white) LED tapes. For ambient lighting high color resolution was +really important so you could dim it down a lot without flickering. I ended up using the same driver stage I used in the +`multichannel LED driver`_ project for its great color resolution and low hardware requirements. + +.. raw:: html + +
+ An illustration of the RGB color cube. +
An illustration of the RGB color cube. + Picture by + Maklaan from Wikimedia Commons, + CC-BY-SA 3.0 +
+
+ +To make setting colors over Wifi more intuitive I implemented support for HSV colors. RGB is fine for communication +between computers, but I think HSV is easier to work with when manually inputting colors from the command line. RGB is +close to how most monitors, cameras and the human visual apparatus work on a very low level but doesn't match +higher-level human color perception very well. When we describe a color we tend to think in terms of "hue" or +"brightness", and computing a measure of those from RGB values is not easy. + +Colors and Color Spaces +----------------------- + +`Color spaces`_ are a mathematical abstraction of the concept of color. When we say "RGB", most of the time we actually +mean `sRGB`_, a standardized notion of how to map three numbers labelled "red", "green" and "blue" onto a perceived +color. `HSV`_ is an early attempt to more closely align these numbers with our perception. After HSV, a number of other +*perceptual* color spaces such as `XYZ (CIE 1931)`_ and `CIE Lab/LCh`_ were born, further improving this alignment. In +this mathematical model, mapping a color from one color space into another color space is just a coordinate +transformation. + +.. raw:: html + +
+ An illustration of the HSV color space as a cylinder. +
An illustration of the HSV color space as a cylinder. + Picture by + SharkD from Wikimedia Commons, + CC-BY-SA 3.0 +
+
+ +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 + +
+ +
Illustration of the measured sRGB color space within XYZ. The thick, white line is the spectral + locus. + + mkv/h264 download / + webm download +
+
+ +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. 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. + +* The precise colors of the red, green and blue channels of the LEDs are unknown. Though the red channel *looks* red, it + 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 + +
+
+ Strong ringing on the LED voltage waveform edge at about
+            100% overshoot during about 70% of the cycle time. +
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.
+
+ Weak ringing on the LED voltage waveform edge at about 30%
+            overshoot during about 20% of the cycle time. +
Adding a resistor dampened the ringing somewhat, but ultimately it cannot be eliminated + entirely.
+
+
+ +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 +magnitudes of the channels in XYZ will be accurate. + +To map any color to the LEDs, the color's XYZ coordinates simply have to be mapped onto the linear coordinate system +produced by these three points within XYZ. LEDs are mostly 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. + +Measuring the spectrum +---------------------- + +In order to compensate for the cheap LED tape's non-ideal performance I had to measure the LED's red, green and blue +channels' spectra. The obvious thing would be to go out and buy a `spectrograph`_, or ask someone to borrow theirs. The +former is kind of expensive, and I did not want to wait two weeks for the thing to arrive. The latter I could probably +not do every time I got new LED tape. Thus the only choice was to build my own. + +Luckily, building your own spectrometer is really easy. The first thing you need is something that splits incident light +into its constituent wavelengths. In professional devices this is called the *`monochromator`_*, since it allows extraction +of small color bands from the spectrum. The second thing is some sort of optics that project the incident light onto a +screen behind the monochromator. In professional devices lenses or curved mirrors are used. In a simple homebrew job a +pinhole as you would use in a `camera obscura`_ does a remarkably nice job. + +For the monochromator component several things could be used. A prism would work, but I did not have any. The +alternative is a `diffraction grating`_. Professional gratings are quite specialized pieces of equipment and thus +rather expensive. Luckily, there is a common household item that works almost as well: A regular CD or DVD. The +microscopic grooves that are used to record data in a CD or DVD work the same as the grooves in a professional +diffraction grating. + +Household spectra +----------------- + +From this starting point, a few seconds on my favorite search engine yielded an `article by two researchers from the +National Science Museum in Tokyo`_ providing a nice blueprint for a simple cardboard-and-DVD construction for use in +classrooms. I replicated their device using a DVD and it worked beautifully. Daylight and several types of small LEDs I +had around did show the expected spectra. Small red, yellow, green, and blue LEDs showed narrow spectra, daylight one +continuous broad one, and white LEDs a continuous broad one with a distinct bright spot in the blue part. The +single-color LED spectra are quite narrow since they are determined by the LED's semiconductor's band gap, which is +specific to the semiconductor used and is quite precise. White LEDs are in fact a blue LED chip covered with a so-called +*phosphor*. This phosphor is not elementary phosphorus but an anorganic compound that absorbs the LED chip's blue light +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. + +.. raw:: html + +
+
+ +
The ingredients. The cup of coffee and Madoka Magica DVD set are essential to the eventual + function of the appartus.
+
+ +
Step 1: Cut to size and mark down all holes as described in the manual
+
+
+ +
Step 2: Cut out all holes
+
+ +
The finished result with the back side showing. The viewing window is on the bottom of the other + side.
+
+
+ + +Now that I had a spectrograph, I needed a somewhat predictable way of measuring the spectrum it gave me. + +Measuring a spectrum +-------------------- + +Pointing a camera at the spectrograph would be the obvious thing to do. This produces pretty images but has one critical +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. + +.. raw:: html + +
+ +
The daylight spectrum as seen using a DVD as a grating. + Picture by + Xofc from Wikimedia Commons, + CC-BY-SA 4.0 +
+
+ + +Measuring light intensity +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Looking around my lab, I found a bag of `SFH2701`_ visible-light photodiodes. Their +datasheet includes their spectral response so I can compensate for that, allowing precise-ish absolute intensity +measurements. Just like LEDs, photodiodes are extremely linear across several orders of magnitude. The datasheet of the +classic `BPW34`_ photodiode shows that this photodiode's light current is exactly proportional to illuminance over at +least three orders of magnitude. The `SFH2701`_ datasheet does not include a similar graph but its performance will be +similar. The `SFH2701`_ photodiodes I had at hand were perfect for the job compared to the vintage `BPW34`_ since their +active sensing area is really small (0.6mm by 0.6mm) compared to the BPW34 (a whopping 3mm by 3mm). If I were to use a +`BPW34`_ I would have to insert some small apterture in front of it so it does not catch too broad a part of the +spectrum at once. The `SFH2701`_ is small enough that if I just point it at the projected spectrum directly I will +already get only a small part of the spectrum inside its 0.6mm active area. + +To convert the photodiode's tiny photocurrent into a measurable voltage I built another copy of the `transimpedance +amplifier`_ circuit I already used in the `multichannel LED driver`_. A `transimpedance amplifier`_ is an +amplifiert that produces a large voltage from a small current. The weird name comes from the fact that it works kind of +like an amplified resistor (which can be generalized as an *impedance* electrically). Apply a current to a resistor and +you get a voltage. A transimpedance amplifiert does the same with the difference that its input always stays at 0V, +making it look like an ideal current sink to the connected current source. + +Transimpedance amplifiers are common in optoelectronics to convert small photocurrents to voltages. In this instance I +built a very simple circuit with a dampened transimpedance amplifier stage followed by a simple RC filter for noise +rejection and a regular non-inverting amplifier using another op-amp from the same chip to further boost the filtered +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. + +.. raw:: html + +
+ A drawing of the photodiode preamplifier's schematic +
The photodiode preamplifier schematic. Schematic drawn with an unlicensed copy of + DaveCAD.
+
+ +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 + +
+
+ +
The front side of the preamplifier board.
+
+ +
The wiring of the photodiode preamp.
+
+
+ +Given a way to measure intensity what remains missing is a way to scan a single photodiode across the spectrum. + +Scanning the projection +~~~~~~~~~~~~~~~~~~~~~~~ + +A cheap linear stage can be found in any old CD or DVD drive. These drives use a small linear stage based on a +stepper-driven screw to move the laser unit radially. Removing the laser unit and connecting a leftover stepper driver +module I was left with a small linear stage with about 45 steps per cm without microstepping enabled. The driver I used +was an `A4988`_ module that required at least 8V motor drive voltage. I used a small micro USB-input boost converter +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. + +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. + +Above the photodiode, I mounted a small piece of paper on the linear stage to be used as a projection screen to align +the linear stage in front of the spectrometer viewing window. A line on the screen paper points to the photodiode die in +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: + +.. raw:: html + +
+ 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. +
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.
+
+ +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. + +The capture process +~~~~~~~~~~~~~~~~~~~ + +To capture a spectrum, first the light source has to be mounted near the spectrograph's entry slot. The LED tape I +tested I just taped face-down directly into it. Next, the grating DVD has to be adjusted to make sure the spectrum +covers a sensible part of the photodiode's path. Mostly, this boils down to adjusting the photodiode distance and height +to match the vertical extent and wiggling the grating DVD to adjust the projection's horizontal position. + +After the optics are set-up, the photodiode preamplifier has to be adjusted. In my experiments, most LED tape at 5GΩ +required a high-ish amplification. The goal in this step is to maximize the peak response of the preamp to be just +shy of its VCC rail to make best use of its dynamic range. To adjust the pre-amp, I took several very coarsely-spaced +measurements to give me an estimate of the peak while I did not yet know its precise location. + +Since stray daylight totally swamped out the weak projection of the LED's spectrum I shielded the entire setup with a +small box made of black cardboard and two black t-shirts on top. This shielding proved adequate for all my measurements +but I had to be careful not to accidentially move the DVD that was stuck into the spectrograph with the shielding +t-shirts. + +For capturing a single spectrum I wrote a small python script that will automatically move the stepper in adjustable +intervals and take two measurements at each point, one with the LED tape off that can be used for offset calibration and +one with the LED tape on. All measurements are stored in a sqlite database that can then be accesssed from other +scripts. + +I built a small script that shows the progress of the current run and an jupyter notebook for data analysis. The jupyter +notebook is capable of live-updating a graph with the in-progress spectrum's data. This was quite useful as a sanity +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. + +.. raw:: html + +
+ A plot with three wide peaks, two large peaks on both sides and
+        one smaller one in the middle. The middle one overlaps the two on the sides. The large ones are about 2.5V in
+        amplitude. Overall, the plot is about 300 stepper steps wide with each peak being around 130 steps wide. +
A plot of the raw preamp output voltage versus stepper position. From left to right, the three peaks + are blue, green and red. Step 0 corresponds to the bottommost stepper position and the shortest wavelength. +
+
+ + +Data analysis +~~~~~~~~~~~~~ + +Data analysis consists of three major steps: Offset- and stray light removal, wavelength and amplitude calibration and +color space mapping. + +Offset removal +************** +The first task is to remove the offset caused by dark current as well as stray light of the LED's bright primary +reflection on the DVD. The LED is very bright and only a small part of its light gets reflected by the grating towards +the photodiode screen. The remaining part of the light is reflected onto the table in front of the DVD spectrograph. +Though I covered all of this with black cardboard, some of that light ultimately gets reflected onto the photodiode. +This causes a large offset, in particular in the blue part of the spectrum since in this part the photodiode is closest +to the spectrograph's opening. + +The composite offset can be approximated with a second-order polynomial that is fitted to all the data outside of the +main peak's area. Since at this point the wavelength of each data point is still unknown this is done with a rough first +estimate of the three colors' peaks' locations and widths. + +Wavelength- and amplitude calibration +************************************* +The photodiode's response is strongly wavelength-dependent. In particular in the blue band, the photodiode's sensitivity +gets very poor down to about 20% at the edge to ultraviolet. This effect is strong enough to move the apparent location +of the blue peak towards red. + +The problem is that in order to remove this non-linearity, we would already have to know the wavelength of the measured +light. Since I don't, I settled for a two-step process. First, a coarse wavelength calibration is done relative to the +red peak and the short-wavelength edge of the blue peak. The photodiode measurements are then sensitivity-corrected +using this coarse measurement. Then all three channel peaks are measured in the resulting data and a fine wavelength +estimate is produced by a least-squares fit of a linear function. This fine estimate is then used for a second +sensitivity correction of all original measurements and the scale is changed from stepper motor step count to +wavelength in nanometers. + +.. raw:: html + +
+ A plot with three wide peaks, all three of different
+        heights. The leftmost peak is highest at 6nA, the middle peak lowest at 1.6nA and the rightmost peak in between
+        at 4nA.  The middle one overlaps the two on the sides.  Overall, the plot spans about 300nm on its x axis with
+        each peak being around 100nm wide. +
A plot of the processed measurements. From left to right, the three peaks are blue, green and red. +
+
+ + +.. FIXME re-do these measurements, avoiding clipping +.. FIXME re-do calibration using CCFL +.. FIXME calibration for brightness imbalance due to wedge-shaped projection of spectrum + +Color space mapping +******************* +Finally, to achieve the objective of measuring the LED tape's channels' precise color coordinates the measured spetra +have to be matched against the color spaces' *color matching functions*. The color matching functions describe how +strong the color space's idealized *standard observer* would react to light at a particular wavelength. Going from a +measured spectrum to color coordinates XYZ works by integrating over the product of the measurement and each color +coordinate's color matching function. + +The result are three color coordinates X, Y and Z for each channel R, G and B yielding nine coordinates in total. When +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. + +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`_. + +.. raw:: html + +
+ +
Illustration of the measured LED color space scaled to fit within XYZ with sRGB (light gray) for + comparison. The thick, white line is the spectral locus. + + mkv/h264 download / + webm download +
+
+ +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 + +
+ +
Illustration of the measured LED color space at scale factor 2.5 within XYZ with sRGB (light gray) + for comparison. The thick, white line is the spectral locus. + + mkv/h264 download / + webm download +
+
+ +Firmware implementation +----------------------- +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`: {{}} +.. _`small driver`: {{}} +.. _`multichannel LED driver`: {{}} +.. _`sRGB`: https://en.wikipedia.org/wiki/SRGB +.. _`CC BY-SA 3.0`: https://creativecommons.org/licenses/by-sa/3.0 +.. _`Color spaces`: https://en.wikipedia.org/wiki/Color_space +.. _`HSV`: https://en.wikipedia.org/wiki/HSL_and_HSV +.. _`CIE Lab/LCh`: https://en.wikipedia.org/wiki/Lab_color_space +.. _`XYZ (CIE 1931)`: https://en.wikipedia.org/wiki/CIE_1931_color_space +.. _`camera obscura`: https://en.wikipedia.org/wiki/Pinhole_camera +.. _`article by two researchers from the National Science Museum in Tokyo`: http://www.candac.ca/candacweb/sites/default/files/BuildaSpectroscope.pdf +.. _`spectrograph`: https://en.wikipedia.org/wiki/Ultraviolet%E2%80%93visible_spectroscopy +.. _`monochromator`: https://en.wikipedia.org/wiki/Monochromator +.. _`diffraction grating`: https://en.wikipedia.org/wiki/Diffraction_grating +.. _`SFH2701`: https://dammedia.osram.info/media/resource/hires/osram-dam-2495903/SFH%202701.pdf +.. _`BPW34`: http://www.vishay.com/docs/81521/bpw34.pdf +.. _`transimpedance amplifier`: https://en.wikipedia.org/wiki/Transimpedance_amplifier +.. _`A4988`: https://www.pololu.com/file/0J450/A4988.pdf +.. _`parallelepiped`: https://en.wikipedia.org/wiki/Parallelepiped diff --git a/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv b/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv new file mode 100644 index 0000000..0a1eece Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.mkv differ diff --git a/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm b/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm new file mode 100644 index 0000000..04d355c Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_fancy_camera_path_scale=2.5.webm differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv b/content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv new file mode 100644 index 0000000..69dfccf Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_scale=1.0.mkv differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm b/content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm new file mode 100644 index 0000000..8034882 Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_scale=1.0.webm differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv b/content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv new file mode 100644 index 0000000..a7fba0b Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_scale=2.5.mkv differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm b/content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm new file mode 100644 index 0000000..d0c9135 Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_scale=2.5.webm differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=3.mkv b/content/posts/led-characterization/video/led_within_srgb_scale=3.mkv new file mode 100644 index 0000000..94c7750 Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_scale=3.mkv differ diff --git a/content/posts/led-characterization/video/led_within_srgb_scale=3.webm b/content/posts/led-characterization/video/led_within_srgb_scale=3.webm new file mode 100644 index 0000000..3dc88cc Binary files /dev/null and b/content/posts/led-characterization/video/led_within_srgb_scale=3.webm differ diff --git a/content/posts/led-characterization/video/sRGB.mkv b/content/posts/led-characterization/video/sRGB.mkv new file mode 100644 index 0000000..903c719 Binary files /dev/null and b/content/posts/led-characterization/video/sRGB.mkv differ diff --git a/content/posts/led-characterization/video/sRGB.webm b/content/posts/led-characterization/video/sRGB.webm new file mode 100644 index 0000000..737cc1b Binary files /dev/null and b/content/posts/led-characterization/video/sRGB.webm differ diff --git a/content/posts/led-characterization/video/scale=1.mkv b/content/posts/led-characterization/video/scale=1.mkv new file mode 100644 index 0000000..410896e Binary files /dev/null and b/content/posts/led-characterization/video/scale=1.mkv differ diff --git a/content/posts/led-characterization/video/scale=1.webm b/content/posts/led-characterization/video/scale=1.webm new file mode 100644 index 0000000..dc599be Binary files /dev/null and b/content/posts/led-characterization/video/scale=1.webm differ diff --git a/content/posts/led-characterization/video/scale=2.5.mkv b/content/posts/led-characterization/video/scale=2.5.mkv new file mode 100644 index 0000000..6ff3619 Binary files /dev/null and b/content/posts/led-characterization/video/scale=2.5.mkv differ diff --git a/content/posts/led-characterization/video/scale=2.5.webm b/content/posts/led-characterization/video/scale=2.5.webm new file mode 100644 index 0000000..6a6a860 Binary files /dev/null and b/content/posts/led-characterization/video/scale=2.5.webm differ diff --git a/content/posts/led-characterization/video/scale=5.mkv b/content/posts/led-characterization/video/scale=5.mkv new file mode 100644 index 0000000..b4e7e65 Binary files /dev/null and b/content/posts/led-characterization/video/scale=5.mkv differ diff --git a/content/posts/led-characterization/video/scale=5.webm b/content/posts/led-characterization/video/scale=5.webm new file mode 100644 index 0000000..0298a11 Binary files /dev/null and b/content/posts/led-characterization/video/scale=5.webm differ diff --git a/content/posts/multichannel-led-driver.rst b/content/posts/multichannel-led-driver.rst deleted file mode 100644 index 181fb63..0000000 --- a/content/posts/multichannel-led-driver.rst +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Multichannel Led Driver" -date: 2018-05-02T11:31:14+02:00 -draft: true ---- - diff --git a/content/posts/multichannel-led-driver/index.rst b/content/posts/multichannel-led-driver/index.rst new file mode 100644 index 0000000..ff8930e --- /dev/null +++ b/content/posts/multichannel-led-driver/index.rst @@ -0,0 +1,5 @@ +--- +title: "Multichannel Led Driver" +date: 2018-05-02T11:31:14+02:00 +--- + diff --git a/content/posts/wifi-led-driver.rst b/content/posts/wifi-led-driver.rst deleted file mode 100644 index 1c83de5..0000000 --- a/content/posts/wifi-led-driver.rst +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Wifi Led Driver" -date: 2018-05-02T11:31:03+02:00 -draft: true ---- - diff --git a/content/posts/wifi-led-driver/index.rst b/content/posts/wifi-led-driver/index.rst new file mode 100644 index 0000000..0279457 --- /dev/null +++ b/content/posts/wifi-led-driver/index.rst @@ -0,0 +1,5 @@ +--- +title: "Wifi Led Driver" +date: 2018-05-02T11:31:03+02:00 +--- + diff --git a/content/posts/zeus-hammer.rst b/content/posts/zeus-hammer.rst deleted file mode 100644 index d2a2eec..0000000 --- a/content/posts/zeus-hammer.rst +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Zeus Hammer" -date: 2018-05-03T11:59:37+02:00 -draft: true ---- - -In case you were having an inferiority complex because your friends' IBM Model M keyboards are so much louder than the -shitty rubber dome freebie you got with your pc... Here's the solution: Zeus Hammer, a simple typing cadence enhancer -for `PS/2`_ keyboards. - -.. FIXME: add demo video - -The connects to the keyboard's PS/2 clock line and briefly actuates a large solenoid on each key press. An interesting -fact about PS/2 is that the clock line is only active as long as either the host computer or the input device actually -want to send data. In case of a keyboard that's the case when a key is pressed or when the host changes the keyboard's -LED state, otherwise the clock line is silent. We ignore the LED activity for now as it's generally coupled to key -presses. By just triggering an NE555 configured as astable flipflop we can stretch each train of clock pulses to a -pulse a few tens of milliseconds long that is enough to actuate the solenoid. - -.. image:: /images/zeus_hammer_schematic.jpg - -Since PS/2 sends each key press and key release separately this circuit will pulse twice per keystroke. It would be -possible to ignore one of them but I figure the added noise just adds to the experience. - -Built on a breadboard, the circuit looks like this. - -.. image:: /images/zeus_hammer_breadboard.jpg - -The completed system looks like this. - -.. FIXME: add image of completed system - -Since my solenoid did not have a tensioning spring I used a rubber band and some vinyl tape to make an adjustable -tensioner. The small orange USB hub serves as an end-stop because I had nothing else of the right shape. The sound and -resonance of the thing can be adjusted to taste by moving the end stop, adjusting the tensioning rubber and tuning the -excitation duration using the potentiometer. My particular solenoid was a bit slow so I added some pieces of circuit -board as shims between the plunger and the case to limit the plunger's travel inside the solenoid core. Here is another -video of the thing in action in which I tune and de-tune the mechanical resonance using the potentiometer. - -.. FIXME: add video w/ tune/detune - -.. _`PS/2`: https://en.wikipedia.org/wiki/PS/2_port - diff --git a/content/posts/zeus-hammer/index.rst b/content/posts/zeus-hammer/index.rst new file mode 100644 index 0000000..6865bdb --- /dev/null +++ b/content/posts/zeus-hammer/index.rst @@ -0,0 +1,42 @@ +--- +title: "Zeus Hammer" +date: 2018-05-03T11:59:37+02:00 +--- + +In case you were having an inferiority complex because your friends' IBM Model M keyboards are so much louder than the +shitty rubber dome freebie you got with your pc... Here's the solution: Zeus Hammer, a simple typing cadence enhancer +for `PS/2`_ keyboards. + +.. FIXME: add demo video + +The connects to the keyboard's PS/2 clock line and briefly actuates a large solenoid on each key press. An interesting +fact about PS/2 is that the clock line is only active as long as either the host computer or the input device actually +want to send data. In case of a keyboard that's the case when a key is pressed or when the host changes the keyboard's +LED state, otherwise the clock line is silent. We ignore the LED activity for now as it's generally coupled to key +presses. By just triggering an NE555 configured as astable flipflop we can stretch each train of clock pulses to a +pulse a few tens of milliseconds long that is enough to actuate the solenoid. + +.. image:: /images/zeus_hammer_schematic.jpg + +Since PS/2 sends each key press and key release separately this circuit will pulse twice per keystroke. It would be +possible to ignore one of them but I figure the added noise just adds to the experience. + +Built on a breadboard, the circuit looks like this. + +.. image:: /images/zeus_hammer_breadboard.jpg + +The completed system looks like this. + +.. FIXME: add image of completed system + +Since my solenoid did not have a tensioning spring I used a rubber band and some vinyl tape to make an adjustable +tensioner. The small orange USB hub serves as an end-stop because I had nothing else of the right shape. The sound and +resonance of the thing can be adjusted to taste by moving the end stop, adjusting the tensioning rubber and tuning the +excitation duration using the potentiometer. My particular solenoid was a bit slow so I added some pieces of circuit +board as shims between the plunger and the case to limit the plunger's travel inside the solenoid core. Here is another +video of the thing in action in which I tune and de-tune the mechanical resonance using the potentiometer. + +.. FIXME: add video w/ tune/detune + +.. _`PS/2`: https://en.wikipedia.org/wiki/PS/2_port + -- cgit