Virridy Home | Lume — Water Quality Sensing Water for Carbon

What the drift experiments have established

One account across five records: the burn-in fleet (25 units, August), the four-batch barrel (21 to 29 August), the vacuum degassing rig (20 to 21 August), the spike test (29 August to 2 September) and the daily-calibration test (8 TLF units, seven ladders, 22 to 25 September, with the drift and rhodamine challenge of 1 October). They answer four questions: what moves the reading when nothing in the water changes, whether temperature can be corrected, how the gain changes, and what calibration procedure those answers lead to.

Charts and the figures inside them are computed from the archived sweeps by scripts/build_findings.py. Figures from the daily-calibration test are computed on that page and its scripts, and are quoted here on the same basis.

The short version

The largest error in the record is light released inside the sensor when it is handled: an additive step on the zero that holds for one to two hours and relaxes over about ten. Temperature is correctable on each unit's own coefficient, with a small unit-specific residual. Once a unit is settled and left alone its zero moves under 1 %/day. The gain moved about 15 % over seven weeks without handling, and the FDOM puck does not track it. A procedure that never touches the unit between its zero and its reading cuts the error at 50 ppb from 10.9 to 4.2 ppb.

1Handling releases light, and that is the largest error

Every time a unit is disturbed its S-TLF steps up, on every unit, by an amount that does not scale with the reading. Each cap opening adds a median 1.07 S-TLF on 8 of 8 units, flat across a 15-fold spread in pedestal, so the step is additive and it is compared across events in S-TLF rather than in percent. Ranked on that scale, median over the eight units, 2 to 8 min after against the 6 min before (daily-calibration test, run 7):

EventAirCapStep, S-TLFStep, %
Shake in the bath (three of them)nountouched+0.32 to +0.452.0 to 3.6
Quarter turn under waternoloosened+0.472.7
Cap off and on under waternoremoved+1.198.6
Out of the water and back by handyesuntouched+1.8813.6

What orders the four is how completely the water at the window is exchanged. The out-and-back step matches the burn-in figure for handling a submerged sensor, about +14 %, while the same handling done entirely in air moved the burn-in fleet a median −0.06 % (n = 22).

How it behaves

Agitation alone is enough. The degassing rig's control shake at 16:27 on 20 August, with the tank open and no vacuum, stepped 500226 by +14.6 % and 500225 by +4.7 % on the uncorrected amplitude (6 min before against 2 to 8 min after); the other three moved −2.0 to −0.2 %. The seven barrel units whose S-TLF rose more than 5 % with ToF unchanged when the barrel was shaken, and 500146 rising after its shake on the rig, are the same step.

Ruled out: SiPM saturation and slow recovery (the step holds flat for 40 min where recovery would decay), temperature, photobleaching of the cavity water (a removal in 50 ppb gave no larger step), anything carried in the cavity water such as particulates, a gas film or a thermal gradient (a shake exchanges that water and gives +0.3 to +0.5 against +1.2 to +1.9 for opening the joint), air carried in on reinstall (8 of 8 units, every time, at the same size, with de-bubbling every time), and cap orientation (caps keyed since run 5, steps unchanged).

Still standing: stress relaxation in the compressed elastomer of the cap joint, the window or filter shifting on its mount, and a pinned capillary film at the cap-to-bezel contact line. Pressing the cap under water without turning it separates the first two from the third; the same disturbance in a 10 °C and a 25 °C bath separates elastomer creep from a film; a dial indicator on the cap and window over 10 h says which surface moves.

The zero and the reading have to be taken in the same handling state, and the relaxed overnight state is the reproducible one. In the daily calibration as run, the cap was opened between the blank and the test, and DI, which should read zero, read 10.4 ppb in runs 1 to 6. With the same opening done under water in run 7 it read 0.9 ppb. Nothing about the clock changed between the two.

2After per-sensor correction, does the barrel baseline go flat?

