TLF Dilution Calibration — Tryptophan
- Bench serial dilution — 14 sensors, 2026-07-16. A tryptophan stock
stepped down through a serial dilution with every sensor in the same bath. Read on
mon2_valat the calibrated combo and on the pooled-quadraticsTLF. This is the first half of the page. - Burn-in fleet ladder — 25 sensors, 2026-08-06. A known ladder
(0, 0.1, 0.5, 5, 10, 50 ppb) dosed into the burn-in bath, read four ways and used to
derive each unit’s offset and gain. Merged here from the retired burn-in page on
2026-08-21; it is the second half, below. It uses the current
tlf_amptwo-way log-model amplitude, which replaced the pooled quadratic on 2026-08-13 — so the TLF feature differs between the two halves.
14 sensors · tryptophan serial-dilution bench test, 2026-07-16 · TLF (mon2_val) vs known tryptophan concentration
1 · Bench serial dilution — 14 sensors, 2026-07-16
Read on mon2_val and the pooled-quadratic
sTLF, the feature in use at the time.
Overview
A serial-dilution characterization of the Lume’s tryptophan-like fluorescence (TLF) channel
(mon2_val, the SiPM signal). A tryptophan stock solution is stepped down through a
serial dilution while all 14 sensors read the same bath, so each sensor sees an identical, known
concentration at each step. The goal is a per-sensor TLF → concentration response and a
check of linearity, sensor-to-sensor spread, and limit of detection.
TLF is the primary E. coli–bearing signal in the field model, so a clean concentration–response curve on a pure tryptophan standard is the fluorophore analog of the ToF → NTU turbidity calibration. This page reads the sensors live during the test; enter the dilution steps below to build the calibration curve as data comes in.
Live TLF Readings
Raw mon2_val per sensor over the test window, pulled from the sensor API
(combo: 'best' — the calibrated combo per unit). These 14 units auto-range, so the
operating combo (LED power) can differ between units; hover a point to see its combo. Absolute
mon2 is only comparable within a sensor across steps, not between sensors at different LED powers.
All 14 Overlaid — Same Bath, Corrected to a Common Scale
All 14 units read the same solution at the same times, so once each unit’s instrument response is removed they should trace one curve. Each trace here is the full-sweep TLF slope with three per-sensor corrections applied: (1) temperature, corrected to 21 °C SiPM via the unit’s own quench (from the 50 ppb temperature sweep); (2) a two-point gain + offset that maps each unit’s blank → 0 and its 50 ppb → 1; and the lifetime sample count shown per unit in the legend (burn-in state). The dilution ramp should rise 0 → 1 together, and the 6-hour 50 ppb temperature hold should sit flat at 1.
SiPM Temperature
SiPM (detector) temperature per unit over the test window. (The diagnostics
temperature field is the board temperature, which self-heats ~1 °C from the
electronics and is not representative of the water, so it is not used.) Temperature quenches TLF, so it is
the covariate to watch when interpreting the dilution response — a drift here can move
mon2 independently of tryptophan.
The TLF Feature — Two-Way Log-Model Amplitude
Switched to the canonical amplitude, 2026-08-21. This page ran on the bias-response
slope from 2026-07-21. Everything on it — the overlay, the calibration, the low-level
test, the per-sensor prediction — now reads the two-way log-model amplitude
(scripts/lib/tlf_model.js), the estimator the rest of the programme uses. The slope
definition below is kept because it is still what production serves at Boulder and Chicago, and
because the comparison is the evidence for the switch.
Measured on this ladder, same rows, same model form
(conc = a + b·f + g·f² + c·ΔT + d·ΔT² +
e·f·ΔT + h·f·ΔT²), pooled over the 12 sensors every
feature can fit:
| Feature | pooled R² | RMSE (ppb) | fails to fit |
|---|---|---|---|
absolute mon2 | 0.9097 | 4.98 | 50059, 50091 |
| S-TLF slope (previous) | 0.8963 | 5.34 | 50059 |
| two-way log amplitude ◀ now used | 0.9087 | 5.01 | 50059 |
Read this honestly: the amplitude does not
beat absolute mon2 on accuracy. On the sensors where all three work they are level
(0.9087 vs 0.9097). What the amplitude buys is robustness — it fits 13 of 14 sensors where
mon2 fits 12, and it beats the slope on 11 of 13 with the gap concentrated exactly
where it should be: 50091 0.4835 → 0.8131, 500193 0.8713 → 0.9260,
50062 0.8232 → 0.8700. On well-behaved units the two tie. That is the estimator behaving
as designed: it does not make good sweeps better, it stops bad ones from being wrong.
50059 fits under no feature and is excluded throughout — it carries no dilution blank of its own (see the transfer section on /colilert), not a fault of the estimator.
The slope of the SiPM gain response, read at the calibrated bias — a self-normalizing, railing-proof
replacement for absolute mon2. Computed once per reading from the full
LED×bias sweep, in five steps:
- Sweep — take every combo in the reading: LED power ∈ {32, 128, 512} across the full SiPM
sipm_biassweep (~2800–3900). - Screen — keep only unsaturated combos,
200 < mon2 < 3250— dropping the low-bias pedestal (mon2 ≈ 170, SiPM below breakdown) and the high-end saturation (~3299 ceiling). - Normalize — for each kept combo compute
y = (mon2 − 170) / LED. Becausemon2 ≈ 170 + LED·gain(bias)·fluor, dividing by LED power collapses all three LEDs onto one gain curve. - Fit — regress
y = a + b·bias + c·bias²(a quadratic, all kept combos pooled). - Evaluate — the feature is the response slope at the fixed reference bias 3000:
sTLF = (b + 2c·3000) × 10³.
Constants: pedestal 170 · screen 200–3250 · reference bias 3000 · scale ×10³ · ≥6 combos required
(fitSlope in the page source). Evaluating at one fixed bias — rather than a raw slope over each LED’s
own auto-ranged bias arc — is what keeps the three LEDs in agreement and stops high-gain units from inverting.
Every reading carries a full LED×bias sweep, not one point. Rather than pick a single
combo (absolute mon2), we sweep all combos, screen out the low-end
pedestal (SiPM below breakdown, no gain: mon2 ≈ 170) and the
high-end saturation (~3299 ceiling), and fit the bias-response. Because
mon2 ≈ pedestal + LED·gain(bias)·fluor, dividing by LED power
collapses all three LEDs onto one gain curve; its slope vs bias tracks fluorescence but
partially cancels the SiPM gain’s own temperature drift.
One subtlety the sensors forced: the gain curve is curved, and the auto-range sweeps each LED over
a different bias arc (bright units saturate LED 512 early, leaving a high-bias tail that is
LED 32 only). A single straight-line slope over those mismatched arcs is dominated by the widest LED and can
invert on high-gain units (it drove 500128 to a spurious −38σ at low ppb). Fix: fit
(mon2−pedestal)/LED vs bias as a quadratic and take the derivative at a
fixed reference bias (3000) — evaluating at one bias makes the feature independent of how far
each LED’s sweep reaches, so the LEDs agree and 500128 reads correctly.
Why this matters for normalization: absolute mon2 quenches from both the
fluorophore and the detector gain (SiPM breakdown voltage rises with heat), so it drifts
~4 %/°C. The bias-response, measured across the sweep, drifts less
(roughly 2.5–3 %/°C) and it never rails. Below: at the
fixed 50 ppb temperature sweep, each sensor’s signal indexed to its own value at
20 °C; the exact per-sensor quench and spread are printed under the chart.
On raw discrimination the two features tie (both track concentration and field E. coli about
equally); the slope’s advantage is as a normalized reference — lower temperature
sensitivity, immunity to railing, and (with the fixed-reference-bias fit) correct behavior on high-gain units.
The whole page runs on it: the Normalized-TLF, temperature-correction, calibration, low-level,
and prediction sections all use the bias-response derivative (scaled ×10³) in place of absolute
mon2. This robustness trades a little in-sample fit: the fixed-reference-bias feature calibrates to
pooled R² ≈ 0.86 (vs ~0.98 for a raw single-combo fit that leaned on the high-bias tail), the
price of making every unit — including saturated/auto-ranging ones like 500128 — behave consistently.
ToF Turbidity (signal_per_spad_kcps) — Control Channel & Zero-Point
The Time-of-Flight photon backscatter (signal_per_spad_kcps, the turbidity proxy) per unit over
the test. Tryptophan is dissolved, not scattering, so a pure-tryptophan dilution adds no
turbidity: ToF should stay flat at the clean-water baseline across every step while TLF
rises. That makes this a control (TLF and ToF are independent channels) and, at the same time, the
0-concentration step gives each unit its clean-water ToF zero-point SPS₀
— the turbidity offset used by the ToF → NTU calibration
(NTU = k × (SPS − SPS₀), pooled
k ≈ 1.59 from the turbidity page).
Below, the same ToF converted to NTU per unit via each sensor’s own
SPS₀ and the pooled slope. Since the bath is clean water throughout, every trace should sit
near 0 NTU; departures are ToF noise / drift, and set the turbidity detection floor.
Calibration — Normalized TLF vs Concentration
Median normalized TLF slope (median bias-response slope over a step − the 0-conc blank)
vs concentration, per sensor, with a per-sensor linear regression (R² in the legend). Four views: the
isothermal ramp only (the two temperature-change periods excluded) at full range and zoomed to
0–1 ppb, and the temperature-corrected version using all data (each reading corrected
to 21 °C SiPM via the sensor’s slope quench) at full range and 0–1 ppb. Full-range panels are
log–log (so each decade weighs equally and R² isn’t dominated by the 50 ppb
endpoint); non-responsive sensors whose low-end normalized slope goes negative can’t be log-fit and show
R² = —.
Low-Level Response — Significance at 0.1 & 0.5 ppb
Is there a detectable response at the lowest dilutions? Each point is one sensor at one level, expressed as
SNR = (median TLF slope at that level − blank median) / blank noise (SD). Each reading’s
slope is first put on the canonical corrected signal — temperature-corrected to
21 °C SiPM and sample-cycle (burn-in) corrected, from each sensor’s joint quench + burn-in fit on
the 50 ppb sweep — so neither the small temperature differences nor cumulative-cycle drift between the blank and
the 0.1/0.5 ppb steps are mistaken for signal. The shaded band |SNR| < 2 is
indistinguishable from blank; 2 and 3 σ lines are marked. The 0 ppb group is the blank itself
(SNR ≈ 0 by definition — the null reference). 5 & 10 ppb are shown as positive
controls. (SNR is an effect size vs. blank noise; within-step readings are autocorrelated so it is descriptive,
not a formal p-value.)
Predicted Concentration — Per-Sensor Calibration
Per-sensor calibration: each sensor gets its own coefficients, fit on its own
full-sweep TLF slope — conc = aₛ + bₛ·slope + gₛ·slope² + cₛ·ΔT + dₛ·ΔT² + eₛ·(slope·ΔT) + fₛ·(slope·ΔT²), ΔT = TSiPM − 21 °C.
The isothermal dilution ramp (SiPM ≈ 21 °C) fixes each sensor’s baseline/gain/curvature (aₛ,bₛ,gₛ); the fixed-50 ppb
temperature sweep (SiPM ≈ 21→33→27 °C) fixes its quadratic quench (cₛ,dₛ,eₛ,fₛ). The bias-response slope is fit from every
unsaturated combo in the sweep, so there is no LED-hopping and no railing — the units that
pinned mon2 at the ~3299 ceiling (LED 512) are handled automatically. Predicted vs known concentration below (origin 0,0; dashed line = perfect 1:1).
Units with weak response (small slope rise) calibrate poorly — see the per-sensor RMSE.
50066 — Dilution ppb Scale vs Field E. coli
How this dilution’s response maps onto field E. coli for the one strong field-Colilert overlap sensor, 50066. The dilution fixes the
ppb scale (7.2 counts/ppb at LED 512). For the field grabs, the raw mon2 is the best E. coli
predictor (r = 0.74): this field set was all cold and in a narrow band (~13–17 °C), so temperature-correcting
with the warm-sweep quench actually degrades the correlation (r 0.74 → 0.55) and drags the coldest / highest-E. coli
grab into the pack — so no aggressive correction is applied here. Each grab is referenced to the field’s own
clean-water floor (the cleanest observed grab = 0 ppb) so estimates stay non-negative, then scaled at
7.2 counts/ppb. Bottom axis = ppb above the field floor, top axis = mon2 counts; y = measured log₁₀ E. coli.
Fit log₁₀(E. coli) = 1.66 + 0.021·ppb (r = 0.74): ~46 CFU at 0 ppb, ~200 at
30 ppb, ~1400 at 70 ppb. The response is real but noisy at low concentration. Indicative: n = 14, per-sensor;
ppb scale is nominal (field vs dilution temperature/matrix differ).
TLF ppb at the WHO risk levels — literature vs our sensors
| WHO risk level (E. coli / 100 mL) |
Literature ppb Sorensen 2018 |
Our sensors ppb CBT low + 50066 high |
|---|---|---|
| Low (~10) | 1.3 | ~3–12 (CBT)† |
| Medium (~100) | 2.4 | ~16 (50066; CBT 10–99 ~12) |
| High (~1000) | 6.9 | ~63 (50066) |
| Very high (>1000) | 27.1 | >63 (50066) |
E. coli anchors = WHO risk-band boundaries. Literature ppb: Sorensen et al. 2018 TLF thresholds
(thermotolerant coliforms / E. coli). Our sensors ppb: low end from the
CBT drinking-water dataset (165 grabs <10 CFU + 51 at
10–99, 3 sensors; E. coli signal referenced to each sensor’s own 0-CFU DOM background); high end from the
50066 Boulder field fit log₁₀(E. coli) = 1.66 + 0.021·ppb. Both on the nominal LED-512 dilution ppb
scale (7.2 counts/ppb). The sensor does resolve the low-CFU regime — the E. coli signal rises
0 → ~3 → ~12 ppb across 0 / 1–9 / 10–99 CFU — though 1–9 vs 0 is
marginal (within the ±3–4 ppb DOM-noise floor). Across all levels our sensors read ~2–9× more ppb
than the literature for the same E. coli (nominal scale, noisy per-sensor relationship).
†CBT is right-censored at 100 CFU so it anchors the low end; 50066 covers 32–1986 CFU — together they span the full range.
Dilution Steps
The dilution steps for this completed test. Each point on the calibration and prediction charts is a sensor’s median over a step’s time window; steps are shaded on the charts above. This test is final — the step definitions are locked.
Sensors Under Test
The 14 units running the acceptance / dilution firmware (v0.1.18, 20-min reporting): 8 acceptance-test units and 6 units pulled from the Boulder Creek field deployment. (50059 was offline 14:10–16:34 MT, so it has no 0-conc blank and is omitted from the normalized/calibration/prediction charts; it appears on the raw and temperature charts.)
| Group | Barcodes |
|---|---|
| Acceptance test | 500193, 50091, 500212, 50090, 500129, 50084, 500128, 500194 |
| Boulder Creek field | 50046, 50048, 50052, 50059, 50062, 50066 |
2 · Burn-in fleet ladder — 25 sensors, 2026-08-06
Merged in from the burn-in page 2026-08-21. The 25-unit burn-in fleet's own tryptophan ladder, read four ways: the single-combo mon2 the fleet used before the slope, the full-sweep amplitude, that amplitude temperature-corrected, and the ppb it predicts.
Stage 1Dilution calibration — offset and gain
Known tryptophan ladder dosed into the bath on 2026-08-06: 0, 0.1, 0.5, 5, 10 and 50 ppb. Every step is read as a plateau — the window is checked for drift before it is averaged. The 50 ppb window sits at 15:24–15:33 rather than the logged 15:19–15:29, because that dose was still mixing for its first five minutes (24.6 % rise inside the logged window, against ≤ 2.5 % for every other step). The ladder ran before the DI baseline began, which is why the clean-water stages do not read it.
All four panels are built the same way: the mean at each dosed level, per sensor, with hashes at the 95 % CI of that mean (Student t, since the 50 ppb step is only a handful of sweeps). Markers only — a segment drawn between two dose levels would assert a trajectory that was never measured. Each series carries an OLS regression across all six plotted levels, and the R² in the legend is that line’s.
mon2 at the typical operating point
The single-combo reading the fleet used before the slope:
mon2 at LED 512, SiPM bias nearest 3000, one sample, never averaged across
biases. Raw and uncorrected. This is the comparison baseline for the other three panels, and its weakness is
the point: it depends on that one operating point being the right one for that unit. Where auto-range has
moved a sensor elsewhere, the number stops meaning what it means on its neighbours. That is exactly the
dependency the full-sweep slope removes.
Full-sweep TLF slope (uncorrected)
tlf_amp, the two-way log-model amplitude of a
single sample: every dark-subtracted cell of the sweep
(screen 200 < mon2, cells at the 3250 ADC ceiling enter as
censored bounds, ≥6 cells) estimates the same
c in log(mon2 − dark) = aLED + bov + c.
(Replaced the pooled quadratic d/d(bias) slope, still shown on
tlf-dilutions, on 2026-08-13.) Because it pools the whole sweep, no single operating point can carry the reading, and
nothing time-series or temperature enters the feature itself. No temperature correction,
no gain, no offset: this is the signal itself, on the same axes as the panel beside it.
Same chart, temperature-corrected sTLF
Identical construction to the panel beside it, with one change: every sample’s slope is first divided by its own clean-water quench factor, so the two differ only by that correction. The quench is fit on the clean-water window alone (0 ppb throughout, DI outdoors, SiPM ~22 → 37 °C) as a cubic in temperature on log sTLF. The ladder itself cannot be used to fit it, because its temperature rise is collinear with the dose. This is the slope’s own quench, fit on the slope, not the mon2 quench.
Predicted ppb from the corrected sTLF
An offset and a gain taken
from the panel beside it — per sensor,
s = offset + gain · ppb — then inverted to give
predicted ppb = (s − offset) / gain. No other terms.
Plotted against the level actually dosed, with the dashed line at y = x. Six points
and two parameters leaves 4 degrees of freedom, so departure from the diagonal is residual, not zero by
construction. The legend carries each sensor’s R² for that offset/gain fit.
Clean water, so the truth on the panel above is zero and every departure from it is instrument. Two numbers matter: how far the corrected signal sits from zero (bias, which a per-deployment blank removes) and how much it moves about (noise, which nothing removes). The noise is the one that sets what a real measurement can resolve.
The ppb figures are the sTLF scatter divided by each sensor’s own gain from the Stage 1 ladder, mapped to 21 °C. They are therefore only as good as that gain: it was measured on one ladder, on a different day, over six dose levels. The percentages below need no such transfer — they are the scatter against that sensor’s own blank, measured entirely inside this window.
Against the published requirement
How good does this have to be? The literature answers that through the TLF concentration that corresponds to a given E. coli level. Sorensen et al. (2018) pooled groundwater and surface drinking-water data from India, Malawi, South Africa and Zambia (n = 564) and placed the WHO risk bands at 1.3, 2.4, 6.9 and 27.1 ppb for ≥1, ≥10, ≥100 and ≥1000 organisms per 100 mL. Independent field studies put the detection threshold in the same place: 1.9 ppb from thermotolerant coliforms and 1.7 ppb from E. coli in Malawi (Ward et al., 2021), 2.2 ppb in Uganda (Sorensen et al., 2021), 1.0 ppb in Kenya (Nowicki et al., 2019).
The recreational thresholds sit inside the published High band, so they are read by interpolating between 6.9 ppb at 100 and 27.1 ppb at 1000 CFU/100 mL: the EPA geometric mean of 126 lands at ≈ 7.9 ppb and the statistical threshold value of 410 at ≈ 16.0 ppb. That interpolation is ours, and it carries a drinking-water relationship into recreational surface water, which Ward et al. explicitly caution against. Treat the recreational rows as indicative.
Which noise applies. A threshold crossing is called at a moment, so the relevant figure is the short-term scatter, taken here as the standard deviation of successive-sample differences (÷ √2), which removes any slow drift. That is a different and much smaller quantity than the multi-day figure in the card above, and it is the one comparable to a published detection limit. Both are reported.
For scale, Sorensen et al. (2018) report field fluorimeter detection limits of 1.99 ± 0.53 ppb for the Cyclops-7 and 1.74 ppb for a modified GGUN–FL30, both of which fail their own 1.3 ppb threshold, against 0.17 ± 0.06 ppb for the photomultiplier-based UviLux; field repeatability in Sorensen et al. (2021) was σ = 0.4 ppb. Bedell et al. (2022) reported 0.05 ppb in deionised water for an earlier generation of this sensor.