All work
2026/ Hardware · R&D/ Stars of Science · applicant

Acoustic Water-Leak Localizer

A low-cost device that finds buried water leaks by listening from two points and correlating what it hears. Tuned specifically for plastic pipe, where the conventional correlators utilities already own tend to fail, and cheap enough that a municipality can own several without a specialist to run them.

Interactive demo

Move the leak · the correlator locates it from the two signals

correlator · 100 m span, dual hydrophone
A · 0 m B · 100 m leak
50
30

The device

Two clamp-on sensors and a handheld unit

Two clamp-on sensors feeding a handheld unit that reads 'Leak found: 14.2 m from Valve A'
The operator gets a distance, not a correlation plot to interpret.
Diagram of how the leak localizer works end to end
Clamp on, listen, read the number. The whole field workflow.

At a glance

Stage
R&D concept · simulation
Method
Cross-correlation + classifier
Target
Plastic pipe, where correlators fail
Problem
>40% non-revenue water

The physics

One equation does the locating

sensor A sensor B leak · continuous noise d L − d Δt = (L − 2d) / c → d = (L − c·Δt) / 2
Both sensors record the same signal, shifted. The correlation peak is Δt.

Plastic attenuates high frequencies hard, so what reaches the sensors is low-frequency and narrow-band, which makes that peak broad and shallow instead of sharp. Push the noise slider in the demo and you can watch it flatten until the classifier refuses to call it. That is the exact failure mode this design targets.

Code

What runs on the microcontroller

firmware/correlate.py the same maths the demo runs live

def locate(sig_a, sig_b, span_m, velocity, fs):
    corr = np.correlate(sig_a, sig_b, mode="full")
    lag  = corr.argmax() - (len(sig_a) - 1)
    dt   = lag / fs

    d = (span_m - velocity * dt) / 2.0
    return np.clip(d, 0, span_m), corr
firmware/validate.py the part that replaces the specialist operator

def is_real_leak(corr, history):
    peak = corr.max()
    prominence = (peak - corr.mean()) / (corr.std() + 1e-9)

    # a real leak holds still; pump harmonics and traffic wander
    stable = np.std([h.position for h in history[-5:]]) < 1.5   # metres

    if prominence < 4.5 or not stable:
        return Verdict(False, "reposition sensors, peak not trustworthy")
    return Verdict(True, f"located, {prominence:.1f} sigma")

The operator gets a position and a verdict, not a plot to interpret.

Skills, in context

Where each one actually showed up

Signals & systems The correlation running live above, plus band-pass design for plastic's lower, narrower usable band.
On-device ML The peak-validity classifier in validate.py: prominence plus stability across windows.
Embedded systems Power and sampling budget, which sets window length and how often a measurement can run.
Acoustic sensing Sensor coupling and material velocity: a 20% error in c digs in the wrong place.
Back to the start 3ayn