The barrel is the one record where all four batches sit in the same water at the same time, and its 20 to 21 August heater-then-chiller ramp separates temperature from elapsed time. The question is whether, after correcting each sensor for quench, thermal lag and drift, what remains is flat.

Leaving out Chl-a, raw scatter of — falls to — once temperature is removed and to — once drift is removed as well.

Mostly it does not. The correction is fitted on — of the units in the barrel, with nothing dropped for fitting badly, and — reach a flat baseline under 1 %. The median residual is 1.73 % for FDOM, 4.52 % for the burn-in fleet and 7.60 % for the five new TLF units; the Chl-a batch, which returns no amplitude on most of its DI readings, cannot be corrected at all. The barrel record contains the immersion transient and the 20 August shake, and section 1 shows the size of the step a shake leaves. One of the new TLF units, 500156, is a hardware fault on four independent axes (section 8). Out-of-water readings are filtered here: three such rows in 1,291 took one unit's apparent noise from 0.75 to 21.5 %.

The same model run over the burn-in campaign (Stage 10) passes 24/24 units in the cold hold and 23/24 in air, windows spanning 0.3 and 3.4 °C, but only 7/25, 5/25 and 12/24 on the wide-swing outdoor windows a deployed sensor lives in.

3Temperature is correctable on each unit's own coefficient

On the burn-in fleet each sensor's coefficient is the same in water and in air and across two weeks, when it is fitted on 5 h windows. Fitted jointly with a linear time slope over 72 to 77 h windows the coefficients look unstable (between-window correlation +0.014), because drift is not linear and a long window folds its curvature into the coefficient. Short windows remove that.

bT per unit, by condition

Each dot is one sensor's own coefficient from repeated short windows.

Do units differ from each other?

Spread between units against each unit's own scatter. Below the line, per-unit calibration is fitting noise.

Quench is fitted per sensor, on that unit's own sipm_temperature, and no fleet or batch constant is used anywhere. Where a window spans too little temperature to identify a coefficient, it also carries too little quench to need one: under 0.5 °C is worth less than 1 % at a typical −1.7 %/°C.

It does measurable work in the calibration. On the eight drift-cal units the coefficients run from −0.89 to −2.61 %/°C, and window temperatures across the seven runs span 15.9 to 28.3 °C. Switching the correction off moves the 50 ppb reading from 98 to 92 % and the median error from 4.63 to 7.56 ppb.

A small residual survives, and it is unit-specific. Regressing the 50 ppb reading on window temperature within each unit leaves a median +0.43 %/°C, 6 of 8 positive, with 500212 over-corrected (−1.37) and 500227 under-corrected (+2.42). DI read across runs still depends on run temperature by a median 0.76 %/°C. On 500140 refitting ρ from −1.43 to −2.09 %/°C takes its DI spread across runs 1 to 4 from CV 4.6 to 1.2 %; 500103 shows no residual at all. Refitting ρ across runs absorbs between-run level steps as temperature and returns coefficients as steep as −8.6 %/°C; the test is a deliberate ramp at constant analyte (see open questions).

4Drift is mostly settling after a disturbance

Most of what this program has called drift is a transient following something that was done to the unit, and each kind of disturbance has its own timescale:

DisturbanceHow long it takesWhere measured
Cap opened or unit handledRaised level holds 1 to 2 h, then relaxes over about 10 to 14 h to a baseline that repeats morning to morningDaily-calibration test, both DI overnights
Unit taken out of waterRate of change falls from about −6 %/day to under 0.5 %/day by day 3 and to near zero by day 4The three days after the daily-calibration test
Immersion, low-background unitClimbs for about a week (+17, +11 and +6 % from 23 to 27 August), then flatBarrel, constant 22 to 23 °C; spike pre-dose stretch
Immersion, bright unitUnder 2.5 days; not resolvable under the barrel's temperature swingBarrel
Water changed around a settled unitComplete within the 10 min mixing waitSpike dosing, 1 September
Settled and left alone, the zero barely moves. From 29 to 31 August, nine to eleven days after immersion and untouched at 22.4 °C, S-TLF moved −0.2 to −0.9 %/day. Over the last 3.4 days of the barrel the bright units ran +0.1 and −0.1 %/day. On the bench an undisturbed zero moved about 0.08 S-TLF an hour, so reading the sample 20 min after the DI costs 1.21 ppb of detection limit against 1.12 back to back. Nothing in these records shows a persistent slope that does not follow a disturbance and is larger than about 1 %/day.

