Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add dark frame calibration and add calculateLux method as per Si114x AN523 #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

gtalusan
Copy link

@gtalusan gtalusan commented Nov 3, 2016

... aka make the SI1145 more useful on the Arduino.

The SI1145 datasheet is quoted as saying:

Accurate lux measurements with IR correction algorithm

It's hard to determine exactly what the algorithm is until looking at their SI1145 AN523 application note. The lux calculation is given as such:

Lux level = [ [(ALS visible reading) - (ALS visible dark reading)] x (ALS visible coefficient) +
[ (ALSIR reading) - (ALS IR dark reading)] x (ALS IR coefficient) ] x gain correction

The dark readings are absolute minimums reported by the sensor in "absolute" darkness, and the coefficients are gleaned from the table in AN523.6. I have changed the Adafruit_SI1145 class to keep track of the absolute minimums of the VIS and IR channels and use them for dark frame subtraction. The initial dark values were determined by covering the sensor with a black cloth.

I have also exposed an API for adjusting the gain on the visible and IR channels.

I have a TSL2561, TSL2591 and SI1145 hooked up to my Arduino Uno's I2C bus and the EV calculations are in relative agreement.

TSL2561 IR: 88  Full: 228 Lux: 94.00  EV: 3.63
TSL2591 IR: 94  Full: 232 Lux: 63.517436  EV: 3.24
SI1145 IR: 14  Full: 12 Lux: 63.799999  EV: 3.24

TSL2561 IR: 86  Full: 225 Lux: 94.00  EV: 3.63
TSL2591 IR: 93  Full: 227 Lux: 60.775676  EV: 3.19
SI1145 IR: 14  Full: 13 Lux: 69.209999  EV: 3.32

TSL2561 IR: 83  Full: 219 Lux: 93.00  EV: 3.62
TSL2591 IR: 90  Full: 221 Lux: 59.894393  EV: 3.18
SI1145 IR: 13  Full: 13 Lux: 69.290000  EV: 3.32

@gtalusan gtalusan force-pushed the master branch 2 times, most recently from 94734d3 to dc338c1 Compare November 4, 2016 05:02

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…AN523
Copy link

@HGrabas HGrabas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be a very useful amelioration - SensorLab doesn't make obvious the formulae to do absolute lux measurements.
@gtalusan : I noticed that in the begin() statement you have kept:
writeParam(SI1145_PARAM_ALSVISADCMISC, SI1145_PARAM_ALSVISADCMISC_VISRANGE);
and:
writeParam(SI1145_PARAM_ALSIRADCMISC, SI1145_PARAM_ALSIRADCMISC_RANGE);

From the header file it seems that #define SI1145_PARAM_ALSVISADCMISC_VISRANGE 0x20 puts the SI1145 in high range mode. It is the same for IR lmeasurments.

When performing ALS-VIS measurements, the ADC can be programmed to operate in high sensitivity operation or high signal range.
The high signal range is useful in operation under direct sunlight.
0: Normal Signal Range
1: High Signal Range (Gain divided by 14.5)

Shouldn't then the IR and visible part of the signal being multiplied back by 14.5?

Also you formula for the gain correction seems to be wrong to me, the data sheet states that:

Increases the ADC integration time for ALS Visible measurements by a factor of (2 ^ ALS_VIS_ADC_GAIN). This allows visible light measure- ment under dark glass. The maximum gain is 128 (0x7).
For Example:
0x0: ADC Clock is divided by 1 0x4: ADC Clock is divided by 16 0x6: ADC Clock is divided by 64

So it looks to me that you should change:
float lux = ((5.41f * vis) + (-0.08f * ir)) / (1 + 2 * gain);
to:
float lux = ((5.41f * vis) + (-0.08f * ir)) / pow(2 ,gain);

So I think the complete function should look like:

// returns a calculated lux value as per SI144x AN523.6.
float Adafruit_SI1145::calculateLux(uint16_t vis, uint16_t ir) {
    uint8_t gainVis = readVisibleGain();
    uint8_t gainIr  = readIRGain();
    float rangeVis = 1 + 13.5f * ((readParam(SI1145_PARAM_ALSVISADCMISC) >> 5) & 0x01);
    float rangeIr  = 1 + 13.5f * ((readParam(SI1145_PARAM_ALSIRADCMISC) >> 5) & 0x01);
    float lux = (5.41f * vis * rangeVis)/ pow(2 ,gainVis) + (-0.08f * ir * rangeIr) / pow(2 ,gainIr);
    return lux;
}

However the fact that this function is quite different from the one you originally had and tested against other lux-measurements units has me quite confused.

An other issue I can see is that no bit masking is done in your functions:
readVisibleGain() and readIRGain(). Since the gain occupy only 3bits and the rest of the bits are un-specified I'd mask them.

@gid1
Copy link

gid1 commented May 14, 2020

hi, can you provide the updated Adafruit_SI1145.cpp file with the dark frame calibration and the lux calc'. thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants