How a Synthetic Control Manufactured Shared Error
Summary. A synthetic control for triple collocation on structural rain-field coordinates simulated coarse observers by widening Gaussian rain cells while holding their peaks fixed. That operation does not conserve mass, and the mass gain depends on a property of the truth (cell width) that every observer shares. Two observers with independent planted errors therefore acquired correlated coordinate errors (about 0.16 on centroid y in the original 15 × 15 windows), and the collocation estimator mis-ranked observers on dispersion. A finding built on this baseline correlation was later withdrawn. A mass-conserving Gaussian convolution removes the spurious centroid correlation on the full canvas and restores the correct rankings; a small dispersion correlation remains, of unresolved origin. The note gives the mechanism, the invariant checks that would have caught it, a minimal reproduction, and a short checklist.
1. The setup
Triple collocation estimates each observer's noise fraction from the covariances of three observers of the same quantity, under the assumption that their errors are mutually independent. In the project the quantities are structural coordinates of a rain field: the intensity-weighted centroid (y, x) and the intensity-weighted dispersion about it. The synthetic control (T1) existed to check that the estimator recovers planted noise when every assumption holds.
Each truth field is a sum of 1 + Poisson(1.5) Gaussian cells, with centres uniform in ±5 cells, widths w ~ U(0.8, 2.5) and peaks lognormal(1.5, 0.8). Three observers re-render the same cells with independent per-cell position and intensity errors. The radar-like observer R is sharp; the microwave-like S1 and infrared-like S2 are coarser, blurred by b = 1 and b = 2 cells. No shared random perturbation was planted between observers.
2. The symptom
With nothing shared planted, the residuals of S1 and S2 on truth were correlated: 0.16 on centroid y and x, 0.34 on dispersion. The collocation estimate for dispersion ranked the sharp radar-like observer as noisier than S1 (estimate 0.121 vs 0.058; truth 0.046 vs 0.137). The baseline correlation was read at the time as a finding: smoothing itself creates shared structural error between coarse observers (F6). It had a plausible physical reading, and no invariant check on the renderer was in place to contradict it.
3. The mechanism
The coarse observers were produced by re-rendering each cell with width w + b and the same peak I. A two-dimensional Gaussian cell has mass
M = ∫ I exp(−r² / 2w²) dA = 2π I w²,
so widening multiplies each cell's mass by
M′ / M = ((w + b) / w)².
For b = 2 this factor is 12.3 for the narrowest cell (w = 0.8) and 3.2 for the widest (w = 2.5). A field-level centroid is the mass-weighted mean of cell centres, Σ Mk ck / Σ Mk. Widening reweights it toward narrow cells. Because cell width belongs to the truth, both coarse observers are pulled toward the same cells in the same window, by amounts that depend on the configuration of cells rather than linearly on the true centroid. The pull survives regression on truth and appears as correlated residuals. It needs at least two cells: a lone symmetric cell keeps its centre when widened. In minimal.py, single-cell fields give a centroid-y correlation of −0.015 under widening and multi-cell fields +0.099. Dispersion is affected twice: through the same reweighting, and because widths add linearly (w + b) where a convolution adds them in quadrature (√(w² + b²)).
4. The invariant checks
A blur that models a coarser sensor should satisfy three properties that can be computed on the truth field alone, before any observer error is added. For a normalised Gaussian kernel of standard deviation b on a canvas large enough to hold the field:
- mass is conserved (∫ f∗g = ∫ f · ∫ g = ∫ f);
- the centroid is unchanged (first moments add, and the kernel's is zero);
- squared dispersion grows by exactly 2b² (second central moments add, b² per axis).
On 1,000 truth fields from minimal.py:
| blur | b | median mass ratio | median centroid shift (cells) | median |Δd² − 2b²| / 2b² | verdict |
|---|---|---|---|---|---|
| widen (T1) | 1 | 2.52 | 0.15 | 350% | fail |
| widen (T1) | 2 | 4.75 | 0.22 | 171% | fail |
| convolve (T1-bis) | 1 | 1.000 | 5 × 10⁻¹⁶ | 0.01% | pass |
| convolve (T1-bis) | 2 | 1.000 | 5 × 10⁻¹⁶ | 0.03% | pass |
These checks are the stronger reference. They do not depend on any statistical estimator, and a failure localises the problem to the renderer. In the project, T1-bis made them a pass/fail gate before any collocation was computed (centroid shift 5 × 10⁻¹⁶, squared-dispersion growth within 0.04%). The original flaw was identified by an external review of the project and confirmed against the simulation code.
5. The corrected result
With the same random cells and the mass-conserving blur, the S1–S2 centroid error correlation on the full canvas falls to the sampling-noise level (|r| ≤ 0.014, 95% field-bootstrap intervals including zero), and the collocation estimates for centroid y and dispersion lie close to the truth with the correct ranking (T1-bis showed the same for all four structural variables). A small dispersion correlation remains (sections 6 and 7).
| full canvas, dispersion | R est. / true | S1 est. / true | S2 est. / true | ranking |
|---|---|---|---|---|
| widen | 0.110 / 0.045 | 0.071 / 0.138 | 0.250 / 0.304 | S1 < R < S2 (wrong) |
| convolve | 0.051 / 0.045 | 0.102 / 0.109 | 0.280 / 0.284 | R < S1 < S2 (correct) |
The corrected control still does its job as a positive control: in T1-bis, a shared displacement planted in S1 and S2 (σ = 1.0 cell) inverts the centroid ranking as expected, and a five-observer tetrad audit identifies the planted pair in 10 of 10 blocks with no false alarms when nothing is planted.
6. The residual window effect
Real data are read in finite windows. A plausible reason windows add shared error is that they clip the tails of smoother fields more than sharp ones (not tested separately here). This is a genuine, smaller source of shared error that remains under a correct blur. In T1-bis, 15 × 15 windows gave S1–S2 error correlations up to 0.02 on centroids and up to 0.14 on dispersion, growing as the window was shifted off the storm (central window 0.06; shifted by (−3, +4) cells 0.14). minimal.py reads only the central window and shows the same pattern (centroids |r| ≤ 0.01, dispersion 0.06). Widening and windowing also interact: under widening the centroid correlation is 0.07 on the full canvas and 0.15 in the window, close to the original 0.16, which was measured in windows.
7. Differences between the minimal example and the project runs
minimal.pyuses 10,000 fields (T1, T1-bis: 20,000), a 64 × 64 canvas throughout, no intensity threshold (T1 zeroed values below 0.1 mm/h), and no planted shared error or fifth observer.- Widening on the full canvas gives a centroid correlation of 0.07 rather than T1's 0.16; the window brings it to 0.13–0.15. Dispersion (0.29 full, 0.33 window) and the dispersion mis-ranking (R 0.110 vs S1 0.071) are close to T1 (0.34; 0.121 vs 0.058).
- Under convolution the full-canvas correlations are −0.001 and −0.014 on centroids and 0.031 on dispersion (T1-bis: −0.001, 0.009, 0.021). The centroid intervals include zero (95% field-bootstrap, 1,000 resamples: −0.001 [−0.021, +0.017], −0.014 [−0.033, +0.006]). The dispersion interval does not: +0.031 [+0.005, +0.056]; T1-bis gave +0.021 (no interval computed there). It is not a renderer artefact (the analytic checks pass), it does not disappear with squared dispersion (+0.036), and it remains in multi-cell fields alone (+0.022). A plausible source is that each observer's dispersion error depends on the truth configuration (number of cells, mass shares) in a way a linear regression on the true dispersion does not absorb; this was not investigated further. Single-cell fields are a degenerate case for dispersion: their dispersion is a fixed function of the true width, so their residuals are shared almost exactly.
8. A checklist for synthetic benchmarks
Two validations are separate tasks: that the rendering operation does what it claims (invariant checks), and that the extracted measurements meet the statistical assumptions of the estimator (independence and linearity of their errors). This note fails the first and, after the correction, shows a small residual in the second.
- Write down the invariants of each simulated operation (what each should preserve, and what it should change by a known amount: for a blur, mass and first moment preserved, second moment increased by 2b²) and test them on the truth alone, as a gate, before any downstream statistic is computed.
- Implement degradations as operators on the rendered field (convolution, resampling), not as edits to the generating parameters, unless the parameter edit is shown to equal the operator.
- Check that independence holds where it is assumed. Compute the true pairwise error correlations among simulated observers with nothing shared planted; they should be near zero. A non-zero value is a property of the simulator until shown otherwise.
- Look for common directional bias, not just common sensitivity. Two observers can both become noisier on small cells without their signed errors correlating. Shared error arises when both shift the estimate in the same direction as a function of the truth, as here, where both reweight the scene toward narrow cells.
- Separate the canvas from the read region. Simulate on a canvas large enough to contain the field, then apply windows, thresholds and clipping as separate, measured steps.
- Keep a planted positive control alongside the null, so a corrected simulator is shown to still detect what it should.
- Treat a surprising baseline result as a test of the simulator first. A physically plausible explanation is not evidence that the simulation produced it for that reason.
Reproduce
cd precip-disagreement/notes/synthetic-shared-error ../../.venv/bin/python minimal.py # numbers, about 30 s ../../.venv/bin/python minimal.py --figures # also writes fig1-3 (matplotlib)
Sources: T1_PLAN.md, T1_RESULTS.md, T1BIS_PLAN.md, T1BIS_RESULTS.md, scripts/t1_synthetic.py, scripts/t1bis.py, LABBOOK.html §7 and §12.