The burn-in record, read in that light

The burn-in drift windows are bounded by events and opened 2 h after each one, so every one of them starts inside the relaxation that follows a handling event. Cut that way, — of — windows are separable (time and temperature not collinear) and drift is estimable per sensor; the two that are not are the post-UV window and the barrel tank phase. Earlier windows that straddled several interventions measured the steps: “Water, days 2 to 5” crossed the UV dose, the blackout caps, the basin carry and an in-place shake, and read −13.56 %/day against a half-window disagreement of 20.74.

Temperature is fitted jointly per unit, so quench cannot leak into the time slope. w is how many separable windows a unit contributed and rel how many pass the split-half check. Immersion is 16:45Z, where ToF steps 140 → 46 kcps in all three batches at once; local time is UTC−6.

Per-sensor drift, all units, air and water

Air against water, and the batch spread

The burn-in fleet is the only batch measured in both media, so its two rows are the same sensors under the two conditions. Air is the only medium in which all four batches have data.

Which windows carry a number

A joint fit means something only where time and temperature are separable inside the window. |corr| above 0.9 means the two regressors are collinear, so the window is reported as not separable.

What it looks like

The same 24 burn-in units in both panels, 20 h apart, each temperature-corrected and normalized to its own first settled hour. The line is the fleet median, the band the interquartile range.

Water

Air

In water the fleet falls about 1.3 % over 44 h with a narrow band, so the units move together. In air the median barely moves and the band straddles zero.

An uncontrolled window

The same units in water on a 15 °C diurnal swing. Per-unit rates spread from −15.7 to −1.1 %/day across the interquartile range, so no single drift number describes the fleet.

Bars are the drift each window reports; the marker is how far the two halves of the same window disagree. Where the marker exceeds the bar, the number measures nothing.

A good window still decays

Successive 6 h blocks inside the one reliable hold. The early blocks are the settling transient, so a short hold overstates the rate.

Extrapolating a slope mostly makes prediction worse

Fit a slope on past data and predict forward, against assuming the last baseline holds.

A fitted slope does not carry forward reliably. Extrapolating it is worse than assuming flat in four of six train and predict configurations, by 1.4 to 1.9×, and better in the other two by 1.1 to 1.2×; it helps between 0 and 16 of 25 units depending on the configuration. A rate term cannot represent a decaying transient or a step.

How long a baseline holds on these windows

Error against a 6 h baseline as a function of the baseline's age, on the burn-in windows.

On these windows a baseline is within about 2 % at 6 h and 15 % off by 12 h. That is the span of the post-handling relaxation, and each window opened 2 h after an intervention. On an undisturbed, settled unit the zero holds far longer (above); what limits a stored zero is the next disturbance.

5Gain changes slowly, and offset and gain are both required

Four corrections sit between a raw sweep and a number, and each does a different job.

StepWhat it removesScope
Amplitude estimatordependence on which cells survived screening: railing, pedestal pinning, cell dropoutone sensor, one sweep
Quenchtemperature, on that unit's own coefficientone sensor, over temperature
Zerothe unit's level, including any handling step, read in DI in the same handling state as the sampleone sensor, one run
Gainthe unit's own sensitivity, counts per ppbacross sensors, absolute scale

