Offline

Centered RMS

zero-lag twin
time-domainzero-lagsingle-carrierRMS ≈ 0.707×

An envelope detector traces the loudness contour of a waveform — the slow outline riding over the fast carrier inside it. Every graph on this page is drawn by the method's real algorithm, and the sliders at the top drive all of them at once.

The whole method, live

Centered RMS
level 0.581280 samples
Hilbert refCentered RMS
Window16 samp (0.3 ms)

Score card

Causality
zero-lag
Signal model
single-carrier
Reads
RMS ≈ 0.707×
Latency
none (zero-lag)
Cost
cheap
Domain
time
Reads (measured on a steady sine)0.71×

Tracking error vs the true envelope, by challenge axis — longer bar is a tighter fit. Computed live across the oracle generators.

Temporal
9%
Robust
30%
Spectral
6%
Boundary
24%

How it works

A zero-lag RMS envelope: square each sample, average the squares, take the root. The trick is the averaging window — it is centered on each sample, drawing on equal numbers of future and past samples rather than only the ones already behind it. Because the window straddles the point it measures, the time lag is erased: the curve sits right on top of the signal instead of trailing behind it.

It reads ≈0.707·A for a sine of amplitude A, a smooth power-true outline of the swell. The catch is that it is non-causal — it needs samples from the future, so it can only run on recorded material, never a live stream.

Key terms

Centered (symmetric) window
An averaging window that spans an equal number of past and future samples around each point. Because it is symmetric about the sample it measures, the result has no time shift — the envelope lines up exactly with the signal underneath it.
RMS
Root-mean-square: square every sample, average the squares, then take the root. Squaring weights big excursions harder, so the result tracks power rather than raw amplitude — it reads 0.707·A for a sine of amplitude A.
Non-causal
A process that uses future samples to compute the present output. It can only run on recorded material, where the whole signal is already in hand — never on a live stream, where the future hasn't arrived yet.

Building the envelope, step by step

Each step adds one idea and shows a graph with only that principle applied — drawn by the real algorithm on the page's own input, working up to the finished curve.

  1. Step 1The carrier

    Start with the raw waveform — a fast carrier whose height swells and fades. The envelope is the slow outline we want, not the fast wiggle inside it.

  2. Step 2Square

    Square every sample with . Like rectifying, this makes every value positive — but it weights big excursions harder, which is what makes the result a measure of power rather than raw amplitude.

  3. Step 3Centered mean, then root

    Average the squares over a window centered on each sample — half its samples before, half after — then take the square root. Because the window straddles the sample instead of trailing it, the curve has zero lag: it sits right on the swell rather than behind it.

The code

Six readable forms of the exact algorithm that draws the curves above — C, JS and Python ports, an optimized C, a fixed-coefficient version, and a user-controlled one whose parameters match the sliders.

#include <math.h>

/* Centered (zero-lag) RMS: square, centered moving mean over W samples,
   then square-root. The window straddles each sample (half before, half
   after) and clamps at the edges, so the envelope sits right on the signal. */
void centered_rms(const double *x, double *env, int n, int W) {
    if (W < 1) W = 1;
    int half = W / 2;
    for (int i = 0; i < n; i++) {
        int lo = i - half;       if (lo < 0) lo = 0;
        int hi = i + half + 1;   if (hi > n) hi = n;
        double sum = 0.0;
        for (int j = lo; j < hi; j++) sum += x[j] * x[j];
        env[i] = sqrt(sum / (hi - lo));
    }
}