Tidal harmonic analysis · reference & data registry Data access Sign in Contact
tidalcore water-level time-series analysis - documentation & datasets release 0.9.3 · MIT

Home › tutorial › residual

Reading the residual

The residual is observed minus fitted, and it is where everything the tide does not explain has to live. Four different causes leave four different shapes in it, and telling them apart is most of what the series is good for.

Four shapes

A residual root-mean-square of 0.186 m, as on station-7, is a summary and nothing more. Two records can share that number and mean completely different things, so the first move is always to plot the residual against time and read its shape before its magnitude.

What the common causes look like in the residual, and the time scale that separates them.
CauseShape in the residualTime scale
Storm surgesmooth positive humphours to a few days
Datum shiftflat step, holds afterwardsinstant, then permanent
Gauge faultspikes or a flat lineseconds to hours
Seasonal set-upslow sinusoid under everythingmonths

Surge

A meteorological surge is the signal most people are after, and it is the easy one: a rounded elevation of a few tens of centimetres that builds over a day and relaxes over the next. On station-7 the largest residual excursion, 0.53 m on 11 March 2026, is exactly this, and because the harmonic fit has already removed the tide underneath it the surge can be read off directly instead of being eyeballed out of the raw curve.

Datum shift

A level shift shows as a step that starts at one instant and never returns to zero afterwards, and it almost always means the gauge was serviced, re-levelled or renumbered rather than that the sea changed. The library will not correct it, because it cannot know which side of the step is right; what it gives you is a residual in which the step is unmistakable and dated, so the metadata can be checked against that date.

rest = tc.residual(rec, sol)
before = tc.rms(rest[:k]); after = tc.rms(rest[k:])
# a clean step moves the mean, not the rms, on each side

Gauge fault

Instrument trouble is the noisy one and comes in two flavours: bursts of isolated spikes, which the spike flagger should already have caught, and a dead flat stretch where a stuck sensor reports one value while the real level keeps moving. The flat case is worth a direct test, because a frozen reading can sit perfectly inside the plausible range and pass every threshold aimed at outliers.

rec = tc.qc.flag_flat(rec, window="2h")
# a value unchanged for two hours in a six-minute record is not tide

Next: fitting a short record when a year of data is not on offer.