THE PROBLEM:

Here is a comparison for forward voltage and luminosity (mcd) at 20mA for an 0603 green LED that might be used for indicators, note the variance in forward voltage and the amount of light produced.  There are also variations between different components from the same manufacturer!  So picking 10mA isn't always a good option for designing indicators. 

Our eyes have a logarithmic response to light.  

Source: https://www.telescope-optics.net/eye_intensity_response.htm

LED I-V curve is non linear.  

SOLUTION:

Design a device that lets you adjust the luminosity of the LED while showing all the measurements at that brightness for whatever system voltage I'm working with.  Simply put, light an LED, dim it and measure for the current to determine the current limiting resistor for a given system voltage. 

The Analog Dimming Circuit:

The original circuit was designed built around the Analog Devices LT3085 (diagram below) to provide the constant current dimming circuit.  It worked well but was expensive and since it's integrated, limited to what can be done with it.

So I designed my own constant current dimming circuit. 

The final design is within 70PPM error between 10-80C, utilizing a thermally compensated JFET current source. 

The LED forward voltage measurement is within 0.5% (<= 0.016V of 3.27V forward voltage and usually within 0.01V!) of my calibrated FLUKE 87!  To provide a margin of error I claim 1%. 

The curve is linear for the entire throw of the dimming potentiometer.  

To simulate the changing resistance in LTSpice.  Place a formula like this in the RESISTANCE field:    R=100k-(100k*time)

PRECISION Measurements:

The measurement is achieved by measuring the LED voltage against the 5V reference.   In order to maximize resolution a 30Ω, 0.1% shunt is measured against the 1.1V internal bandgap reference.  Since bandgaps can have variations in manufacturing (+/-10%), the bandgap is compared and calibrated against the 5V reference given by a precision 5V LDO at AVCC.  This ensure that there's no drift and that each device stays calibrated out of the box and over time.  Once calibrated, the bandgap reference provides precise measurements.

Parameter Value
ADC reference 1.1 V (nom)
Resolution 14-bit  (16,384 steps)
Shunt resistor 30 Ω,  0.1%,  25ppm/C             
Voltage LSB 67.14 µV
Current LSB 2.24 µA
Full-scale current 36.67 mA
25 mA utilization 68.2% of range

Putting it all together:

I am not a mechanical engineer.  My work on Solidworks seems to be more time-consuming than productive.  I used tinkercad to generate the 3D printed case.  It took about 5 tries to get everything the way I wanted it.  Apparently this is not a complicated part to get injected molded if it ever becomes a thing.  I will probably have to redesign for molding as the lines are parallel in this model.  I will likely have to redo it in Solidworks. 

This project was challenging in many ways:

1. Originally designed as 2 PCBs sandwiched with standoffs but my wife said it looked unfinished (although I liked the exposed look of it).  This took my usual 2 dimensional design into 3 dimensions and took a few iterations to get right.

2. The analog design is challenging and very touchy.  Many simulations, calculations, and test circuits brought me to this point.

3. To get precision from the ADC required some interesting solutions.  The debugging was fun also. 

4. Final design to improve accuracy and make calibration easy as well as put it into a nice case.

Outtakes :

The journey was long with a lot of mistakes and challenges.  For instance

I was wondering why I was not getting a good reference for the ADC, and it was because I forgot to connect AVCC to the MCU.  I placed a LC filter and it is now referencing an external 5V from an LDO.  

Initially the software caused a lot of headaches.  With INT and FLOAT math with all the divisions, cause a lot of truncation (and later, overflows). I multiplied values to increase the resolution.  Then I needed to create conditional statements to output the correct values... no one wants to see 10000 Ω, so conditional if else statements now show as 10k.

There were so many things I learned along the way it's hard to list them all.  The design keeps improving and hope that one day it gets into the hands of people who can use it to simplify their LED design. 

The results are much better than I had originally intended and it really is a sum of many ideas I've had over the years.