The amplitude is a ratio to each unit's own reference sweep, so it normalizes a unit against itself and leaves every unit near 1 at its reference state regardless of how many counts per ppb it delivers. Only a per-sensor gain makes two sensors comparable. On the 16 July dilution ladder, 13 sensors, the gain spans 10.6× and the blank 2.2×; across the wider burn-in fleet the gain spans 27×. One shared offset and gain in place of per-sensor values takes R² from 0.815 to 0.120 and RMSE from 7.14 to 15.58 ppb (scripts/dilution_feature_compare.mjs). The blanks fall into two groups, about 0.52 to 0.64 and 0.96 to 1.12, matching a two-tier gain structure (about 93 to 118 against 404 to 983). One unit, 50091, has a negative fitted gain (−0.00054 at R² 0.30). The amplitude estimator ties absolute mon2 on well-behaved units (pooled R² 0.9087 against 0.9097 on the 12 both fit) and rescues the hard ones: it fits 13 of 14 where mon2 fits 12, with 50091 going from 0.4835 to 0.8131.

How the gain moved

Every cap opening the eight drift-cal units have had is logged, so 6 August to 22 September is 47 days with no handling. A gain is the difference of two levels taken with no cap opening between them, so an additive step cancels out of it; an offset is a level and carries the step.

The FDOM puck does not track the gain. Within a unit across runs, the puck response and that run's ladder gain correlate at a median −0.17 (against the blank) and −0.08 (against the DI test), 3 of 8 units positive. A fixed puck expressed in ppb through each unit's own ladder varies 28 % run to run. Rescaling a stored gain by the puck each run takes the median error at 50 ppb from 4.8 to 12.4 or 17.3 ppb. Its 28 % noise exceeds the gain drift it would correct, about 0 % within a week and 20 % over 47 days. It stays useful as a diagnostic, since it is the one fixed optical reference and it is what exposed the cap-opening step, and it stays out of the calibration path.

An aging term on the stored gain works, and is not yet a physical rate. Aging each unit's stored gain on its own sample-cycle count, refitted leave-one-unit-out and at every reference run, beats the alternatives on 7 of 8 choices: 6.02 ppb median error against 7.67 with one fleet scalar and 9.67 with no correction. The fitted rate swings from −0.08 to +6.65 % per 10,000 cycles with the reference run and changes sign at run 5, so what it reliably does is remove a fleet-wide shift and treat 500128 differently. A third commissioning ladder per unit, spaced in cycles, would test the shape.

6The procedure these findings lead to, and what it reaches

Commissioning, once per sensor. The unit goes into a vessel of DI and does not come out, and the cap does not come off. Read DI, spike the same vessel to 5 ppb and read, spike to 50 ppb and read. Gain is (S-TLF at 50 ppb − S-TLF at DI) / 50 on the unit's own quench coefficient; repeat the ladder two or three times, store the median, and store the unit's cycle count with it.

Every run. Read DI, then the sample, with nothing touched between them: no cap opened and the unit not lifted. ppb = (S-TLFsample − S-TLFDI) / gain, with the stored gain aged to the current cycle count and every term temperature-corrected on the unit's own coefficient. A new or re-immersed low-background unit needs about a week in water before its zero is stable enough to store.

Arm, 47 unit-runsDI reads5 ppb rec / err50 ppb rec50 ppb errDay-to-day CV, 50 ppb
Procedure, gain = median of earlier ladders0.076% / 1.7102%4.2 ppb18%
Procedure, gain from run 10.071% / 1.697%4.8 ppb17%
Procedure, 6 Aug gain aged on cycles0.073% / 1.697%5.6 ppb17%
Procedure, 6 Aug gain, no aging0.081% / 1.1108%6.5 ppb17%
Daily blank + puck calibration, as run8.0 ppb220% / 6.8115%10.9 ppb23%

Scored on the identical 47 unit-runs every arm can reach, run 1 excluded (no arm is scored against its own gain) and 500227's run 4 ladder excluded (that unit never saw the 50 ppb solution: its reading is its 5 ppb level plus one handling step).

Reproducibility is set by the reading. Every procedure row lands at 17 to 18 % day to day whatever the gain source, because dividing by a constant cannot change a coefficient of variation; the daily calibration sits at 23 % because its divisor is re-measured every run. Nothing clears the 10 % bar the protocol set. The gain's age shows up in accuracy instead: 4.2 ppb on a gain from the same week, 6.5 on one seven weeks old, 5.6 once that old gain is aged on cycles.

