ambient light sensor/What it sees/08. The flicker under room lights
What it sees · 08 of 10

The flicker under room lights

Many LED and fluorescent lamps on the mains brighten and dim 100 times a second, or 120 where the mains is 60 Hz. This sensor is fast enough to follow that, so single reads scatter. Average everything read over 50 ms, five whole cycles at 100 Hz and six at 120 Hz, and the ripple cancels.

Faster than it looks

The phototransistor switches in about 15 µs. After it, the 100 nF and the 4.7 kΩ make a filter, 4.7 kΩ times 100 nF, which is 0.47 ms, with a corner near 340 Hz. Anything slower than that corner passes straight through to SIGNAL. The ripple of a mains lamp is slower than that.

Many LED and fluorescent lamps run from the mains get a little brighter and dimmer twice every mains cycle: 100 times a second where the mains is 50 Hz, 120 where it is 60 Hz. You do not see it. How deep the ripple is depends entirely on the lamp: some barely ripple, some a lot. This sensor sees it, and a single analogRead catches the lamp wherever it happens to be in its wave.

The flicker under room lights
Mains
Each reading is
Spread
Cycles in window
none
The 100 nF takes off
4 %
The lamp brightens and dims 100 times a second, and the sensor is fast enough to follow it. Pick how the sketch reads, then run it.

Leave the reading on One analogRead and run it. Eight readings, taken at different moments, scatter across tens of counts on an Uno. The ripple in the figure is a picture of a lamp, ±25 %, not a measurement of any particular one; yours may be smaller or larger. The 100 nF takes only 4 % off it at 100 Hz, and 6 % at 120 Hz.

Average whole cycles

Pick The mean of 50 ms. Each reading is now the average of everything read over 50 ms, and 50 ms holds exactly five cycles of 100 Hz. Whole waves average to the same value wherever they start, so the eight readings land on top of each other. Switch to 60 Hz: 50 ms is six whole cycles of 120 Hz, and it still works.

Try The mean of 10 ms. At 50 Hz mains it is one whole cycle and works perfectly. At 60 Hz it is 1.2 cycles, the leftover fifth of a wave depends on where the reading started, and the scatter comes back. That is why the sketches use 50 ms: it is whole cycles in every country.

The sketch

readSteadyMilliVolts reads as fast as the board can for WINDOW_MS and returns the mean. It is not the number of reads that matters but the time they cover. The sketch prints a single read beside the average, so you can watch one column wander and the other hold still under the lamp in your room.

The code

Two readings side by side: one analogRead, and the mean of everything read over 50 ms. Under a lamp that ripples, the first column wanders and the second holds still.

light_steady.ino
/*
  Ambient Light Sensor - a steady reading                TK20 / /p/tk20

  Wiring. Count from the square pad on the TinkerBlock board, parts
  up, header at the bottom:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
              ESP32-S3, GP26 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. Arduino Uno
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The analog pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int LIGHT_PIN = A0;

// Uno and Pico only: the ADC's full scale, in mV.
// Uno: 5000. Pico: 3300.
const float FULL_SCALE_MV = 5000.0;

// 5 cycles of a 100 Hz ripple, 6 of a 120 Hz one.
const unsigned long WINDOW_MS = 50;

float readMilliVolts() {
#if defined(ARDUINO_ARCH_ESP32)
  return analogReadMilliVolts(LIGHT_PIN);   // calibrated in the chip
#else
  return analogRead(LIGHT_PIN) * FULL_SCALE_MV / 1023.0;
#endif
}

// The mean of everything read in WINDOW_MS.
float readSteadyMilliVolts() {
  float sum = 0;
  long n = 0;
  unsigned long start = millis();
  while (millis() - start < WINDOW_MS) {
    sum += readMilliVolts();
    n++;
  }
  return sum / n;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.print("one read ");
  Serial.print(readMilliVolts(), 0);
  Serial.print(" mV    50 ms mean ");
  Serial.print(readSteadyMilliVolts(), 0);
  Serial.println(" mV");
  delay(250);
}

WINDOW_MS is 50 because 50 ms is five cycles of a 100 Hz ripple and six of a 120 Hz one, so the average contains only whole waves wherever it starts. The loop reads as fast as the board can for that long, which is a few hundred reads on an Uno.

When it does not work

The reading wobbles by tens of counts under my ceiling light.

That is the lamp, not the block. Run the sketch here and compare the single read with the 50 ms average: the average should hold within a count or two. Under daylight or a battery torch both columns should be steady, which confirms it.

Why 50 ms and not 10?

10 ms is exactly one cycle of the ripple where the mains is 50 Hz, so it works in Europe, Australia and much of Asia. Where the mains is 60 Hz the ripple is 120 Hz, and 10 ms is 1.2 cycles, which leaves part of a wave in every reading. 50 ms is whole cycles of both, so one sketch works everywhere.

Can I just put a bigger capacitor on the board?

The 100 nF with the 4.7 kΩ makes a filter with a corner near 340 Hz, which takes only a few per cent off a 100 Hz ripple. Hiding it would take a capacitor tens of times larger, soldered to a surface-mount pad, and the reading would lag too. Averaging in the sketch does the same job with no soldering.

Does averaging slow the sketch down?

Each reading takes 50 ms, so at most 20 readings a second. For light in a room that is far more than enough. If the sketch has other work to do, take one reading every second or so rather than one after another.

Where this goes next

A TK01 that comes on at dusk, calibrated to your room, and does not flicker while it decides.

A night light

Edit this page — content/books/ambient-light-sensor/the-flicker-under-room-lights.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Ambient Light Sensor

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum