Elba: an audit of the pole detection and the cable mapping

Two questions. Is the pole-detection method sound, and were the circuits traced from the utility sheet put in the right place on the map? Both were re-derived from the raw data rather than taken from the handoff note.

Independent re-run · 17.6 M LiDAR returns, 37 road segments, 284 candidates, 1,981 circuit vertices
Pole detection

Method sound, confidence overstated

The idea and the implementation are right, and I reproduced every published number. The significance test leans on an idealised null; replacing it with the observed one drops the headline from 31 poles on 5 lines to 25 on 4.

Cable mapping

Not validated, and the map flatters it

The quoted 10 m accuracy is the training residual of the fit that produced it. Held out, the same procedure is about twice as bad. 74% of the delivered circuit vertices lie under 1 m from a road because they were snapped there.

1 · Pole detection

What the method does, and why the core of it is right

A pole is a poor LiDAR target: it is vertical, the scanner looks down, and at 7.8 pts/m² one pole returns roughly 3 to 25 points. Detecting poles as objects fails, because "tall, dense, connected" describes a tree. The method instead detects the line: poles hold a near-constant setback from the road over hundreds of metres and trees do not. Candidates are found per road, runs sharing a common perpendicular offset are extracted, and each run is tested against a null built from that road's own candidate count. Surviving roads then go through Benjamini-Hochberg.

That chain is well-posed, and the code does what its docstrings claim. Re-running it from the LAZ reproduced all 16 candidate lines and their p-values to Monte Carlo noise (Adkinson Street 8 of 11; Factory Street 3 of 11 at p ≈ 0.61, both as documented). The criticisms below are about the null, not the idea.

The null the p-values come from

Each test asks: scatter this road's candidates at random, how often does a run this big appear? "At random" is implemented as offsets drawn from Uniform(−20 m, +20 m). That is an assumption about where non-pole clutter sits, and everything downstream — including the FDR correction — inherits it.

Where candidate offsets actually fall
284 candidates, all 37 road segments pooled, against the flat distribution the null assumes
The pooled distribution is only mildly uneven — a Kolmogorov–Smirnov test against uniform gives D = , p = , which is not significant. There is a dip either side of the centreline, where the road surface itself returns nothing, and a rise around 5–10 m. Median |offset| is m.

So the marginal is not grossly wrong. The problem is that the statistic is extremely sensitive to mild concentration: the run test counts candidates falling within a 3 m window, and modest crowding raises the chance of that a great deal. Substituting the observed offsets for the idealised ones is therefore worth doing, and it changes the answer.

Every candidate line, under the shipped null and the observed one
p-value, log scale. Lower is stronger evidence. Dashed lines are the Benjamini-Hochberg cutoffs each null produces at FDR 10%
Uniform null (shipped) Empirical null (observed offsets)
Every line moves right — weaker — but only two cross a cutoff. Claxton Avenue goes from p = 0.031 to 0.095 and Simmons Street from 0.031 to 0.083, and neither survives. The empirical null draws offsets from the pooled observed set without replacement, so it cannot manufacture ties; a jittered variant gives the same four survivors.

What survives

Pole linepoles / candsp uniform p empiricalAt FDR 10%

31 poles on 5 lines becomes 25 poles on 4. Claxton Avenue's 7 poles — 23% of the published count — rest on the uniform assumption. The four survivors are well clear of the cutoff and are not in doubt.

One bookkeeping note on the table above: its "p uniform" column is this audit's own re-run at 8,000 trials, which accepts six lines, not the five the shipped run accepted at 4,000. Simmons Street sits on the boundary and flips between the two. That instability is itself a finding, and it is the subject of the next section; the empirical column is stable across every variant tried.

Two things corroborate this. A null built only from roads that produced no run at all — so it cannot contain the signal — gives the identical four. And the handoff note itself records that "all lines confirmed on geometry alone" numbered four; Claxton entered only when the map prior was used to relax the threshold.

The accepted set is unstable to the random seed

The BH boundary sits at p ≈ 0.03, and with a few thousand permutation trials a p-value there carries a standard error near 0.003. Re-running the same code with a different draw changes the published count:

trialslinespolesrun

Anything with p between 0.02 and 0.05 is a coin flip. Raising the trial count and reporting a confidence interval on each p-value would fix this.

2 · Cable mapping