Per unit, seven of eight read 91 to 111 % at 50 ppb with 2.4 to 5.6 ppb median error. 500128 reads 125 % with 13.4 ppb (section 8).

Detection limit. Computed for the procedure as run, 3 σ(zero) / gain with the zero's noise measured on undisturbed stretches, and converted to E. coli with the published tryptophan conversion: the fleet median clears 10 CFU/100 mL but only 4 of 8 units do on their own, spread 4 to 43 CFU/100 mL, and every unit clears 200. The zero's noise comes from about 70 min on one day. On deployed sensors against paired Colilert grabs the signal first clears chance at 100 CFU/100 mL; resolving a part per billion of tryptophan in DI and separating river water at a threshold are different claims (derivation).

7Bubbles need supersaturated water

Pulling a vacuum on a sealed container of DI grows something on the optical window, and releasing the pressure removes it. 500226 reached 13.4× its baseline under vacuum and returned to 0.93× when the container was opened.

Temperature is excluded: the SiPM moved at most 0.17 °C across the vacuum, worth at most 0.4 %, against +1,238 %.

In ordinary use they are rare. Across 10 days of the burn-in fleet submerged in DI, sample-to-sample jumps above 5 % occur at a rate of 0.061 %, and 6.7 % of those have a matching ToF move. Freshly poured DI is not supersaturated.
How to call a bubble. Coupling with ToF is not required: through a sevenfold S-TLF change in the second vacuum cycle, 500226's ToF stayed at 1.00 to 1.02, because the ToF and fluorescence optics do not share an aperture. Nor is coupling sufficient: after the UV firmware reverted, with the fleet in air, S-TLF and ToF correlated at r = +0.964 from a shared reboot transient. The discriminator is reversal on pressure release.

7bThe degassing rig

Closed, data frozen. Final pull 2026-08-21 19:38Z, 6,974 sweeps from 2026-08-20 15:29Z to 2026-08-21 19:35Z. 500146 stopped producing sweeps at 2026-08-20 22:42Z (376 rows against 1,603 to 1,678 for the others); its one later reading, 08-21 19:35Z, is in air (ToF 141 against an in-tank median of 55) and is not part of the experiment. The degas cohort is frozen in scripts/export_burnin_sweeps.js; re-pulling needs --thaw.

Five units, 500220, 500225, 500226, 500108, 500146, in a sealed pressure container of DI, in at 09:29 local on 20 August with the vacuum applied at 10:50. The 81 min between them gives each unit an undisturbed water baseline, so a move at the vacuum line is attributable to the gas.

The vacuum steps

loading…

The degassing record

The record begins at immersion (09:29), so there is no dry-air record and no air-to-water step here. Each unit is normalized to its own median over the 30 min before the vacuum, so 1.0 is the settled in-water baseline. Rows the out-of-water detector flags are kept: at immersion that flag is the transition.

S-TLF, normalized to the pre-vacuum baseline

Full-sweep amplitude (tlf_amp). Watch for steps, not slope.

ToF

Signal per SPAD.

SiPM temperature

A vacuum drives evaporative cooling and S-TLF is quenched by temperature; it moved at most 0.17 °C across the vacuum.

Battery

Pack voltage; these units ran on battery.

Per-unit vacuum step and current state

What each intervention showed

The tank blocks the cellular uplink while sealed, so readings buffer on the device and back-fill when it is opened; the export is keyed on database row id so late rows with old timestamps are collected in full.

