logarithmic voltage

fernando_g

Senior Member
I've found this wonderful little IC, Sharp's GA1A1S201WP logarithmic light sensor.
There are breakout boards available, too.

Its logarithmic voltage output means that it can cover a range from about 3 to 50,000 lux without a scale change.
FYI, 50,000 lux is what I've measured in the south Texas desert at noon...it is a very bright light.

But here lies the problem....how to convert that logarithmic voltage into a lux value with a Picaxe?

And no, I don't expect that if I'm in the 10,000 lux range, to have a resolution of 1 lux.............that would be completely preposterous.
 

Attachments

premelec

Senior Member
it has a log / linear converter so you might just choose ranges appropriate to the linear reading - just what are you trying to do? TAOS had a bunch of light sense units too. What resolution do you really need? What accuracy? What repeatability?
 

oracacle

Senior Member
A quick look through the data sheet, shows a change in current, and not voltage.
however I would hook up a scope and see what it outputs to start with. In the electro-optical characteristics table it shows values for 100lx and 1000lx being 20 and the 30uA respectively, I would be tempted to say if current is less than 21 lx = current*10/2, less than 30 current*100/3.. so on up through the values.
use case select or if statement, but I don't think there will be a single equation that will do the job without floating pint maths
 

fernando_g

Senior Member
premelec;
I just came about this nifty IC by chance. I'm not planning to do anything with it, at least not yet.
It got me thinking how the Picaxe could handle such an output. It is only technical curiosity, that is all.

What I particularly piqued my curiosity about this little device is that it performs the infrared compensation internally. Other light sensing ICs have two separate registers: one has to read the visible + IR channel, then read the IR channel and perform some mathematically challenging manipulations to obtain the true visible light value.

After giving it a little thought perhaps the output voltage could be represented as is, no manipulation. Similar to decibel-lux, where the dark current would be represented as 0 dBlux, and the maximum current let's say 127 dBlux.
Good for relative measurements only.
Or another to do several lookup tables, dividing the range in decades, as oracacle suggests.
 

eggdweather

Senior Member
So it needs a load resistor to convert the output current to a voltage, with the value chosen to scale it for the Picaxe ADC input, then assign bands of ADC readings into decades and that gives a relative and wide range of light level measurement. There is a similar scale defined for the human skin exposure to the sun and there are other chips available that scale their output in decades using a log conversion and thereby give a UV index output. Doing all this is easily achieved with integer maths, I've done something similar using the Arduino.
 

AllyCat

Senior Member
Hi,

As PICaxe maths is rather "weak", conversion from log to linear is probably best done using a "piecewise linear" graph transfer characteristic (from a lookup table of data). The advantage is that most of the nasty maths can be done by a curve-fitting process in a spreadsheet such as Excel. Basically, it's the same process as required for (NTC) thermistor calibration and for Sin/Cos/Tan etc. conversions (and their inverses), etc. (which it happens I have a need for, all in one program). Ideally, one should not just take sample (line-end) points from the transfer characteristic, but do (e.g.) a least-squares fit of each line, perhaps even taking into account that PICaxe integer calculations always round down.

However, I couldn't find much on the PICaxe forum except a good example from Jeremy Leach (for ATAN), but that uses nearly all of an M2's named variables (which thus have to be pushed/swapped into the extended RAM space). So I decided to write my own "General Purpose" interpolation (sub-)routine to handle multiple lookup tables (of piecewise-linear transfer characteristic data). I hope to post it in the code snippetts section eventually, so won't give a listing here, as you don't have an immediate need. To Keep It SimpleS, I assumed only a continuous positive gradient in about 16 linear sections of equal size. That shouldn't be a severe limitation because an NTC just needs the scale reversed (e.g. TempC = 100 - TempC) and trignometric angles can be handled my "mirroring" the positive quadrant, etc..

Each line segment is the diagonal of a rectangular "cell" where the position of the lower left corner can be calculated, then its height from the table, to give the gradient. Then the position along the line/sides calculated as a simple ratio (division) and the corner offset added. I used 256 points across the width of each cell and up to 65,535 for the height (i.e. a Word lookup table), thus ~12 bits of input data map to a 16 bits output range. For the "inverse" operation a simple search of the table is first used to find the required cell.
_____

However, it isn't too difficult to make wide range luminance measurements with (just) a PICaxe. The trick is to use a current to time (or frequency) converter (aka an oscillator). The PIcaxe can then use a 16-bit counter-timer (e.g. Timer1 with its Gate Control logic) to achieve up to 1:65k resolution or dynamic range. Timing the period gives more resolution at low light levels (currents) whilst counting a frequency gives more resolution at high brightness levels.

