Skip to content
PreciSim
concepts

Calibration chains

The six chains, their order and dependencies, what each one is judged on, and why "chain" is the right word.

Why "chain" and not "a pile of calibrations"

Because they depend on each other in order, and when an earlier one is wrong the later one does not fail — it produces a plausible wrong number.

         ┌──────────────────────────┐
         │ C3 Intrinsics & distortion│  make what the camera sees geometrically correct
         └────────────┬─────────────┘
                      ↓
         ┌──────────────────────────┐
         │ C1 Pixel size             │  convert pixels to millimetres
         └────┬────────────────┬────┘
              ↓                ↓
   ┌──────────────────┐  ┌──────────────────────┐
   │ C2 Hand-eye       │  │ C4 Galvo field       │
   └────────┬─────────┘  └──────────────────────┘
            ↓
   ┌──────────────────┐   ┌──────────────────────┐
   │ C6 Stage geometry │   │ C5 Z focus (separate)│
   └──────────────────┘   └──────────────────────┘

The six

# Name Solves for Depends on Typical criterion
C1 Pixel size mm/px, rotation, non-orthogonality C3 deviation < 0.05 mm over 20 mm
C2 Hand-eye T_Tool_Cam or T_World_Cam C1 nine-point residual RMS < 0.03 mm
C3 Intrinsics & distortion fx, fy, cx, cy, k₁, k₂, p₁, p₂ reprojection error < 0.15 px
C4 Galvo field correction field distortion correction table C1 in-field residual RMS < 15 µm
C5 Z focus best focal plane, depth of field focus repeatability < 10 µm
C6 Stage geometry squareness, centre of rotation, flatness C1, C2 squareness error < 50 µrad

Those numbers are the default tolerances of the demo-2axis-vision machine. On real hardware you set them from your own error budget — in machine configuration, not in code.

Every chain has the same five steps

All of them implement one interface, so the UI, logging, archiving and re-run logic are shared:

public interface ICalibrationProcedure
{
    string Id { get; }
    IReadOnlyList<string> DependsOn { get; }
    Task<CalibResult> RunAsync(CalibContext ctx, IProgress<CalibProgress> p, CancellationToken ct);
}
Step Does On failure
prepare Check dependencies, fixtures and parameters Stop here. Never let someone spend five minutes to discover a missing dependency
acquire Collect data at planned poses A single bad pose is re-acquired; the run continues
solve Fit, report parameters and residual An odd residual must come with likely causes, not just a number
verify Re-project data held out of the solve Produces the deviation and PASS/FAIL
persist Versioned write Append only, never overwrite, always revertible

Verify data must not have been used in the solve. Fitting and validating on the same data produces a flattering residual and proves nothing — the most common piece of self-deception in calibration reports.

Ground-truth scoring: only on virtual devices

On real hardware you have a residual but no truth. The virtual device knows the truth, so it prints one more line:

solve:  mm/px = 0.019823
truth:  mm/px = 0.019841
verify: deviation 0.018 mm over 20 mm, tolerance 0.05 mm → PASS

The point is not prettier numbers. It is learning how small a residual has to be before the result is actually correct. Most people only really understand calibration the first time they see "residual 0.02 px, actual error 0.3 mm".

Where results live

%ProgramData%\PreciSim\calibration\
  demo-2axis-vision\
    C1-pixel-size\
      2026-09-21T10-24-13.json     ← one record per run, never overwritten
      latest.json                  ← points at the active record

Each record holds parameters, residual, the truth comparison (virtual only), a reference to the raw acquisition data, the software version and the operator. When something goes wrong, "which calibration did it start with" is answerable only because of this archive.

Last updated: Sep 21, 2026
Was this page helpful?