← Back Case study · Flagship Handed over · still running

3DREAMS@SG

A real-time atmospheric-intelligence platform that turns three Doppler LiDARs, NEA air quality and NASA fire detections into a detection score an operator can inspect, and reaches out the moment haze starts to move in over Singapore. I designed it, built it end to end, operated it from 2025 to 2026, and handed it over in full: the CCEH team runs it today.

Designer · Sole engineer · Operator Centre for Climate Change and Environmental Health, NTU Feb 2025 to Aug 2026 Python · DuckDB + PostgreSQL · Next.js

00 / 04Context

The problem.

Elevated aerosol layers (haze, transported smoke, dust) sit aloft for hours before they mix down to street level. By the time a ground monitor reads the spike, the event is already happening. The signals that see it coming live in Doppler-LiDAR backscatter and wind profiles, but those feeds are noisy, ragged, and arrive on different clocks across sites, and clouds routinely masquerade as aerosol.

The brief: make that early signal trustworthy and actionable. Fuse the sources onto one timeline, score the likelihood of an episode with a physical model an operator can interrogate, forecast when it reaches the surface, and push that judgement to the people who act on it, without drowning them in false alarms.

01 / 04System

The architecture.

One pipeline, read left to right: what comes in, what decides, what acts. Three Halo Photonics StreamLine XR Doppler LiDARs stare straight up from rooftops at NTU's Asian School of the Environment, Raffles Girls' School and Woodlands Health, each averaged to one backscatter profile a minute, with a six-beam wind scan solved by least squares.

Every feed lands on one ten-minute clock with its gaps carried, never interpolated away. One shared scorer reads the last two hours, and the same code runs live, in replay and behind the dashboard, so a past episode re-runs exactly as it fired.

The 3DREAMS@SG pipeline in three columns. Ingest: Doppler LiDAR, NEA air quality, satellite fire detections from FIRMS, and a cloud mask derived from the LiDAR. Decide: fusion of three sites onto one ten-minute clock, then a shared scorer over a two-hour window with a six-component probability model and breakthrough ETA, and a three-stage cloud mask beside it. Act: Teams and Telegram agents, mission control with ten panels, and a geospatial hub with five viewports. Beneath, the episode ledger, replayed through the same scorer.
The pipeline, as drawn for the 3dreams-sg repositorygithub.com/awvmeijer/3dreams-sg
// 01

Ingest

LiDAR backscatter, vertical velocity and wind; NEA PM2.5, PSI and weather; NASA FIRMS fire detections; and a three-stage cloud mask computed from the LiDAR itself. Files are deduplicated per site in SQLite, and every upsert is idempotent.

// 02

Decide

Three sites on one ten-minute clock. The shared scorer rates each two-hour window and forecasts when an elevated layer will break through to the surface.

// 03

Act

Alert cards in Microsoft Teams with every signal attached; plots and status in Teams and Telegram; mission control and the five-viewport Geo Data Hub for the people who look.

// 04

Ledger

Every detected episode is recorded in PostgreSQL and can be replayed through the same scorer: how v2 was measured against the February 2026 episode.

From the film: the StreamLine XR on the Asian School of the Environment's roof at NTU, with the instrument card (system 239, 1.5 µm, 200 range gates of 60 m to 12 km, one stare profile a minute, a six-beam wind scan at 75 degrees) and the LiDAR Bot's daily plots of backscatter, vertical velocity and wind for 29 September 2026.
NTU's LiDAR, system 239, on the Asian School of the Environment · from the film, 0:35Plots: the LiDAR Bot's own, 29 Sep 2026

02 / 04Detection

The science.

Detection is a physics-based score, not a black box. Every ten minutes the last two hours are rated 0 to 100 from six weighted checks, each one shown on the alert, so an operator can see exactly why a number moved.

Before anything is scored, hard gates ask for enough minutes of stare, an elevated layer several range gates deep, and a coherent wind. A window that passes them all is MEDIUM. It becomes HIGH when a second site corroborates or the score reaches 75. A diurnal boundary-layer model then estimates when the layer will reach the street.

Clouds are the hardest part of trusting LiDAR: a cloud base looks like a dense layer. A three-stage cloud mask runs beside the score and puts its verdict on the card.