Cycle 1. Under vacuum 500226's S-TLF climbed over 13 to 15 min to 13.4× its pre-vacuum baseline and held for the full 68 min, with ToF roughly doubling. At 11:58 the vacuum was released, the container opened and the units shaken at one instant; both channels fell to baseline (S-TLF 0.93×, ToF 1.00×). 500225 did the same at smaller size (1.78× to 1.50×). The prompt ±15 min response (median +0.9 %) understates an effect that grows under sustained vacuum; the peak-under-vacuum column is the one to read.
Cycle 2. 500226 rose from 0.88× to 6.99× under the second vacuum and came back to 0.87× when the tank was opened at 16:04, returning to the same baseline within 0.01× across two cycles; its ToF did not move. 500225 went 1.32× to 1.83× (ToF 1.64×). With the pump and a shake together at 14:05 it rose 0.87× to 6.40× within one minute against 13 to 15 min in cycle 1: agitation nucleates supersaturated water. A shake under sustained vacuum at 15:29 moved 500225 by +2.1 %.
The control, 16:27. Tank open, no vacuum, units back at baseline: a shake with no gas driver. 500226 stepped +14.6 % and 500225 +4.7 %; 500108, 500146 and 500220 moved −2.0 to −0.2 %. Agitation alone moves the signal, which is the handling step of section 1, distinct from the pressure-reversed bubble effect above. Only two of five units responded to either. 500108 and 500220 stayed flat under vacuum; 500146 moved on S-TLF alone and rose after the 11:58 shake (1.42× to 1.93×), the handling step again.

8The four batches, and units that look like hardware

Three optics builds from the August 2026 variant run (FDOM, Chl-a, TLF) and the older burn-in fleet.

Temperature response differs between builds

FDOM quenches about 2.4× harder than Chl-a, and its interquartile range does not overlap that of any other batch. The two TLF batches have tight ranges; the Chl-a range spans zero.

The two TLF batches agree. New TLF units read −1.78 %/°C and the burn-in fleet −1.59, same optics at different ages, so the spread between builds is the optics. The coefficient is still fitted per sensor (section 3); a TLF coefficient is never applied to an FDOM unit.

Drift in air, by batch

Same window for all four (08-19 to 08-20, in air, temperature-corrected). The reliability column is the split-half check.

The medians differ, Chl-a steepest at −2.38 %/day and the burn-in fleet nearly flat at −0.28, but no batch passes the split-half check, and batch is confounded with age (the variant builds were 1 to 2 days old, the burn-in fleet 13 to 15) and with time since handling, so a batch difference in drift is not established.

Response to the barrel shake, by batch

All units shaken at one instant in shared water, temperature-corrected; 41 have enough readings either side to score.

The FDOM, new TLF and burn-in medians sit within 1 % of zero, and no unit moved more than 5 % on both channels. Twelve units moved more than 5 % on S-TLF with ToF unchanged; seven of them rose, the direction of the handling step (section 1).

The Chl-a batch shows no response. In DI it returns no amplitude on — of its readings, which DI alone would explain since it holds no chlorophyll, so these units are scored only against each other. On 1 October nine reporting Chl-a units were dosed with rhodamine WT to 5 ppb, 2 mg/L and 20 mg/L, doses at which reference instruments respond, and every sweep sat within one count of the pedestal (173 to 179 counts) at every dose and through both handling events. The cause is not identified. On the same doses the TLF units rose 15 to 30 % (low-background) or fell 14 to 27 % (bright) at 2 mg/L and fell 42 to 79 % at 20 mg/L, the pattern of absorption by the dye.

Units that look like hardware

Every unit in the barrel is fitted and reported, and each is scored against its own batch, never the fleet. A unit is listed when it exceeds 4 MAD above its batch on an axis or trips an absolute fault rule; three or more independent axes is rework, two investigate, one watch. The barrel ran a long temperature ramp rather than a hold, so corrected residual is used only as a tie-breaker.

500128 on the daily-calibration test: 125 % at 50 ppb with 13.4 ppb median error against 91 to 111 % and 2.4 to 5.6 for the other seven; a blank three to ten times noisier (σ = 0.29 S-TLF against 0.02 to 0.07); the only unit whose gain fell over the seven weeks; a negative 5 ppb rise in two runs; 94 % internal humidity.

What is still open