Artificial Wasteland · an instrument made of your own room
The Hum Is a Clock
Somewhere in your room something is humming at twice the frequency of your electricity grid. That frequency is never exactly 50, or exactly 60. It moves, by tens of millihertz, all day, and every generator on your synchronous grid moves with it. Not your continent: the European regulation this page checks against names four separate synchronous areas, which is why it has to quote two different legal bands below.
A microphone can read it. Not the wall socket, not a meter: the sound a transformer makes. This page opens your microphone, listens for twenty seconds, and reports your grid's frequency with an interval. Before it will do that, the identical estimator has to recover four answers that are already known, in front of you, including one it must get wrong on purpose.
And then there is the catch, which is the better half of the page. What comes out is not the grid. It is the grid divided by the crystal inside your own sound hardware. This page measures that too.
First: four answers it already knows
A page that measures your room has a problem no arithmetic page has. You have no second instrument. You cannot check it. So this one is not allowed to report your number until the same code has recovered four numbers that were fixed in advance and frozen before any of them ran. Two of the four are traps: a hard-coded estimator sails through the first and dies on the rest.
The slate
| role | specimen | known | measured | off by | tol | |
|---|---|---|---|---|---|---|
| running… | ||||||
running the slate…
The control on the control
This is not an argument that a constant would fail. It is the same slate, run again through an estimator that has been deliberately hard-coded to return the first anchor's published value with a small error bar, so you can watch it fail.
…
Your room
Twenty seconds, somewhere with mains power and preferably a light or a charger on. Nothing leaves your browser; the check panel at the bottom lists every network request this page has made, and there is a content security policy in the head that forbids any other origin.
Your grid, right now
not measured yet
The instrument has to arm first. That is happening above.
what this page measured a published log one standard deviation
The shipped anchor, drawn against the published log it was made from.
| candidate line | grid this implies | best in-band SNR | windows above the floor |
|---|
Nothing arrived? That is a result, and it has its own section below. A battery-powered device in a room with no wiring nearby genuinely has no mains hum in it, and a page that always produces a number is a page that is not measuring.
You did not measure the grid
Here is the objection, and it is correct. Your sound hardware counts samples with a quartz crystal, and that crystal is not exactly right. It says 48000 samples per second and delivers 47997, or 48004. Every frequency this page reports is scaled by that error, because the only ruler it has is the sample count.
An ordinary consumer crystal is specified to about 100 parts per million. On a 50 Hz grid that is 5.0 mHz of error, a tenth of the 50 mHz that Continental Europe's standard frequency range allows either side of nominal, and larger than this estimator's own noise floor. A page reporting millihertz from a laptop microphone without saying so is lying.
This is not a new worry. It is a clause in a forensic guideline that is older than most phones:
Calibration/measurement should be routinely carried out on the database clock source used in the digitisation process of the ENF. A correction factor to the database ENF estimates would need to be applied for data that had been collated using a soundcard that had a bias in its sampling frequency. ENFSI Forensic Speech and Audio Analysis Working Group, Best Practice Guidelines for ENF Analysis in Forensic Authentication of Digital Evidence, ref. FSAAWG-BPM-ENF-001, Issue No. 001, 2 June 2009, clause 3.6.2
Read whose clock that is, though, because it is not yours. The guideline is telling a laboratory to calibrate the soundcard that digitised its own reference database, which is the far end of the comparison from you. Your microphone is the questioned recording's end, and no clause in that document asks anyone to calibrate it. The worry carries over exactly; the instruction does not, and this page will not borrow authority it was not given. It measures the crystal anyway, because the arithmetic does not care which end of a comparison the wrong clock is on.
The answer is not a caveat. It is three more results, and you can operate all three.
One. Your crystal, measured, right here
A browser hands you both clocks in one object. AudioContext.getOutputTimestamp() returns contextTime, which advances with the audio device's own sample counter, and performanceTime, which advances with the system clock. Regress one on the other and the slope is the ratio between two crystals. This needs no microphone and no permission at all.
Your audio clock against your system clock
not measured yet
Press the button. It listens to nothing; it just watches two clocks disagree.
This is a ratio of two crystals, not a calibration. Neither one is a standard. If your system clock is being steered by NTP while this runs, that steering lands in this number, which is why the fit residual is printed with it. And this is the one panel on the page that the browser gate cannot check. The gate feeds Chromium a file through a fake audio device, and that device is not a crystal: asked this same question it answers, but it answers with the pacing of Chromium's own sample generator, which came out near −1300 ppm here and moved by hundreds of ppm between runs. That is an order of magnitude outside what a real crystal is specified to, so there is nothing there to check the arithmetic against. The verifier measures it in that browser rather than assuming it. What is checked instead is offline: the regression, against slopes planted at known parts per million and including the sign, and the estimator's ratio behaviour, against the specimen deliberately mis-clocked below.
Two. Break the clock on purpose and watch what survives
The shipped anchor is a recording whose true answer is known exactly. Below, the page resamples that same file by a clock error you choose and runs the same estimator over the result. Watch the absolute reading move by exactly the amount the arithmetic predicts, and watch the shape of the trace not move at all.
Mis-clock the anchor
…
Three. The shape is the whole of forensic ENF
The forensic use of mains hum is not the absolute value. It is matching the wander of a questioned recording against an archived log, which is what ENFSI clause 5.1.4(c) describes: overlay two vectors and compute a correlation. A constant clock error moves a whole trace up or down together, and a correlation with the mean removed cannot see that. So the objection kills one claim and leaves the other standing, and this page can say which is which because it measured both.
Below, the recovered trace is matched against a shipped day of the Nordic grid log at every second of it the trace can be laid against: a three minute trace has to fit inside the day, so the count printed under the graph is a little short of its 86,400. The negative control is a real recording of a real grid on the other side of the world, which has no correct answer in this day at all.
Find this recording in the day
Correlation of the recovered trace against the shipped day, at every second. The dashed line is the 99.9th percentile of the scores at every candidate second, the true one included, so the winning peak always stands above it and standing above it settles nothing. What decides a match here is the gap between the peak and the best answer somewhere else in the same day.
…
When there is nothing to find
Every room does not hum. Off-grid, battery-powered, DC-lit and aggressively filtered captures have no mains component in them at all, and the dataset used here ships a set of recordings made for exactly that test: same rooms, same devices, no mains hum. A refusal on one of those is the correct answer, and it is the single hardest thing to get right, because a spectrum always has a maximum.
A real recording with no mains in it
The spectrum of the shipped null recording across all four candidate bands, so you can see the absence rather than take it on trust.
…
And when there are two sources
Two harmonics of one grid must give the same number. A second source (an uninterruptible power supply, an inverter, an unrelated tone) does not, and that is the case ENFSI clause 2.2(c) separates out. Press this to add a second source to the shipped anchor and watch the same estimator stop answering.
…
A regulation, checked
European law names the number this page measures. Commission Regulation (EU) 2017/1485 (the system operation guideline) sets, in Annex III Table 1, a standard frequency range of ±100 mHz for the Nordic synchronous area and ±50 mHz for Continental Europe, and in Table 2 a target of at most 15 000 minutes per year outside that range, the same 15 000 for all four synchronous areas. Here is that count, summed in your browser from the deposited log. Then the same log counted three other ways, because the regulation names a number of minutes and the log is one sample per second, and nothing anywhere says which operation turns one into the other. One of the four reverses the verdict.
Nordic grid, 2023, against Annex III
…
Article 127(6) lets the transmission system operators of a synchronous area agree different values from Table 2 in their synchronous area operational agreement, so the 15 000 above is the regulation's default and not necessarily what applies. And the deposit does not cover the whole year, which is why the comparison below it is pro rata and says so.
What this is not
- It is not a way to date your own recording. Dating needs a reference log for the right grid covering the right period. This page ships one day of one grid and dates one shipped specimen against it. Your live capture is never matched against anything, and could not be.
- It is not a grid fault detector. If your reading sits outside the normal band, the overwhelmingly more likely explanation is your microphone or your sample clock, not your grid. A crystal 1000 ppm out moves a 50 Hz reading by 50 mHz, which is the whole of what Continental Europe allows on one side of nominal, and crystals that bad exist.
- It goes blind exactly when the grid gets interesting. The search band is the ENFSI one, ±1 Hz around each line, which referred back to the grid is ±0.5 Hz at 2f but only ±0.25 Hz at 4f. So a grid more than about a quarter of a hertz off nominal carries its 4f line out of the window this page looks in, and the page stops answering: near that edge it reports that the two harmonics disagree, and further out that there is no mains line at all. Both refusals are true statements about what the instrument saw and neither is what happened, which was that the grid moved further than the instrument looks. This is not hypothetical. The Nordic year counted below reaches 49.6064 and 50.4916 Hz, and at those seconds this page would have refused and left you thinking it was your room.
- It can be confidently wrong about which grid you are on. Swept over the whole ENF-WHU dataset, this estimator produced 289 answers on real room recordings, and three of them said 60 Hz in a country whose grid is 50 Hz, with a normal-looking interval of about 3 mHz around them. In each case the loudest pair of lines in the room was at 120 and 240 Hz. That is what a second source looks like when it supplies both harmonics, and no rule on this page can tell it from a grid. The rate is in the check panel because it is one in a hundred answers, not zero.
- Off nominal is not the same as off target. Continental Europe runs its grid as a clock deliberately. Synchronous Time, the time you get by counting mains cycles and calling every 50 of them a second, is compared against UTC by a transmission system operator called the Time Monitor at 10 a.m. every day. A discrepancy is tolerated within ±20 s with no action taken; outside that, the Time Monitor sets a time correction frequency offset of ±10 mHz which every operator in the synchronous area applies for the whole of the next day. So on a correction day the target is 49.990 or 50.010 Hz, and a reading 10 mHz off nominal can be a grid sitting exactly on its published set-point. That deliberate offset is twice the 5 mHz your own crystal is allowed to be wrong by, it is scheduled and knowable, and this page does not know which kind of day you are on. ENTSO-E, Synchronous Area Framework Agreement for Regional Group Continental Europe, Policy 1 (Load-Frequency Control and Reserves), B-7-1-3-1, B-7-1-4 and B-7-1-5.
- 50 and 60 are not the only answers. This page tests two nominals and says so. Japan runs both, on grids that are not synchronised with each other; an aircraft runs 400 Hz; plenty of places have no AC grid. The nominal is chosen from the evidence in the signal and never from your locale, your timezone or your address.
- It does not authenticate anything. ENFSI clause 6.3 prescribes a comparison of two competing hypotheses, not a verdict, and ENF evidence has been contested in court. Nothing here proves, authenticates or identifies.
- The wander is not this page's discovery. The shipped anchor wanders because it was built from a published log that wanders. Recovering that wander tests the estimator and is not evidence about grids. The evidence about grids is the log.
Show the check
What the instrument attested, verbatim
…
Does the reading actually move, or is that just noise?
A drift figure on its own has no content: a handful of noisy estimates of a perfectly constant frequency also has a non-zero range. So every trace on this page is tested against its own per-window intervals, and one of the shipped specimens is constant by construction, which is what makes the test capable of saying no.
…
Every free choice in the estimator
…
Measured offline, over 1.4 gigabytes of the ENF-WHU dataset
These cannot run in a browser: they are a sweep over every H1 recording in that dataset against its own simultaneously recorded mains reference, plus the whole H0 null set. They were measured by research/enf-mains-hum/calibrate.mjs, recorded in research/enf-mains-hum/calibration.json together with the list of files it read, and the verifier asserts that what this page says matches that file. This is the one block on this page you cannot re-run yourself without downloading the dataset, which is why it says exactly what was swept, and why the failure it turned up is printed here rather than summarised.
…
Breaking it on purpose
Everything above this line is green, which is also exactly what a verifier looks like when it is testing nothing. So the verifier takes the same engine.js this page just ran, injects one defect at a time, and requires a named check to go red for each one. The defects this slate provably cannot see are listed too, because saying which of them survive is part of saying what the slate is worth.
EACH DEFECT IS ONE SUBSTITUTION INTO engine.js, AND THE CHECK THAT CATCHES IT
▸ the estimator returns a constant 50.000 Hz
Every specimen except the one whose value was hard-coded, and the null recording
emits a number where silence was the correct answer.
▸ the estimator returns the nominal it chose
synth-60, which sits 12.9 mHz off nominal against a 12 mHz tolerance. That gap is
the entire reason the 60 Hz control was built off nominal rather than at 60.000.
▸ the sub-bin refinement is skipped and the raw peak bin is returned
The anchor, the 60 Hz control and the mis-clocked control all fall outside tolerance.
▸ the in-band SNR floor is removed, so nothing is ever refused for weakness
The nominal can no longer be chosen at all: with no floor, noise ties 50 against 60.
▸ the harmonic agreement check is disabled
Two sources at odds are averaged into 49.98511 Hz, which is neither of them: 42 mHz
above the anchor's own answer and 8 mHz below the interferer's grid.
▸ the both-harmonics rule is dropped, so one line is enough
A single isolated tone, which is not what a grid looks like, is reported as a grid.
▸ the sample clock ratio is inverted, so a fast clock is reported as a slow one
A clock planted 500 ppm fast comes back as -499.750 ppm. The browser gate could
not catch this: it never reads the ratio, and the fake audio device it drives has
no true ratio to be read, as the panel above says and the verifier measures.
This one is caught offline or not at all.
▸ the demonstrated accuracy floor is removed from the interval
The interval falls to 0.29 mHz on real room audio, where 3.0 mHz is all this
estimator has ever demonstrated against an independently recorded reference.
SURVIVES, AND IS RECORDED AS SURVIVING
▸ forcing the log-parabolic interpolation to zero
Nothing catches it, and nothing should. The parabola is only a starting point for
the Goertzel search, which has no bin grid at all, so removing it moves every
specimen by under 20 nanohertz. If this one ever starts going red, the method
described above is the thing that has gone wrong.
Sources, and what each one licenses
GRID FREQUENCY LOG
Pre-Processed Power Grid Frequency Time Series (2020-2023), doi:10.5281/zenodo.15784548.
Only the Fingrid (Nordic) series is used or shipped. The deposit's Zenodo licence field
says cc-by-4.0 for the record, and the deposit's own LICENSE.md does not agree with it:
"The pre-processed data in the subfolders `**/Fingrid` are licensed under the CC-BY 4.0."
"TransnetBW/ Netztransparenz originally did not publish their data under an open
license ... we cannot publish our pre-processed version under an open license due to
the missing license of the original data."
So the Continental Europe series is NOT redistributable and is not here in any form. This
page is about the Nordic grid because that is the one whose licence permits it. Attribution
as CC BY 4.0 requires: A. Nikoltchovska, S. Puetz, X. Li, V. Hagenmeyer and B. Schaefer,
Zenodo, doi:10.5281/zenodo.15784548; original measurements Fingrid Oyj, "Frequency,
historical data", published by Fingrid under CC BY 4.0. The full text of both licence
findings is in this page's specimens/LICENCE.
REAL ROOM AUDIO
ENF-WHU-Dataset, github.com/ghua-ac/ENF-WHU-Dataset. MIT License, Copyright (c) 2023
HUA GUANG, fetched verbatim from the repository root on 2026-08-17: permission to "use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies", conditioned only
on the copyright and permission notice travelling with it, which it does, in
specimens/LICENCE. The excerpts here are low-passed at 300 Hz and decimated to 1 kHz, which
is an anti-alias band limit and is also the privacy measure: these are recordings of real
rooms with real people in them, and a 300 Hz ceiling removes the consonant energy that
carries word intelligibility, though it leaves pitch and rhythm. No listening panel was run
to confirm that, and specimens/LICENCE says so. The band limiting is applied by the build
script, not by hand.
STANDARDS AND GUIDELINES
Commission Regulation (EU) 2017/1485 (system operation guideline), Article 127 and
Annex III Tables 1 and 2. Read from EUR-Lex, CELEX 32017R1485, on 2026-08-17.
ENFSI Forensic Speech and Audio Analysis Working Group, Best Practice Guidelines for ENF
Analysis in Forensic Authentication of Digital Evidence, ref. FSAAWG-BPM-ENF-001,
Issue No. 001, 2 June 2009, ed. C. Grigoras, A. Cooper and M. Michalek. Clauses this page
relies on, and what each is used for:
2.2(c) detect the TYPE of ENF component (mains, uninterruptible power supplies, etc.),
which is the two-source refusal above.
3.6.2 the soundcard clock bias, quoted verbatim in the second layer.
5.1.1(a) remove the DC component. Done once, before anything spectral.
5.1.1(b) a band pass of +/- 0.5 to +/- 1 Hz either side of the line. That is this page's
search band, applied at the harmonic it reads rather than at the fundamental.
It is NOT the 300 Hz low-pass above, which is an anti-alias band limit, and
5.1.1(c) recommends decimating to ENF x 2.4, which this page does not do because
it has to keep 240 Hz for a 60 Hz nominal at h = 4.
5.1.2(b) an FFT with an interpolation scheme, which is the locate-then-refine step.
5.1.4(c) overlay two length N vectors and compute a match metric: the dating panel.
6.3 two competing hypotheses rather than a verdict, which is why this page reports a
comparison and stops there.
D. C. Rife and R. R. Boorstyn, "Single-tone parameter estimation from discrete-time
observations", IEEE Trans. Inf. Theory 20(5):591-598, 1974.
G. Hua and H. Zhang, "ENF Signal Enhancement in Audio Recordings", IEEE Trans. Inf.
Forensics and Security 15:1868-1878, 2020, which the ENF-WHU README asks to be cited.
Every network request this page made
…
Reproduce it
Run node research/enf-mains-hum/verify-enf-mains-hum.mjs. It regenerates the synthetic specimens and compares their hashes, recomputes every number above from the same engine this page runs, and checks each of them against the text you are reading. Run node scripts/check-live-sensor.mjs --only=enf-mains-hum to drive this page's own microphone path in a real browser with a signal whose answer is already known.
Built 17 August 2026. The estimator, the specimens, the offline mirror and the verifier are one implementation: public/strata/enf-mains-hum/engine.js, loaded unchanged by all four.