How the sheet is put on the world

The colour sheet is separated in HSV: blue is the primary circuits, pink is the road right-of-way. The fit is anchored on pink, not blue, and that is the right call — circuits sit about 9 m off the centreline by construction, so fitting circuits to roads would bake that error in. A coarse scale/rotation search is followed by a local refinement: the sheet is hand-held paper, so block-wise cross-correlation of road ink against the OSM raster gives a shift per block and a thin-plate spline smooths them into a displacement field.

The reasoning is sound and the engineering is careful. The problem is the number attached to it.

The 10 m is a training residual, not an accuracy. The warp is fitted by maximising alignment of the sheet's road ink to the OSM roads. The reported figure — "road ink lands 10 m from an OSM road" — is the median of exactly the quantity that fit minimised, measured on exactly the data it consumed. With confident blocks feeding a spline, that is on the order of 470 free parameters, and a residual can always be driven down by adding flexibility.

Holding roads out

The test the pipeline does not do: fit on half the road network and score on the half it never saw. Both fits below are scored against the same held-out raster, so the sparser-target effect is held constant and only generalisation differs.

Registration error, in sample and out
Median distance from the sheet's warped road ink to OSM road centrelines
My harness reproduces the pipeline exactly — same 236 of 315 confident blocks, same 140 m median block shift, same 10.0 m residual — so this is like-for-like. Scored against roads the warp never saw, the same procedure lands 85.4 m out, against 41.2 m for a warp that did see them. Roughly a twofold penalty for generalising.

And the 10 m describes the road ink, which is what was fitted. The circuits — the actual deliverable — sit at 41.2 m median from the nearest road under the same fit, with only 38% within 30 m.

What the delivered layer actually looks like

After tracing, route vertices are snapped onto roads within 35 m. Measuring the GeoJSON the viewer draws:

Distance from each delivered circuit vertex to the nearest road
1,981 vertices in circuits.geojson
Strongly bimodal, and that is the tell. of vertices sit under a metre from a road because they were moved there; the median is m. The remaining found no road inside the tolerance and stayed where the registration put them — reaching m at the 90th percentile and m at the 95th.

So the circuits follow the streets on screen because they were snapped to the streets, not because the georeferencing placed them there. The snap tolerance, 35 m, is over three times the claimed registration accuracy — the snapping is doing more work than the registration. The unsnapped quarter is where the true error is visible, and it is large.

Snapping is not itself wrong: distribution circuits really do follow roads, so it is a reasonable prior. But it destroys the ability to judge the registration from the result, and it should be reported as an assumption rather than absorbed silently.

3 · Defects found in the code

WhereWhatEffect
fuse_with_map.py Circuit coverage is stored per road segment ("Claxton Avenue|767") but collapsed to the bare name with max(). Nine unnamed segments spanning coverage 0.08–1.00 collapse to a single 1.00. latent Changes nothing here — 36 of 37 segments are energised anyway and the one that is not produced no run — but it is wrong, and would bite on a larger tile.
requirements.txt No LAZ decompression backend, so laspy.read raises on the only input detect_poles and road_circuits take. blocking Neither module could run as shipped. Fixed by pinning laspy[lazrs].
detect_poles.py offset_runs() takes a line parameter it never uses. cosmetic Harmless; the null passes None.
Stated rationale The map prior is justified as removing the multiple-comparison cost, but the handoff also records that 34 of 37 roads are energised. reasoning The prior barely discriminates, yet it is what licenses relaxing a flat p < 0.01 to BH at 10%, which admits more lines.

4 · What would actually settle it

Nothing in the present data can validate the registration, because every available check reuses the roads the fit consumed. The handoff's own open question 5 — GPS for a sample of poles — is precisely the missing piece. A dozen surveyed positions would give an independent error estimate for the circuits and the LiDAR detections at once.

Three changes to the code follow from this audit:

Reproducibility. Every figure here comes from a re-run against /data/datasets/OD/elba, not from the handoff. The detector was re-executed from tile_2021.laz; the registration harness reproduces the pipeline's own console output exactly before any change is made. Two errors in an earlier pass of this audit were caught and corrected: candidates were first keyed by road name, which collapsed segments sharing a name, and the first empirical null resampled with replacement, which manufactures duplicate offsets and inflates null run sizes. Both are fixed in the numbers above.