RGS, 12 Feb 2026 · the 02:30 HIGH alert, from the v2 replay
  1. Persistenceshare of the two hours the layer is there30
  2. Descentthe layer sinking, metres an hour20
  3. PBL proximityits gap to the boundary layer15
  4. β′ trendbackscatter rising over two hours15
  5. Subsidencesinking air, w below zero10
  6. Wind coherencea steady transport direction10
  1. 01 · Hard gates

    Enough stare, an elevated layer, coherent wind

  2. 02 · Six checks

    Weighted, summed to P(episode), 0 to 100

  3. 03 · Level

    MEDIUM when every gate passes; HIGH on a second site or P ≥ 75

  4. 04 · Alert card

    To Microsoft Teams, with the breakthrough ETA and the cloud mask's note

The six weights, out of 100, and the path from window to cardAs the LiDAR Bot's "Why this alert?" panel shows them

The cloud mask, in three stages

TestCatches
01Onseta return too strong, or an edge too sharp, for aerosol
02Columnthe cloud's body above its base, and the shadow it casts
03Persistenceonly what holds minute to minute is kept

Aloft is not the street

The same layer means different things at 03:00 and 14:00. Overnight the boundary layer is shallow and the haze stays up; by mid-morning it grows into the layer and mixes it down. In the public extract's synthetic run, one identical layer scores 1.00 on the breakthrough term at 14:00 and 0.11 at 03:00.

Scoring model
6 checks · weighted
Window
2 h · every 10 min
Surface arrival
PBL breakthrough ETA
Cloud check
3-stage mask
Wind retrieval
least squares · 6-beam VAD
Ingest dedup
SQLite · idempotent upserts

03 / 04Delivery

Reaching people.

A score nobody sees is worthless. The system is proactive: when a window crosses the line, the LiDAR Bot posts the alert to the dashboard and an alert card to Microsoft Teams, with every signal attached, before anyone has asked.

The same agents answer on demand. Teams carries the alerts, analysis, NEA readings and event log behind seventeen commands; Telegram receives the daily plots and status and answers plot requests.

From the film: the LiDAR Bot page at 02:30 on 12 February 2026. The terminal logs the ten-minute cycles, the RGS HIGH alert at 96 percent for a layer from 210 to 980 metres, and the alert sent to the dashboard and to Microsoft Teams; the Alerts tab shows the HIGH alert above the MEDIUM one from 21:40 the evening before.
The LiDAR Bot at 02:30 SGT, 12 Feb 2026 · from the film, 2:05Alert values from the v2 replay
2Chat platforms
17Teams commands
10Mission-control panels
5Geo-Hub viewports
4Fused sources

04 / 04Result

What changed.

Replayed against the 36-hour February 2026 reference episode over Raffles Girls' School, v2 issued ten alerts where the previous detector issued none. The north-east monsoon carried a layer in aloft; the first HIGH came at 02:30, and the layer mixed down at 08:15: 5 hours 45 minutes of warning.

NIGHT NIGHT 0 m4008001,200 18:0000:0006:00 12:0018:0000:0006:00 11 FEB12 FEB13 FEB 21:40 · MEDIUM 58% 720–960 m 02:30 · HIGH 96% 210–980 m 08:15 · HIGH 81% · mixing active 210–480 m 00:50 · MEDIUM 47% 600–840 m 5 h 45 min NEA PM2.5, central 6 → 16 → 23 µg/m³ 08:00 → 10:00
The February 2026 episode at RGS: four of the ten alerts, each drawn as the layer it reportedv2 replay · NEA, data.gov.sg

Reactive → proactive

Monitoring shifted from reading spikes after the fact to being told an episode is likely, with a forecast for when it reaches the surface.

Every alert inspectable

The web app ships a public preview at lidar-dashboard-3dreams.vercel.app; the operational dashboard behind it is login-gated for the CCEH team. The signal behind a score is one click from the alert itself.

Handed over, still running

Ingestion, retrieval, scoring, backend, dashboard and agents: designed, built and operated by one person, then migrated in full to the CCEH team, who run it today.

Shown to WHO delegates

Presented by CCEH's founding director at the Regional Action Forum NTU co-hosted with the World Health Organization in June 2026, to delegates from eleven Western Pacific countries. I built the platform and the film shown there; the film at the top of this page follows one evening of September 2026's haze through the platform.

In the open. The 3dreams-sg repository ↗ is a standard-library extract of the scorer's design: the shared scorer, the breakthrough term and the cloud check, run over three synthetic windows with python3 examples/synthetic_window.py and tested in CI.

The observational data, the credentials and the operational thresholds stay with CCEH. The repository shows how the decisions are structured, not the numbers that tune them.

Next case study Brains →
© 2026 Anthony Meijer · Singapore 3DREAMS@SG · Centre for Climate Change and Environmental Health, NTU