For example, a BPW32 photodiode gives about 8 mA at peak solar level, whilst the input leakage of a PICaxe pin is about 5 nA (max 120 nA) so a range of up to 1,000,000:1 can be possible (e.g. using one of the internal comparators to implement the oscillator). Even a single continuous scale may be possible using Timer1 as the primary Counter/Timer, with the PICaxe checking for overflows of the 16-bit value (if you can work around the PICaxe's operating system). Again, I have had a prototype working for some time with an 08M2, using only an external photodiode, 100 nF capacitor, a transistor or diode and a couple of resistors, which hopefully will one day make its way into the code snippetts section. ;)

Cheers, Alan.
 

eggdweather

Senior Member
Add a load resistor, say 100K assuming 50uA maxium output, scales the maximum output to 5v
Code:
  symbol decade = w2;
  readdac10 w1 ; read DAC level into w1, scale the load resistor to match the PICAXE supply voltage to give maximum resolution
  if w1 < 50 then
    decade = 0;
  endif
  if (w1 >50 AND W1 <= 227) then
     decade = 0;
  endif
  if (w1 >227 AND w1 =318) then
     decade = 1;
  endif;
etc...
  if (w1 > 318 AND w1 <= 408) then decade = 2
  if (w1 > 408 AND w1 <= 503) then decade = 3
  if (w1 > 503 AND w1 <= 606) then decade = 4
  if (w1 > 606 AND w1 <= 696) then decade = 6
  if (w1 > 696 AND w1 <= 795) then decade = 7
  if (w1 > 795 AND w1 <= 881) then decade = 8
  if (w1 > 881 AND w1 <= 976) then decade = 9
  if w1 > 976 then
    decade = 10
  endif
At the end w2 = a rough UV index or light levels measured in decades
 

AllyCat

Senior Member
Hi,

At the end w2 = a rough UV index or light levels measured in decades
Sorry to be critical but...

The "UV Index" is actually a Linear Scale and would/should be zero below about 5,000 "Lux", if it were a UV sensor (which it isn't). Strictly, Lux is a measure of Visible light, but I have seen it in the specification sheets of some IR LEDs/sensors. :confused:

I think perhaps you mean "Octaves" (2:1 ratio) not "Decades" (10:1 ratio)? Even in light level terms, a decade is quite a lot, probably the difference between full sun and heavy cloud (at least in Texas?). And I would at least use code to calculate a linear interpolation between the "decade" thresholds. However, the sensor has a "continuous" true logarithmic response, not piecewise segments, so for 4-5 decades I'd use a lookup with at least 15 linear segments, maybe 30+.

Also, I think you mean READADC, it is possible to use READDAC in some very specific circumstances, but not with that code. The "Recommended Operating Voltage" of the sensor is a maximum of 3.2 volts, so I'd use the PICaxe's internal FVR2048 ADC reference and at most a 39k resistor.

Cheers, Alan.
 

fernando_g

Senior Member
Interesting discussion, lots of good ideas! That is what I wanted to accomplish with this thread.

With a low Ios, Vos opamp, one can easily create a very linear current to voltage converter.
Based on the above ideas, and the fact that ALL the luxmeters I've seen perform a scale change (either manually or automatic like a DMM) to accomodate the whole range, a similar approach could be made with the I/V converter's gain transfer function.
This can be done with a single resistor value change. The output voltage can be scaled to 3 or 5 volts. Probably the former, to have a single supply voltage for the complete system.

The resulting output voltage could be read with the Picaxe's ADC and then via a lookup table, linearize and display the results.

The V/F conversion is also intriguing.

In addition to linearization, the value added by a Picaxe to such a system would be:
-autoranging
-logging
-alarm setting
-remote monitoring
-other sensors (temperature?)

This could be developed as an excellent greenhouse monitor.
 

eggdweather

Senior Member
Yes I did mean READADC, another slip of the keyboard.
Thanks for clarifiying, because I was under the impression the UV index was a measurment of light intensity measured on a log scale of w/m^2 simplfied as a linear scale for most people. It looks like the device also measures light intensity on log scale giving a linear output voltage, so in my mind:
Code:
UV Index
1       2       3        4      5       6      7       8         9          10
0.0001  0.001   0.01     0.1    1       10     100     1,000     10,000     100,000

Device scale
1       2       3        4      5       6      7       8         9          10
0.001   0.01    0.1      1      10      100    1,000   10,000    100,000    1,000,000
and where a 'decade' was a colloquialism for an indice increase of 1 (or 10 in base10). So from both of these a relative light intensity can be established and with some adjustment made to be the same.

For information and may be of use, I've used a UVM-30A with an Arduino and it can be used to give a calibrated UV index out of the box.
 
Last edited:

hippy

Technical Support
Staff member
The attached code will do the antilog conversion to convert the sensor output to lux. It uses both the decade deciding and multiple tables described by others; actually 100 tables by using EEPROM.

"Calculate" is the main routine. Takes a "uAx20" value and converts that to lux. READADC10 can be used for reading the sensor output (0-50uA) multiplied by 20 through being applied to a ~97K resistor giving a reading of (0-1000) at 5V.

Output from simulation -

Code:
 0.0uA      lux = 1           1.000
 5.0uA      lux = 3           3.162
10.0uA      lux = 10          10.00
15.0uA      lux = 32          31.62
20.0uA      lux = 100         100.0
25.0uA      lux = 316         316.2
30.0uA      lux = 1000        1,000
35.0uA      lux = 3162        3,162
40.0uA      lux = 10000       10,000
45.0uA      lux = 31620       31,620
50.0uA      lux = 65535       100,000

12.3uA      lux = 17          16.98
12.4uA      lux = 17          17.38
12.5uA      lux = 18          17.78
12.6uA      lux = 18          18.20
 

Attachments

fernando_g

Senior Member
Simply brilliant, hippy..........

How did you calculate the EEPROM table? Did you employ an excell spreadsheet?
 

hippy

Technical Support
Staff member
Simply brilliant, hippy..........

How did you calculate the EEPROM table? Did you employ an excell spreadsheet?
I wrote a Python program. The 'write' command was a little more complicated than shown here ...

Code:
def antilog10(x):
  return 10.0 ** x
with open ("eeprom.txt","w") as fEeprom:
  n = 0
  while n <= 200:
    fEeprom.write( "Eeprom " + str(n) + ", ( " + str(antilog10(n/20.0)) + " )" + "\n" )
    n = n + 2
 

AllyCat

Senior Member
Hi,

Yes a very nice piece of code from hippy (of course), but perhaps rather "overkill", at least for my application. Certainly much of the 400+ bytes of codespace is concerned with the test harness and neat presentation of the data, but 202 bytes of EEPROM is 80% of that available in many PICaxe chips and is "stolen" from the program space of an 08M2 (which my project "must" use*).

For those who haven't examined the calculation in detail, the table contains alternate lookup values explicity and the intermediate values are interpolated by a simple average of adjacent entries. So the table size could be halved by interpolating 3 intermediate values and deleting alternate word entries. Then (I believe) the first part of the calculate: routine could become:

Code:
    b0 = uAx20 // 200
    b15 = b0 // 4
    b0 = b0 & $FC / 2  
    Read b0, w1.msb : b0 = b0 + 1 : Read b0, w1.lsb 
    w1 = w1.msb * 100 + w1.lsb
    b0 = b0 + 1
    Read b0, w2.msb : b0 = b0 + 1 : Read b0, w2.lsb 
    w2 = w2.msb * 100 + w2.lsb
    w1 = w2 - w1 * b15 / 4 + w1
    w2 = uAx20 / 200
;   etc..
Note that not only should alternate EEPROM data lines be deleted (or commented out) but each EEPROM declaration contains an explicit address which must be halved.
______

Looking at the overall accuracy, each inremental step of the READADC10 result represents a Lux increase of just over +1%. If one divides the whole conversion range (4+ decades) into about 16 line segments (actually 4 per decade) as I proposed earlier, the worst error is about 2.8%, but that can be offset to +/- 1.4%, a little worse than the ADC quantisation eror (assuming the ADC is otherwise truly linear).

If one goes to 8 line segments per decade (33+ words for the 4+ decades) the basic error becomes about 0.6% that can be offset to about +/- 0.3%, which IMHO is probably "good enough". Or with hippy's "decade" method, only 8 line segments (18 bytes in EEPROM) would be required for a single decade, which might be doubled to 16 segments (or more) for better accuracy.

* FWIW, Part of my own "project" requirement is to compare the "actual" (measured) light value with the "expected maximum" value (calculated from the local time, date and latitude). Hence my reference to trignometric conversions and the need for compact code for the relatively "easy" parts of the measurement. ;)

Cheers, Alan.
 

hippy

Technical Support
Staff member
Yes a very nice piece of code from hippy (of course), but perhaps rather "overkill", at least for my application.
Very probably :)

I didn't really pay any attention to any requirements beyond delivering the most accurate result without any complex calculation.

Looking at the overall accuracy, each inremental step of the READADC10 result represents a Lux increase of just over +1%.
That's a good observation. As it is, each EEPROM value is less than 256 greater than the one before, so the full set of 200 entries could be held in EEPROM by storing only the difference from previous. One would then have to run through those values to get an actual reading but that wouldn't take too long, and no need for any interpolation.

That would cut program memory required but not EEPROM. Reducing EEPROM use would need fewer entries meaning more interpolation as described.

As always; it's a trade off of one thing against some other thing, often multiple things.
 
Top