Annus Mirabilis · Interactive critical edition in preparation
Measurement bias: localization noise, drift and exposure
See how a camera's errors change what the same motion appears to show.
Observe, then infer
What did the camera change?
Predict before the numbers
Add camera noise. Does the naive diffusion estimate go up, down, or stay the same? Does the correlation between neighboring steps become positive, negative, or zero?
The result appears when you choose, say you have one in mind, or skip.
Comparisons use accepted settings, not unfinished drafts. Reset stage drift with a camera-error comparison; fluid drift remains an explicit physical input.
Four estimates, different assumptions
| Generating value | 0.42944 |
|---|---|
| Ignore camera error and drift | 0.40608 |
| Fit drift, but ignore camera error | 0.4067 |
| Covariance estimate; known synthetic drift removed | 0.51042 |
| Disjoint pairs; noise and exposure corrected | 0.47601 |
Static worked example
Model note
- D, ignoring camera error and drift (
naiveD), D, fitting drift but ignoring camera error (centeredD), D from the covariance, with the known synthetic drift removed (covarianceD), D from disjoint pairs, with noise and exposure corrected (pairD), Covariance-based noise estimate (covarianceNoiseVariance), Stationary-click variance (stationaryNoiseVariance), Increment variance, camera model (expectedVariance), Adjacent-increment covariance, camera model (expectedCovariance), Increment variance, sample (sampleVariance), Adjacent-increment covariance, sample (sampleCovariance), Asymptotic sampling SD of the increment variance (sdVariance), Asymptotic sampling SD of the adjacent-increment covariance (sdCovariance), Expected value of the estimate that ignores the camera (naiveExpectation), Generating value of D (modelDiffusion), Residual degrees of freedom of the disjoint pairs (pairDegrees), Number of disjoint pairs (pairCount), Whether the pair confidence set is empty (emptyPairInterval), Whether the pair set was cut at zero diffusivity (pairLowerClipped), Random draws in the recording (recordingDraws), Random draws executed for this request (requestDraws), Camera and click stream evaluations (measurementDraws), Whether the existing recording was reused (reusedRecording), Whether the existing observation was reused (reusedObservation), Memory held by the kept recording, in bytes (retainedBytes), Fitted drift (driftFit), Bounds on the noise variance (noiseInterval), Interval for D, ignoring the camera and drift (naiveInterval), Interval for D, fitting drift only (centeredInterval), Interval for D from disjoint pairs, with a camera model (pairInterval), Camera positions in each frame (positions), Latent positions at the start of each exposure (idealPositions), Positions averaged over each exposure (blurredPositions), Displacements between camera frames (increments), Exposure start times (times), Independent stationary-feature positions (stationaryClicks), The first kept latent positions, a replay check (latentWitness), Frame spacings in the zero-exposure comparison (speedTimes), Ideal apparent speed at each spacing (idealSpeeds), Apparent speed with noise at each spacing (cameraSpeeds), Ratio of noisy to ideal apparent speed at each spacing (speedRatios), Noise-only crossover interval (speedCrossover), Random draws for the hypothetical experiments (coverageDraws), Intervals from the hypothetical camera experiments, relative to the generating value (coverageIntervals), Hypothetical intervals that ignore the camera and cover the generating value (coverageNaiveCount), Hypothetical noise-aware pair intervals that cover the generating value (coveragePairCount) and Hypothetical experiments with an empty pair set (coverageEmptyCount): Host calculation, by the site's own reference code. Computed ininference.bm08. - Seed 1905: with the same settings, the same seed replays the same trial.
- Computed from the settings last applied (settings revision 1, result 1).
- Not modeled: Higher-order optical aberrations; only uniform exposure blur and Gaussian localization error.
Static worked example. No calculation has started in this browser.
Accepted physical seed 1905; D = 0.42944 μm²/s; 101 frames in 2 coordinates; spacing 1 s; exposure 0.5 s; localization error 0.2 μm. Stage drift 0 μm/s; fluid drift 0 μm/s.
The covariance estimate uses the explicitly known synthetic drift, not a secretly fitted mean. It has no general confidence interval here. The pair procedure fits drift within its disjoint pairs and does not use generating D. Negative unconstrained estimates remain visible as diagnostics.
Which intervals are actually valid?
Ignoring the camera and drift
The zero-drift independent-increment interval does not apply to noisy, exposed, or drifting observations. Its point estimate remains visible as a deliberately naive comparison.
Fitting drift only
Fitting drift does not remove camera noise or the adjacent-increment correlation. The simple centered chi-square interval is not admitted.
Disjoint pairs, with a camera model
0.32569 – 0.69675
95% target coverage; μm²/s. Conservative procedure combining stationary-click noise uncertainty with disjoint-pair variance uncertainty.
50 disjoint pairs; 98 residual degrees of freedom.
A noisy image is not a new physical trajectory. Keep one wandering particle and change how it is observed. Then compare the estimates that ignore camera error with a procedure that accounts for it.
Look for the camera’s fingerprint
Neighboring displacements share a localization error with opposite signs. Exposure averaging creates a different correlation. A variance alone cannot distinguish these effects.
| Moment | Sample | Camera model | Asymptotic sampling SD |
|---|---|---|---|
| Increment variance | 0.81215 | 0.79573 | 0.079699 |
| Adjacent-increment covariance | 0.10434 | 0.031573 | 0.0564 |
The last column is a large-sample MA(1) approximation for the moment estimates, not a confidence interval for D. It is particularly unreliable for very small samples. Expected naive D under this camera: 0.39787 μm²/s.
Inspect stationary clicks and inferred noise
Stationary-click variance: 0.027327 μm². Covariance-based noise estimate: −0.019274 μm². Noise bounds used by the pair procedure: 0.018697 – 0.04333 μm². In exact-noise mode the two bounds are the declared value; otherwise they consume half the allowed error probability.
| Click | x | y |
|---|---|---|
| 1 | 0.11424 | −0.12339 |
| 2 | 0.013049 | 0.14156 |
| 3 | 0.30172 | 0.061022 |
| 4 | −0.22497 | −0.18133 |
| 5 | −0.18734 | 0.17894 |
| 6 | 0.23688 | −0.045071 |
| 7 | −0.035658 | −0.11956 |
| 8 | −0.011732 | 0.010424 |
| 9 | 0.024987 | 0.13217 |
| 10 | −0.12084 | −0.11937 |
| 11 | 0.13412 | 0.16166 |
| 12 | 0.33155 | −0.064944 |
| 13 | −0.23434 | 0.17682 |
| 14 | −0.043285 | −0.14566 |
| 15 | 0.14079 | −0.051643 |
| 16 | −0.044961 | −0.049523 |
| 17 | 0.038157 | −0.042038 |
| 18 | 0.22326 | −0.2329 |
| 19 | 0.2486 | −0.27179 |
| 20 | −0.074478 | −0.41927 |
| 21 | 0.34235 | 0.39974 |
| 22 | −0.13891 | 0.069009 |
| 23 | −0.21279 | −0.089314 |
| 24 | −0.021301 | −0.1282 |
| 25 | 0.011022 | −0.07899 |
| 26 | −0.18005 | −0.23813 |
| 27 | 0.048898 | 0.060165 |
| 28 | 0.12458 | −0.012509 |
| 29 | −0.10319 | −0.052014 |
| 30 | −0.053618 | −0.01365 |
Read all accepted frame positions
| Start | Coordinate | Latent start | Exposure average | Camera position |
|---|---|---|---|---|
| 0 | x | 0 | 0.059593 | 0.40616 |
| 0 | y | 0 | 0.49336 | 0.58492 |
| 1 | x | 0.76755 | 0.48381 | 0.45831 |
| 1 | y | 1.4664 | 1.6531 | 1.7576 |
| 2 | x | 1.3522 | 1.9374 | 1.7977 |
| 2 | y | 1.8208 | 2.3611 | 2.3077 |
| 3 | x | 1.6582 | 1.76 | 1.5403 |
| 3 | y | 4.7649 | 5.3406 | 5.6798 |
| 4 | x | 1.8259 | 2.2254 | 2.4785 |
| 4 | y | 6.106 | 6.4078 | 6.9054 |
| 5 | x | 2.6918 | 2.4524 | 2.6495 |
| 5 | y | 6.6218 | 7.1045 | 7.14 |
| 6 | x | 2.3015 | 2.2869 | 2.2653 |
| 6 | y | 6.8674 | 7.7694 | 7.9798 |
| 7 | x | 2.5376 | 3.3202 | 3.6063 |
| 7 | y | 7.815 | 8.1289 | 8.3653 |
| 8 | x | 3.9219 | 4.0269 | 4.0995 |
| 8 | y | 7.9772 | 8.0356 | 7.8886 |
| 9 | x | 3.662 | 4.0396 | 3.9277 |
| 9 | y | 8.7392 | 8.3412 | 8.4006 |
| 10 | x | 4.8784 | 5.035 | 5.1915 |
| 10 | y | 9.8519 | 9.6081 | 9.6218 |
| 11 | x | 3.2188 | 2.9586 | 3.114 |
| 11 | y | 10.096 | 9.8011 | 9.6936 |
| 12 | x | 1.7113 | 1.6358 | 1.6848 |
| 12 | y | 8.6935 | 8.6515 | 8.8669 |
| 13 | x | 1.5758 | 1.4006 | 1.2002 |
| 13 | y | 9.387 | 9.2404 | 9.443 |
| 14 | x | 2.0985 | 2.2149 | 2.3735 |
| 14 | y | 10.441 | 10.087 | 9.9655 |
| 15 | x | 2.3794 | 2.1728 | 2.162 |
| 15 | y | 9.6801 | 9.6963 | 10.071 |
| 16 | x | 3.0533 | 3.5569 | 3.6126 |
| 16 | y | 10.377 | 10.185 | 10.139 |
| 17 | x | 2.9836 | 3.0305 | 3.2455 |
| 17 | y | 10.019 | 10.529 | 10.491 |
| 18 | x | 3.9592 | 3.8842 | 4.1016 |
| 18 | y | 10.077 | 10.248 | 10.194 |
| 19 | x | 4.6413 | 4.7665 | 4.8111 |
| 19 | y | 10.528 | 10.525 | 10.182 |
| 20 | x | 6.0052 | 5.8067 | 5.9848 |
| 20 | y | 9.6698 | 9.6852 | 10.06 |
| 21 | x | 5.6737 | 4.5876 | 4.7685 |
| 21 | y | 9.5329 | 9.9584 | 9.6914 |
| 22 | x | 3.5548 | 3.4927 | 3.5383 |
| 22 | y | 9.2917 | 9.7142 | 9.7763 |
| 23 | x | 2.6572 | 2.3527 | 2.4738 |
| 23 | y | 9.8606 | 10.169 | 10.253 |
| 24 | x | 2.9066 | 2.6567 | 2.7187 |
| 24 | y | 11.145 | 11.579 | 11.513 |
| 25 | x | 3.0205 | 3.2533 | 3.3214 |
| 25 | y | 10.708 | 11.237 | 11.085 |
| 26 | x | 2.2934 | 2.5247 | 2.6839 |
| 26 | y | 10.448 | 10.97 | 10.838 |
| 27 | x | 1.6884 | 2.0406 | 1.7957 |
| 27 | y | 11.697 | 11.544 | 11.487 |
| 28 | x | 3.3604 | 3.3469 | 3.3858 |
| 28 | y | 10.959 | 10.63 | 10.509 |
| 29 | x | 4.0201 | 4.2709 | 4.3107 |
| 29 | y | 10.21 | 9.4371 | 8.9681 |
| 30 | x | 3.6998 | 3.6706 | 3.7236 |
| 30 | y | 8.8745 | 8.8583 | 9.2388 |
| 31 | x | 4.9056 | 4.5599 | 4.7906 |
| 31 | y | 9.4758 | 9.3429 | 9.443 |
| 32 | x | 5.1382 | 5.2829 | 5.1973 |
| 32 | y | 10.67 | 9.888 | 10.094 |
| 33 | x | 4.9866 | 4.4335 | 4.2462 |
| 33 | y | 7.6947 | 7.0434 | 7.0207 |
| 34 | x | 3.1814 | 2.6488 | 2.6366 |
| 34 | y | 4.9934 | 4.8296 | 4.8252 |
| 35 | x | 2.4513 | 2.1114 | 1.8492 |
| 35 | y | 5.6503 | 5.9031 | 5.8574 |
| 36 | x | 3.583 | 4.1399 | 4.2714 |
| 36 | y | 5.4076 | 6.4722 | 6.5851 |
| 37 | x | 5.0896 | 5.7585 | 5.5093 |
| 37 | y | 7.2942 | 6.9373 | 6.9627 |
| 38 | x | 4.9875 | 4.4822 | 4.757 |
| 38 | y | 7.5374 | 7.5797 | 7.5261 |
| 39 | x | 4.7811 | 4.6871 | 4.5648 |
| 39 | y | 6.8521 | 7.6846 | 7.4462 |
| 40 | x | 4.1958 | 3.7755 | 3.5298 |
| 40 | y | 7.795 | 7.9149 | 7.4695 |
| 41 | x | 4.0765 | 4.2618 | 4.2868 |
| 41 | y | 9.1455 | 8.5925 | 8.4906 |
| 42 | x | 3.0093 | 3.3736 | 3.2438 |
| 42 | y | 7.5917 | 7.8292 | 7.873 |
| 43 | x | 2.8804 | 3.1374 | 3.4481 |
| 43 | y | 7.9771 | 8.5259 | 8.2192 |
| 44 | x | 4.4756 | 4.5238 | 4.6473 |
| 44 | y | 8.3495 | 8.2293 | 8.186 |
| 45 | x | 5.2429 | 5.6274 | 5.5681 |
| 45 | y | 7.9999 | 7.9368 | 8.2303 |
| 46 | x | 5.633 | 5.3647 | 5.3908 |
| 46 | y | 8.5688 | 9.5611 | 9.5009 |
| 47 | x | 5.0369 | 5.0662 | 4.7665 |
| 47 | y | 10.82 | 11.466 | 11.533 |
| 48 | x | 4.0358 | 4.3932 | 4.2725 |
| 48 | y | 11.851 | 11.632 | 11.768 |
| 49 | x | 5.1979 | 5.1233 | 5.4984 |
| 49 | y | 10.331 | 10.257 | 10.197 |
| 50 | x | 4.7259 | 4.7283 | 4.9794 |
| 50 | y | 10.256 | 10.587 | 10.651 |
| 51 | x | 5.0725 | 4.9032 | 4.7221 |
| 51 | y | 9.7771 | 9.1211 | 9.1527 |
| 52 | x | 4.2456 | 4.1778 | 4.245 |
| 52 | y | 9.5051 | 9.5482 | 9.5819 |
| 53 | x | 4.9301 | 4.8117 | 5.0577 |
| 53 | y | 9.4363 | 9.3026 | 9.504 |
| 54 | x | 5.3437 | 5.1771 | 5.2083 |
| 54 | y | 8.8494 | 8.8335 | 8.5755 |
| 55 | x | 5.0866 | 5.346 | 5.7544 |
| 55 | y | 8.644 | 8.0718 | 7.9578 |
| 56 | x | 4.9806 | 4.3519 | 4.1889 |
| 56 | y | 7.6619 | 7.8874 | 7.9279 |
| 57 | x | 4.4448 | 3.9883 | 3.8757 |
| 57 | y | 8.5551 | 8.932 | 9.1778 |
| 58 | x | 2.6513 | 2.7795 | 2.5306 |
| 58 | y | 8.8701 | 9.2868 | 9.0655 |
| 59 | x | 2.5853 | 3.0001 | 3.0493 |
| 59 | y | 10.105 | 10.093 | 9.995 |
| 60 | x | 2.9557 | 3.4865 | 3.4012 |
| 60 | y | 10.321 | 10.228 | 10.189 |
| 61 | x | 3.4051 | 3.6652 | 3.7788 |
| 61 | y | 9.9667 | 10.256 | 10.348 |
| 62 | x | 2.7483 | 2.678 | 2.9185 |
| 62 | y | 10.964 | 11.261 | 11.034 |
| 63 | x | 1.9901 | 1.4699 | 1.5596 |
| 63 | y | 11.815 | 12.085 | 12.099 |
| 64 | x | −0.51039 | −1.0691 | −0.79414 |
| 64 | y | 11.626 | 11.596 | 11.893 |
| 65 | x | −0.55716 | −0.60743 | −0.55769 |
| 65 | y | 11.447 | 10.741 | 10.722 |
| 66 | x | −0.63519 | −0.76667 | −0.67494 |
| 66 | y | 10.003 | 9.6375 | 9.8175 |
| 67 | x | −0.013952 | −0.28854 | −0.098885 |
| 67 | y | 8.6998 | 8.708 | 9.1709 |
| 68 | x | 0.25495 | 0.098652 | −0.1038 |
| 68 | y | 9.4474 | 9.9414 | 10.21 |
| 69 | x | 0.53966 | −0.061082 | 0.10451 |
| 69 | y | 10.556 | 11.385 | 11.368 |
| 70 | x | −0.9578 | −1.1715 | −0.94174 |
| 70 | y | 12.09 | 12.185 | 12.175 |
| 71 | x | −2.5558 | −2.2148 | −1.9856 |
| 71 | y | 12.142 | 11.928 | 11.685 |
| 72 | x | −1.1594 | −1.9262 | −1.9588 |
| 72 | y | 11.927 | 11.455 | 11.781 |
| 73 | x | −2.6058 | −3.5836 | −3.1923 |
| 73 | y | 11.171 | 11.547 | 11.544 |
| 74 | x | −3.8485 | −3.1959 | −3.0037 |
| 74 | y | 12.145 | 11.908 | 12.213 |
| 75 | x | −4.0183 | −4.5268 | −4.7412 |
| 75 | y | 12.123 | 11.801 | 11.56 |
| 76 | x | −4.5134 | −4.4151 | −4.6273 |
| 76 | y | 12.066 | 12.046 | 12.437 |
| 77 | x | −5.3005 | −5.1999 | −5.1619 |
| 77 | y | 12.373 | 12.736 | 12.828 |
| 78 | x | −5.7773 | −6.3041 | −6.1381 |
| 78 | y | 13.831 | 14.253 | 14.282 |
| 79 | x | −6.6899 | −6.6807 | −6.4111 |
| 79 | y | 14 | 14.111 | 13.931 |
| 80 | x | −5.5471 | −5.4157 | −5.5802 |
| 80 | y | 12.993 | 12.575 | 12.341 |
| 81 | x | −4.4161 | −4.292 | −4.4776 |
| 81 | y | 12.939 | 12.538 | 12.542 |
| 82 | x | −4.9302 | −5.5939 | −5.667 |
| 82 | y | 12.687 | 12.308 | 12.375 |
| 83 | x | −5.7146 | −5.5407 | −5.5217 |
| 83 | y | 12.829 | 12.842 | 12.75 |
| 84 | x | −5.8769 | −5.8112 | −5.6515 |
| 84 | y | 13.274 | 13.309 | 13.637 |
| 85 | x | −6.6215 | −7.0299 | −7.1864 |
| 85 | y | 13.582 | 14.123 | 14.411 |
| 86 | x | −7.3474 | −7.5472 | −7.5471 |
| 86 | y | 13.582 | 13.491 | 13.521 |
| 87 | x | −7.1866 | −7.0916 | −7.1148 |
| 87 | y | 12.851 | 12.872 | 12.874 |
| 88 | x | −6.8293 | −6.9662 | −6.9872 |
| 88 | y | 12.387 | 12.676 | 12.725 |
| 89 | x | −7.1942 | −7.1278 | −7.1921 |
| 89 | y | 13.206 | 12.418 | 12.761 |
| 90 | x | −7.4735 | −6.8345 | −7.1217 |
| 90 | y | 12.233 | 12.078 | 12.556 |
| 91 | x | −7.2876 | −7.418 | −7.3593 |
| 91 | y | 12.508 | 12.152 | 11.962 |
| 92 | x | −7.3322 | −7.543 | −7.5144 |
| 92 | y | 11.128 | 11.386 | 11.627 |
| 93 | x | −7.9369 | −7.7487 | −7.9716 |
| 93 | y | 10.542 | 10.073 | 10.16 |
| 94 | x | −7.2622 | −7.0985 | −7.1378 |
| 94 | y | 11.179 | 11.377 | 11.174 |
| 95 | x | −6.4592 | −6.7737 | −6.6992 |
| 95 | y | 10.345 | 10.554 | 10.572 |
| 96 | x | −7.2522 | −7.6636 | −7.6852 |
| 96 | y | 9.8799 | 10.11 | 9.9835 |
| 97 | x | −7.7138 | −7.5058 | −7.5345 |
| 97 | y | 9.532 | 9.5214 | 9.658 |
| 98 | x | −7.2317 | −7.6763 | −7.4877 |
| 98 | y | 8.9311 | 8.9259 | 8.7872 |
| 99 | x | −7.3981 | −7.4369 | −7.5648 |
| 99 | y | 9.4625 | 9.0948 | 9.1115 |
| 100 | x | −8.7425 | −8.5387 | −8.3366 |
| 100 | y | 8.0488 | 8.3731 | 8.4126 |
Faster pictures need not reveal a physical speed
This separate analytical comparison holds the accepted diffusivity and localization error fixed, sets exposure to zero, and varies a hypothetical observation interval. It does not create extra frames on the retained quarter-second grid. Neither curve is an instantaneous velocity.
Noise-only crossover interval: 0.093145 s. At positive exposure, blur also changes the spread; that is not part of this zero-exposure comparison.
| Spacing (s) | Ideal (μm/s) | With noise (μm/s) | Ratio |
|---|---|---|---|
| 4 | 0.46338 | 0.46874 | 1.0116 |
| 1 | 0.92676 | 0.96896 | 1.0455 |
| 0.25 | 1.8535 | 2.1715 | 1.1716 |
| 0.0625 | 3.707 | 5.85 | 1.5781 |
| 0.01 | 9.2676 | 29.764 | 3.2116 |
| 0.0025 | 18.535 | 114.65 | 6.1853 |
Does the interval procedure cover the generating value?
Compare 100 other hypothetical paths under the same physical and camera settings. The dashed comparison deliberately applies the naive formula even where it is invalid; a pleasing interval is not evidence that its assumptions hold.
Run hypothetical experiments explicitly to compare procedures.
Every trial, including misses and empty sets, is retained. Changing the noise procedure reuses the same hypothetical identities. The primary path and camera observations are not replaced. A realized coverage fraction need not equal the target.
Accepted identity, random streams and limits
Computed by the host reference evaluator inference.bm08.
Retained path and bridge draws: 32896. New latent work for this request: 32896. Camera/click stream evaluations: 524. Hypothetical experiment draws: 0. Retained latent bytes: 131600.
Source identity: source:sha256:37d9f7d44016660356c07919cd2309def99b7f3bf545d811a2b28076a63be54b. Two latent coordinates and exact Brownian subinterval averages are retained on 4,112 quarter-second intervals. Frame errors have separate timestamp-indexed streams. Remeasurement may evaluate the same noise draws again; it does not create a new latent trajectory. No irregular timing, overlapping exposure, censoring, empirical import or arbitrary camera likelihood is admitted. This is host arithmetic, not audited WASM or historical evidence.
A camera does not record exactly where a particle is: it smears the motion over each exposure and adds a small error to every position. Both change the spread you measure, although the particle's own path is the same, and the lab shows which ways of estimating still give the right answer.
The instrument keeps a particle's own wandering, with D = 0.429 μm2/s, apart from what a camera records. Each recorded position carries an error of standard deviation σ = 0.2 μm, and each frame averages the motion over an exposure of 0.5 s in a 1 s interval. A recorded step then has variance 2D(τ − Te/3) + 2σ2 = 0.716 + 0.080 = 0.796 μm2, not 2Dτ, and neighbouring steps are correlated, by DTe/3 − σ2 = 0.032 μm2: the blur links them positively and the shared noisy position links them negatively. Dividing the variance by 2τ, as the 1905 formula would, expects 0.398 μm2/s, 7 percent low, and this sample gives 0.406; its textbook interval is refused, because the steps are no longer independent. Two estimators allow for the camera. One adds the neighbouring covariance to the variance and gives 0.510 here; one uses only disjoint pairs of frames and gives 0.476, with a 95 percent interval from 0.326 to 0.697 μm2/s that contains the true value. Below τ = σ2/D = 0.093 s the camera's jitter outweighs the particle's own motion in any speed computed from positions.
Write each recorded position as the true position, averaged over the exposure, plus an error of variance σ2. A recorded step is the difference of two such positions, and its variance has two parts. The motion: over an interval τ a step has mean square 2Dτ, but each position is an average over the exposure Te, and averaging a random walk over a window removes a third of that window's share, so the motion contributes 2D(τ − Te/3). With D = 0.4294 μm2/s, τ = 1 s and Te = 0.5 s, that is 2 × 0.4294 × (1 − 0.1667) = 0.716 μm2. The errors: a step contains two independent position errors, 2σ2 = 2 × 0.04 = 0.080 μm2. In all, 0.796 μm2. Now take two neighbouring steps. They share one position, whose error enters the first with a plus sign and the second with a minus sign, so it gives them a covariance of −σ2 = −0.040 μm2; the blur makes them share a little motion, +DTe/3 = 0.4294 × 0.1667 = 0.072 μm2. Their covariance is 0.072 − 0.040 = 0.032 μm2. The 1905 rule, D = variance/(2τ), then expects 0.796/2 = 0.398 μm2/s instead of 0.429. Adding twice the covariance to the variance cancels both the blur and the noise terms, (0.796 + 2 × 0.032)/(2τ) = 0.429 on average, though with 100 steps its scatter is large, and this sample gives 0.510. Using only disjoint pairs of frames keeps every pair independent, at the cost of half the data: 0.476 μm2/s, with an interval from 0.326 to 0.697. Finally the speed: the camera adds 2σ2 to each step's mean square and the particle adds 2Dτ, and they are equal when τ = σ2/D = 0.04/0.4294 = 0.093 s.
Modern qualifications
None of this is in the 1905 paper, which treats every position as exact. Einstein did warn, in 1906 and again in 1907, that a speed computed as displacement over time grows as the interval shrinks, so it is not the particle's speed. The blur term comes from studies of camera exposure in particle tracking (Savin and Doyle, 2005), the full model of variance and covariance is Berglund's (2010), and the estimator that uses the covariance is due to Vestergaard, Blainey and Flyvbjerg (2014).
Show the code
The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
cameraMoments · src/physics/reference/inference/observation.ts · this site’s source, as built · sha256:83cfd1186b1aa96f8d0dfdd59a89c84e241a51db1afd7a43d678d18f6070dc1b
This function computes the listed outputs when it runs.
In words
For a shutter open for a time Te out of each frame interval dt, and a localization error of standard deviation sigma, the measured increment variance is 2 D (dt - Te/3) + 2 sigma squared, and neighbouring increments acquire a covariance of D Te/3 - sigma squared. The function returns both, the apparent speed a reader would compute from each, and their ratio. At a diffusivity of 3.1 times 10^-13 m^2/s and half-second frames: an ideal camera gives a variance of 3.1 times 10^-13 and a ratio of 1; a shutter open the whole interval gives 2.067 times 10^-13 and a ratio of 0.816; a localization error of 0.2 micrometres with no blur gives 3.9 times 10^-13 and a ratio of 1.122.
Implementation
export function cameraMoments(p: CameraModel): Computation<
Readonly<{
variance: number;
covariance: number;
naiveExpectation: number;
idealApparentSpeed: number;
measuredApparentSpeed: number;
apparentSpeedRatio: number;
crossover: number | null;
}>
> {
if (
!finite(p.D, p.dt, p.exposure, p.sigma, p.drift) ||
p.D <= 0 ||
p.dt <= 0 ||
p.exposure < 0 ||
p.exposure > p.dt ||
p.sigma < 0 ||
![1, 2].includes(p.d)
)
return invalid(
"Use positive diffusion and spacing, nonnegative localization error, exposure between zero and spacing, and one or two coordinates.",
);
const variance = 2 * p.D * (p.dt - p.exposure / 3) + 2 * p.sigma ** 2;
const covariance = (p.D * p.exposure) / 3 - p.sigma ** 2;
const naiveExpectation = variance / (2 * p.dt) + (p.drift ** 2 * p.dt) / (2 * p.d);
// These speeds describe the mean-subtracted coordinate spread, not drift.
const idealApparentSpeed = Math.sqrt(2 * p.D * p.dt) / p.dt;
const measuredApparentSpeed =
p.exposure === 0 && p.sigma === 0 ? idealApparentSpeed : Math.sqrt(variance) / p.dt;
const apparentSpeedRatio = measuredApparentSpeed / idealApparentSpeed;
const crossover = p.sigma > 0 && p.exposure === 0 ? p.sigma ** 2 / p.D : null;
if (
!finite(
variance,
covariance,
naiveExpectation,
idealApparentSpeed,
measuredApparentSpeed,
apparentSpeedRatio,
crossover ?? 0,
) ||
variance <= 0 ||
idealApparentSpeed <= 0
)
return invalid("Camera moments cannot be represented at this numerical scale.");
return {
kind: "accepted",
data: Object.freeze({
variance,
covariance,
naiveExpectation,
idealApparentSpeed,
measuredApparentSpeed,
apparentSpeedRatio,
crossover,
}),
};
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
covarianceEstimator · src/physics/reference/inference/observation.ts · this site’s source, as built · sha256:c819dee82ba95281ed8aad5cd93dc656ca7b3acc11633efc7497f1a710882dab
This function computes the listed outputs when it runs.
In words
Two measured moments, two unknowns. The diffusivity is the variance over two plus the covariance, all over the frame interval; the localization variance is a weighted combination of the two with the exposure entering through the ratio Te / 6 dt. Both come out of one pass over the increments, and neither needs the other declared in advance, which is what the previous function's opposite signs make possible.
Implementation
/** Known-drift moments. Do not silently substitute a fitted mean: centering
* changes the finite-sample covariance expectation. Channels are independent. */
export function covarianceEstimator(
increments: Float64Array,
dt: number,
{ d, exposure, knownDrift = 0 }: { d: number; exposure: number; knownDrift?: number },
): Assessment<Readonly<{ variance: number; covariance: number; D: number; sigma2: number }>> {
if (
!(increments instanceof Float64Array) ||
![1, 2].includes(d) ||
increments.length % d ||
increments.length > 100000 ||
!finite(dt, exposure, knownDrift) ||
dt <= 0 ||
exposure < 0 ||
exposure > dt ||
!increments.every(Number.isFinite)
)
return invalid(
"Use finite equally spaced increments, admitted exposure and an explicitly known drift.",
);
const M = increments.length / d;
if (M < 3) return missing("The covariance estimator needs at least three increments.");
let variance = 0,
covariance = 0;
for (let c = 0; c < d; c++)
for (let i = 0; i < M; i++) {
const incA = increments[i * d + c];
if (incA === undefined) continue;
const a = incA - (c === 0 ? knownDrift * dt : 0);
variance += (a * a) / (d * M);
if (i < M - 1) {
const incB = increments[(i + 1) * d + c];
if (incB !== undefined) {
const b = incB - (c === 0 ? knownDrift * dt : 0);
covariance += (a * b) / (d * (M - 1));
}
}
}
const R = exposure / (6 * dt),
D = (variance / 2 + covariance) / dt;
const sigma2 = R * variance + (2 * R - 1) * covariance;
if (!finite(variance, covariance, D, sigma2))
return invalid("The sample moments cannot be represented.");
// Negative finite-sample estimates are diagnostics, not silently clipped.
return { kind: "accepted", data: Object.freeze({ variance, covariance, D, sigma2 }) };
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
disjointPairsKnownNoiseInterval · src/physics/reference/inference/observation.ts · this site’s source, as built · sha256:28f46917a5658571285f63148076eba58dc36a31814a32f4a74b00ccbbf3cf2b
This function computes the listed outputs when it runs.
In words
Take frames in pairs, (0,1), (2,3) and so on, so that no frame and no localization error appears in two increments. Estimate the increment variance from those pairs, subtract twice the noise variance, and divide by twice the interval less a third of the exposure. The interval comes from the chi-square band on the variance, with the noise endpoints subtracted in the widening direction. Drift is fitted from the pairs rather than taken from the truth, which costs a degree of freedom and is the honest choice when a reader has only the frames.
Implementation
/** Disjoint frame pairs (0,1),(2,3),... share neither frames nor noise.
* Uniform exposures are forward [t_i,t_i+Te], Te <= dt. Their Brownian
* supports are disjoint too. Constant drift is fitted, not taken from truth.
* A negative upper endpoint gives an EMPTY physical confidence set, a miss
* which must be retained in coverage studies, not retried or made positive.
*/
export function disjointPairsKnownNoiseInterval(
input: Readonly<{
positions: Float64Array;
dt: number;
exposure: number;
d: number;
alpha: number;
noise: { kind: "exact"; sigma2: number } | { kind: "stationary-clicks"; estimate: ClickNoise };
equalSpacing?: boolean;
independentNoise?: boolean;
}>,
): Assessment<PairInterval> {
const { positions, dt, exposure, d, alpha, noise } = input;
if (
!(positions instanceof Float64Array) ||
![1, 2].includes(d) ||
positions.length % d ||
!finite(dt, exposure, alpha) ||
dt <= 0 ||
exposure < 0 ||
exposure > dt ||
alpha <= 0 ||
alpha >= 1 ||
!positions.every(Number.isFinite)
)
return invalid(
"Use finite frame positions, one or two coordinates, uniform exposure no longer than frame spacing, and valid coverage.",
);
if (input.equalSpacing === false || input.independentNoise === false)
return missing(
"This pair procedure requires equal spacing and independent Gaussian localization errors.",
);
const pairs = Math.floor(positions.length / d / 2);
if (pairs < 2) return missing("At least two disjoint frame pairs are needed when fitting drift.");
if (!noise || !["exact", "stationary-clicks"].includes(noise.kind))
return invalid("Declare exact localization variance or a stationary-click estimate.");
const sigma2 = noise.kind === "exact" ? noise.sigma2 : noise.estimate?.sigma2;
if (!Number.isFinite(sigma2) || sigma2 < 0)
return invalid("Localization variance must be finite and nonnegative.");
const increments = new Float64Array(pairs * d);
for (let k = 0; k < pairs; k++)
for (let c = 0; c < d; c++) {
const posNext = positions[(2 * k + 1) * d + c];
const posPrev = positions[2 * k * d + c];
if (posNext !== undefined && posPrev !== undefined) {
increments[k * d + c] = posNext - posPrev;
}
}
const e = estimateIncrements(increments, 0.5, d, "drift-centered");
if (e.kind !== "accepted") return e;
const estimatedNoise = noise.kind === "stationary-clicks",
alphaVariance = estimatedNoise ? alpha / 2 : alpha;
const varianceBand = chiSquareInterval({
dHat: e.data.unbiasedDHat,
q: e.data.q,
alpha: alphaVariance,
estimatorId: "disjoint-pair-coordinate-variance",
});
if (varianceBand.kind !== "accepted") return varianceBand;
let noiseInterval: readonly [number, number] = [sigma2, sigma2];
if (noise.kind === "stationary-clicks") {
const n = noise.estimate;
if (n.d !== d || !Number.isSafeInteger(n.clicks) || n.clicks < 5 || n.q !== d * (n.clicks - 1))
return invalid(
"Stationary-click dimensions and degrees of freedom must match the noise declaration.",
);
const band = chiSquareInterval({
dHat: sigma2,
q: n.q,
alpha: alpha / 2,
estimatorId: "stationary-feature-noise-variance",
});
if (band.kind !== "accepted") return band;
noiseInterval = [band.data.lower, band.data.upper];
}
const denominator = 2 * (dt - exposure / 3);
const rawLower = (varianceBand.data.lower - 2 * noiseInterval[1]) / denominator;
const upper = (varianceBand.data.upper - 2 * noiseInterval[0]) / denominator;
const estimate = (e.data.unbiasedDHat - 2 * sigma2) / denominator;
if (!finite(rawLower, upper, estimate))
return invalid("The noise-corrected interval cannot be represented.");
const coverageKind = estimatedNoise ? "conservative" : "exact";
const interval: StatisticalInterval | null =
upper < 0
? null
: Object.freeze({
lower: Math.max(0, rawLower),
upper,
q: e.data.q,
coverage: 1 - alpha,
uncertaintyKind: "statistical-interval",
coverageKind,
estimatorId: estimatedNoise
? "disjoint-pairs; stationary clicks; Bonferroni"
: "disjoint-pairs; exact localization variance",
});
return {
kind: "accepted",
data: Object.freeze({
estimate,
pairs,
q: e.data.q,
interval,
empty: interval === null,
lowerClipped: rawLower < 0,
noiseInterval: Object.freeze(noiseInterval),
coverage: 1 - alpha,
coverageKind,
}),
};
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
stationaryClickNoiseEstimate · src/physics/reference/inference/observation.ts · this site’s source, as built · sha256:edf6a3b57f9af2fdeb61bce6f389dec306fd70e77885bf772cc1551ecb1c81fb
This function computes the listed outputs when it runs.
In words
It takes at least five clicks per coordinate on a stationary feature and returns the variance of their scatter, with the degrees of freedom that variance carries. That number is then the noise the pair interval subtracts, so the laboratory never has to assume a localization error: a reader supplies one by doing the same thing an experimenter would.
Implementation
export function stationaryClickNoiseEstimate(
clicks: Float64Array,
{ d }: { d: number },
): Assessment<ClickNoise> {
if (
!(clicks instanceof Float64Array) ||
![1, 2].includes(d) ||
clicks.length % d ||
clicks.length / d < 5
)
return invalid("At least five stationary-feature clicks per coordinate are required.");
const e = estimateIncrements(clicks, 0.5, d, "drift-centered");
if (e.kind !== "accepted") return e;
return {
kind: "accepted",
data: Object.freeze({ sigma2: e.data.unbiasedDHat, q: e.data.q, clicks: clicks.length / d, d }),
};
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
bartlettBandsMA1 · src/physics/reference/inference/observation.ts · this site’s source, as built · sha256:4b2cccf1506e72469656be3250df670885efe5ab2c1c5acc45a0b261d49c03dd
This function computes the listed outputs when it runs.
In words
Bartlett's asymptotic formulas for a moving-average process of order one, which is what camera increments are: correlated with their immediate neighbours and with nothing further away. Given the variance and the neighbour covariance and the number of increments, it returns the standard deviation each of those two moments would show across repeated runs.
Implementation
/** Asymptotic MA(1) sampling bands, NOT confidence intervals for diffusivity. */
export function bartlettBandsMA1(
gamma0: number,
gamma1: number,
M: number,
d = 1,
): Computation<Readonly<{ sdVariance: number; sdCovariance: number }>> {
if (
!finite(gamma0, gamma1) ||
gamma0 <= 0 ||
Math.abs(gamma1) > gamma0 / 2 ||
!Number.isSafeInteger(M) ||
M < 3 ||
![1, 2].includes(d)
)
return invalid("Use an admissible MA(1) covariance and at least three increments.");
const sdVariance = Math.sqrt((2 * (gamma0 ** 2 + 2 * gamma1 ** 2)) / (M * d));
const sdCovariance = Math.sqrt((gamma0 ** 2 + 3 * gamma1 ** 2) / (M * d));
if (!finite(sdVariance, sdCovariance) || sdVariance === 0 || sdCovariance === 0)
return invalid("The sampling band is outside the numerical range.");
return { kind: "accepted", data: { sdVariance, sdCovariance } };
}The explanation
Full explanation
A camera averages the motion over each exposure and adds uncertainty to every recorded position. The particle follows the same path either way, but the recorded displacements, and what they say about diffusion, change. The camera model is a later measurement aid, not Einstein's derivation.
Show every step of the investigation
Add localization noise, drift and a longer exposure one at a time, and compare what the recorded positions imply about the spread after each change.
An explanatory model, not an observation of nature. This embed starts from the laboratory’s worked defaults, not a saved run. Presentation options change the surrounding guide, never the numerical inputs.