In-Stream Intra-Sensor Comparison — BC-13
5 sensors · co-located in-stream at BC-13, installed 2026-07-19 noon MT · agreement of the TLF slope (full-sweep bias-response, replacing mon2), ToF turbidity, and temperature reading the same water
Overview
Five Lume units are installed together in the same reach at BC-13, all submerged in the same water since noon on 2026-07-19. Because every unit sees an identical sample, this is a field precision / reproducibility test: any spread between the traces is sensor-to-sensor measurement disagreement, not a difference in what they are measuring. It is the in-stream analog of the bench serial-dilution's sensor-to-sensor spread, but under real water, real turbidity, and a real diel temperature swing rather than a controlled bath.
Three channels are compared: the tryptophan-like fluorescence mon2_val (TLF, the primary
E. coli–bearing signal), the Time-of-Flight backscatter signal_per_spad_kcps (the
turbidity proxy), and SiPM temperature. TLF uses a best-SNR-per-unit combo (the default
below): each unit runs at the LED×bias that minimizes its concentration noise floor (blank
noise ÷ sensitivity) in the dilution while staying unsaturated in-stream — not simply the
highest unsaturated LED, which isn't always best. Here that puts 50062 at LED 32/bias 3468,
500212 at LED 128/3079, 500128 at LED 512/2942, 50090 at LED 32/3039 (halves its
noise floor, 2.5→1.1 µg/L), and 50084 at LED 512/2934 (a lower bias that avoids the
saturation which had forced it to 128). Each combo's own gain keeps the calibrated µg/L-equivalent
comparable across units. Absolute TLF still carries each unit's own baseline/gain offset (what the
per-sensor field calibration removes); the tracking agreement — do they rise and fall
together as the water changes — is the more meaningful readout, and is reported separately below.
Load Window
Live data pulled per sensor from the sensor API, every reading shown at full resolution (no aggregation). A sweep-health QC gate drops any acquisition cycle where the SiPM did not respond to the bias ramp (a dead cycle pinned at the pedestal, e.g. 50090 at 12:11); rejected cycles are listed below. The window is locked to the deployment period: noon 2026-07-19 (install) to noon 2026-07-23.
Inter-Sensor Agreement — Summary
Revisited 2026-08-21 with the
canonical TLF amplitude and the current correction stack. Five units in the same water, so
every difference between them is instrument. Agreement is measured on deviation from the fleet,
never on each sensor’s own trend: real changes in the water are common-mode and must not count as
disagreement, and a per-sensor detrend would quietly delete the shared signal along with the drift.
devi(t) = ln(Si) − ln(basei) − mediani,
binned to the 15-minute reporting cadence; figures are the median across-sensor SD of that deviation, in %.
Reproduce with scripts/instream_agreement.mjs.
| Fluorescence feature | raw | + quench @20 °C | + quench + drift | worst unit |
|---|---|---|---|---|
mon2 at the calibrated combo | 7.40 | 7.20 | 5.80 | 50062 11.9% |
| S-TLF slope | 6.15 | 6.46 | 2.35 | 50084 4.8% |
| Two-way log-model amplitude ◀ best | 6.31 | 6.31 | 2.20 | 50084 2.6% |
Drift is the whole story; the
estimator decides the tail. Removing differential drift takes the amplitude from
6.31 % to 2.20 % — a 2.9× tightening and the single largest effect here.
Amplitude and slope finish within 0.15 % of each other on fleet spread but differ on the
worst unit: 2.6 % for the amplitude against 4.8 % for the slope. Absolute
mon2 never gets close, bottoming out at 5.80 %. Per-sensor after correction:
50090 1.16 %, 50062 1.82 %, 500212 2.35 %, 500128 2.51 %,
50084 2.64 %.
The per-sensor quench does not help here, and that is not a contradiction. These five share water, so they share temperature. A quench applied to a common T is a common-mode shift, which the fleet-median subtraction cancels exactly — a uniform ρ leaves the number unchanged (6.31 → 6.31, measured). Only the differences between per-sensor coefficients act, and here they made agreement worse (6.31 → 6.85). Per-sensor quench earns its place across sites at different temperatures; within one stream it can only add noise unless the coefficients are right.
This test found a real defect in the quench table. 50084 and 50090 were fitted on a
“clean-water cooldown” of 2026-07-21/22 — a window this very archive shows them spending
in Boulder Creek. Neither carries a site_installations row, so the in-creek guard never
fired: install windows are authoritative but incomplete, and a unit with no window was being
treated as never deployed. Their coefficients were fitted on river water, which
the twin forbids at §12.3b. 50062’s
value is stale for a different reason — it dates from April, before that unit was repaired and
redeployed on 06-25. The generator now carries an explicit known-deployed list.
Raw TLF (mon2_val) — at each unit's operating combo
The raw single-combo mon2 per unit (auto-ranged LED, bias ≈ 3000; hover shows the
LED). Under auto-range the units run at different LEDs and several rail near the ~3299 ceiling, so the absolute
levels are not directly comparable here — which is exactly why the TLF slope
below replaces it as the signal. Shown for reference.
TLF slope — Full-Sweep Bias-Response (replaces mon2)
The signal is the TLF slope (sTLF) — the full-sweep bias-response
derivative at bias 3000, ×10³ (see the definition box on the dilution
page), replacing absolute mon2. It is computed once per reading from the whole
LED×bias sweep, so it needs no per-unit operating combo and cannot rail — the auto-range /
saturation problems that made raw mon2 non-comparable across these units simply don’t arise.
(Absolute levels still differ by each unit’s gain; the calibration below maps them to µg/L-equivalent.)
Calibrated TLF slope — “TLF slope temp + turbidity corrected” → µg/L-equivalent
Each unit's TLF slope is first temperature-corrected to 20 °C — “TLF slope temp corrected” — then mapped into µg/L-equivalent tryptophan with a per-sensor gain (and optional curvature) fit from the 2026-07-16 serial dilution in slope units. Reading the same water, the five traces should collapse onto one line. Which they do depends on where the offset comes from:
s₀ = sTLF·eρ(20−T)
(Watras et al. 2011, as used in Bedell et al. 2022 for this sensor), using that unit's own
coefficient ρ (ln(TLF slope) vs SiPM temp) — this is the “TLF slope temp
corrected” signal. Here ρ is fit empirically from this
deployment because the dilution's 22–34 °C steps under-correct the steeper 20–23 °C
field response; it then zeroes to the median of the cleanest period (the cleanest ~15% of
time, selected from the smoothed signal). That baseline is de-biased: the old
5th-percentile floor sat ~1.6σ below the true zero, so noisy units read systematically high (a +6 µg/L
bias on 50090); the median of the clean period is unbiased regardless of noise, and readings are not clamped
to ≥0 (a true-zero reading must wobble slightly negative). 50090 (weak responder) and 50084
(most temperature-sensitive) carry wider honest noise, but are no longer biased.
r = −0.94 on 50090/50084 versus only −0.36 on the low-gain
500212. Crucially this is not an operating-point choice — tightening the saturation screen or
restricting to the linear region leaves r at −0.9 and the dilution response unchanged, so
it can't be measured away by running the unit lower; it is real optical attenuation. The fix is a single
rule: regress each unit's slope on its own ToF backscatter and subtract the turbidity term
(referenced to that unit's mean backscatter). The coefficient β falls out near zero where
turbidity doesn't matter (500212 −0.04, essentially untouched) and removes it where it
does — no per-sensor branching and no exclusions. This pulls 50090's field p95 from ~163 to ~53 µg/L,
into agreement with the well-behaved units reading the same water.
Predicted E. coli — Calibrated TLF × Temperature, per Sensor
On 2026-07-20, five Colilert E. coli grabs were taken at BC-13.
Because all five units sit in the same water, each grab is ground truth for every
sensor (mWater logs them against primary 50062 with the rest in second_barcode; here
each grab is paired to all 5). The table pairs each grab to every unit's calibrated TLF at that instant
(the spread column is the co-located agreement); the chart below turns that calibrated TLF,
plus temperature and their interaction, into a predicted E. coli trace per sensor.
Predicted vs actual log₁₀(E. coli), per sensor. A minimal two-term map,
log₁₀(E. coli) = b₀ + b₁·TLF (TLF = the unit's calibrated µg/L-eq) — temperature and the
TLF×temperature interaction were dropped to cut overfit. Each marker is one sensor at one grab:
x = actual Colilert, y = model prediction, with a per-sensor
regression line. The 249 CFU grab is dropped as a suspected error (excluded from
the model, the points, and the fits). Horizontal bars are each grab's IDEXX Quanti-Tray/2000 published
95% CI — the remaining 34/41/58 CFU grabs all overlap, so Colilert itself resolves essentially
one level here while the sensors spread across the y-axis. Dashed grey = 1:1; 126 CFU
cross-hairs = exceedance quadrants.
Calibrated TLF — Deviation From the Fleet Median
Each unit's calibrated TLF minus the across-sensor median at that instant, in µg/L-equivalent (each other unit's nearest reading within 12 min), all points, no binning. This is the residual disagreement after calibration, using the mode selected above; if the calibration makes the five identical, every trace sits on 0. Bands mark ±2 and ±5 µg/L-eq.
ToF Turbidity (signal_per_spad_kcps → NTU)
Per-SPAD photon backscatter rate, the turbidity proxy (higher = more scattering particles). One reading per
sweep cycle. Co-located units should report the same particle load. Raw signal_per_spad per
unit first; the calibrated turbidity below uses the same model as the
TLF-dilutions page: NTU = k × (SPS − SPS₀),
with each unit's clean-water zero-point SPS₀ from the 2026-07-16 dilution 0 ppb step
and pooled slope k = 1.59. In the same water the five NTU traces should agree.
Two QC steps run first: a distance gate drops readings whose ToF range jumps off the cap
target (bubble/particle mis-range), and a stability flag marks any unit whose
reading-to-reading jitter is far above the fleet as a suspect (unstable detector) —
shown dashed with a ⚠ and excluded from the agreement spread.
ToF Distance (distance_mm) — the second ToF feed
The ToF sensor returns two channels: the signal_per_spad_kcps backscatter above (turbidity) and
the ranging distance to the cap interior it bounces off. In clean, stable operation the distance
sits at each unit's fixed cap geometry (~70 mm); downward spikes are a bubble or particle
mis-ranging onto something nearer than the cap (these are what the turbidity distance gate drops), and a
slow drift would indicate the optical target changing (fouling on the cap). Shown pre-gate so the
dropouts are visible.
SiPM Temperature
SiPM (detector) temperature per unit — the correct thermal covariate. (The
diagnostics temperature field is the board temperature, which self-heats from the
electronics and is not representative of the water, so it is not used; see the channel comparison below.)
Submerged together, the units should read within a few tenths of a degree; a persistent gap flags a
temperature-sensor offset. Temperature quenches TLF, so this is the covariate driving the quench correction.
Deviation From the Fleet Median
Each unit's temperature minus the across-sensor median at that instant (each other unit's nearest reading within 12 min), all points, no binning. Submerged in the same water, every trace should sit on 0; a persistent offset is a per-unit temperature-sensor bias (and it feeds straight into the TLF quench correction). Bands mark ±0.1 and ±0.25 °C.
Smoothed SiPM Temperature
Rolling-median smoothed temperature per unit, which separates each unit's real thermal trend from
reading-to-reading noise. An excursion that survives smoothing is a real temperature difference;
one that washes out was measurement noise. This is the cleaner temperature to drive the TLF quench
correction (noisy T injects variability through eρ(20−T), amplified on
high-gain units like 50090). Raw readings are shown faint behind each smoothed trace.
All Temperature Channels — water · SiPM · UV-LED
Each unit reports three temperatures: board (self-heated by the electronics, not the water), SiPM (detector), and UV-LED (excitation source). One panel per unit so you can see how the channels differ within and across units. The board runs ~1 °C above the two internal temps (its self-heating offset); SiPM and UV-LED track together. The quench correction uses the SiPM temperature — the board's self-heating makes it unrepresentative of the water.
Sensors Under Test
Five units co-located in-stream at BC-13 from noon on 2026-07-19. 50062 was previously a Boulder Creek field unit; the rest are acceptance-test units now joining the field.
| Barcode | Prior role | Channels |
|---|