assess op• Data kinds: flow2d → table
• Call: import fullseye as fs; fs.ledger.piv_peak_locking(flow, bins=20) (to call the implementation directly, import pivops; pivops.piv_peak_locking(flow, bins=20); from the registry, opspiv.get("piv_peak_locking"))
Strength of peak locking: how far the distribution of the fractional parts deviates from uniform.
Subpixel estimation has a bias that pulls the fractional part of the true displacement towards 0 or 0.5 when it is near there (a textbook systematic error of PIV, arising because the shape of the correlation peak differs from the shape of the fitted function). Unless the flow is uniform, the fractional part should be close to uniformly distributed, and the deviation from that is measured.
The index c0 is a chi-square-type deviation independent of the sample size:
sum((n_i - n_bar)^2 / n_bar) / (bins - 1). Sampling from a uniform distribution gives an expected value of 1, so around 1 it is indistinguishable from uniform; the larger, the more biased.
★ However, this index assumes that "the fractional part of the true displacement is uniform". In fields with few windows or slowly varying displacement, c0 of the ground truth itself also becomes large (measured: 82 for the ground truth of a linear ramp —— the window grid has only 19 columns, so the fractional part only appears discretely). Therefore read c0 compared with the ground truth of the same input.
The decisive diagnosis is something else —— vary the fractional part of a uniform translation from 0 to 0.9 and see whether the estimates lie on the diagonal. Measured (win=32, density 0.02):
========== ================= ==================
method RMS of frac. err. max abs. error
========== ================= ==================
gauss3 0.0037 px 0.0088 px
parabolic 0.0104 px 0.0151 px
centroid 0.2259 px 0.3701 px
========== ================= ==================
centroid answers 0.02 for a true 0.1 and 0.98 for 0.9 —— the textbook S-curve pulling towards integers. It confirms that what should appear did appear, and is not a defect of the implementation (that is why all 3 are kept).
Args:
flow: (2, h, w).
bins: number of classes of the histogram of the fractional part.
Returns:
dict: c0 (index for both components combined), hist ((2, bins)),
frac_mean / frac_std, bins.
• piv_displacement family guide
• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).
• Operator provenance and references — the sources of the research/methods this op family came from.
• The canonical algorithm (author, year) and its uses are named in the family usage guide above.
• piv_field_analysis_tour — py -3.11 examples/piv_field_analysis_tour.py
• poc_battery_electrode_breathing — py -3.11 examples/poc_battery_electrode_breathing.py
table as input)—
assess)piv_sample_at_windows · piv_error_stats · piv_time_statistics
*Provenance: pivops.py — PIV operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.