You set the exposure time to 16 µs, the call returns without an error, and the first frames come back darker than your light budget promised. Nothing crashed: the camera took your float value and snapped it to the nearest value it can physically produce, and most GenICam libraries do that quietly. If you compute strobe delays, blur budgets or brightness targets from the number you typed, your math is running on a value the camera does not hold. The rest of this page gives you the rounding rule as a formula, a worked example you can check by hand, and a set-readback pattern that keeps timing math on the camera's real numbers.
What the camera does instead of raising an error
Every GenICam float feature — exposure time, gain, timing delays — carries three numbers alongside its value: a minimum, a maximum and an increment. The camera can only hold values on the rungs between those limits, spaced one increment apart. When you set a value between rungs, the library picks the nearest rung and writes that instead. In most wrappers there is no exception, no error return and no log line.
The behavior surprises engineers who are used to enumerations, where an invalid symbol raises an error you can catch — see GenICam enumeration invalid value: check symbolics before you set. Floats take the opposite deal: your value is accepted, corrected and never mentioned again. Readback surprises appear in non-float nodes too; camera trigger mode source readback mismatches is the trigger-mode cousin of this problem.
The snap rule, as a formula
Name the node's minimum vmin, its increment inc, and the value you requested v. The writable values are the rungs min + k × inc for k = 0, 1, 2 and so on up to the maximum, and the library selects the rung closest to v:
Three details matter. The minimum is itself a rung, so k = 0 is always legal even for a tiny request. A request exactly halfway between two rungs is a corner case decided by the library's rounding rule, so keep setpoints off the midpoints. And a few float features report no constant increment at all — the standard's HasInc returns false — in which case there are no rungs to land between.
The GenICam float interface defines the increment as a queryable property; the standard names the calls HasInc and GetInc. The rung size is never a mystery. The next two sections show where to read it and what it does to a real request.
A worked example: 16 µs in, 12 µs out
Take a camera whose exposure time node reports a 12 µs minimum and a 9 µs increment. Its rungs sit at 12, 21, 30, 39 µs and upward. You request 16 µs:
- (16 − 12) / 9 = 0.44, which rounds to k = 0, so v* = the bottom rung — a quarter less exposure than you asked for, with no error raised.
The table shows where nearby requests land on this node:
| You request | The camera holds | Why |
|---|---|---|
| 16 µs | 12 µs | 4 µs down vs 5 µs up |
| 18 µs | 21 µs | 6 µs down vs 3 µs up |
| 21 µs | 21 µs | exact rung |
| 25 µs | 21 µs | 4 µs down vs 5 µs up |
| 26 µs | 30 µs | 5 µs down vs 4 µs up |
| 30 µs | 30 µs | exact rung |
Just past the midpoint the snap flips direction, which is why 25 and 26 land on different rungs.
Where the silent snap costs you
Signal strength is proportional to exposure time, so the down-snap in the example costs about a quarter of the signal — log₂ of the request-to-actual ratio is roughly 0.4 stops. If your light budget carried 20% headroom, one set call consumed it.
Motion blur moves with it. A part traveling 100 mm/s smears 100 mm/s × 16 µs = 1.6 µm during the exposure you asked for; the snapped value gives 1.2 µm and an up-snap to the next rung gives 2.1 µm. A published blur budget of 1.5 µm then passes on one camera model and fails on another, with identical code on both.
Timing sequences suffer in the other direction: a frame period or strobe delay computed as exposure plus margin loses that margin to an up-snap, and on triggered lines that shows up as overtrigger faults at production rate — sequenced exposure trigger timing: avoid overtrigger errors walks that failure down. Multi-camera banks drift unevenly: two models asked for the same setting can hold different actual values when their increments differ, so read back per camera, per feature.
Every area scan camera you drive through a GenICam float node follows this rule, whether it streams over GigE or USB3:
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Sensor format
- 1/1.7"
- Interface
- USB3
On high-speed lines the exposure sits inside the cycle budget itself, so the same snap moves line rate as well as brightness.
- Sensor format
- 1.1"
- Lens mount
- C-mount
- Interface
- USB3
- Resolution
- 12 MP
The quiet rounding waits downstream too. A setpoint that leaves your inspection code correct can shift again inside the controller's own float math; if your results drive PLC logic, this PLC float-rounding procedure shows where one controller family rounds, so the number you send is the number that arrives.
The set-readback-verify pattern
The fix is mechanical and costs one line of code: after every float set, read the value back and compute from the readback, not from the request.
// set - readback - verify, in pseudocode
double requested = 16.0; // µs — what you intend
double applied = 0.0; // µs — what the camera holds
exposure.SetValue(requested); // the node may snap silently
applied = exposure.GetValue(); // read it back, always
double increment = exposure.GetIncrement(); // rung width, for computing exact rungs
SetValue, GetValue and GetIncrement are the common wrapper spellings for the three calls; your library's names may differ, but the order does not: set, read back, then compute. On the example node, the readback prints 12.0 for a request of 16.0 — that one mismatched line is the snap, caught. In production, log requested and applied for every float feature at startup; the diff list is your camera's real timing specification.
The same discipline applies while the line runs: setting and reading parameters inside a capture loop has ordering traps of its own, covered in camera parameter set and get in a capture loop safely, and the Python side of the set call itself is walked through in setting camera exposure time through a GenICam API in Python.
Find min, max and increment without writing code
Open the camera in a GenICam feature browser and expand the exposure node: the value control sits beside its minimum, maximum and increment, and most viewers repeat the numbers in the node tooltip. In code, a capabilities query returns the same fields per feature — how to query camera capabilities with GenICam shows the calls.
Read the three numbers at startup, per camera. They belong to that feature on that model, not to the interface, so one camera's 9 µs rung predicts nothing about the next camera on the line. Recording them in the project notes takes a minute and settles most timing arguments later.
Choose the rung on purpose
When the exposure you need falls between rungs, do not request it and hope. Compute k yourself and set an exact rung. On the example node, a blur budget that allows at most 16 µs needs k = floor(0.44) = 0, so set the bottom rung: inside the budget, a quarter dimmer. A signal floor at the same level needs k = ceil(0.44) = 1, so set the next rung up: brighter, more blur. State the rounding direction in the comment beside the set call, because the trade is an engineering decision, not a rounding accident.
If you change exposure while the camera is already streaming, the mid-acquisition path adds its own failure mode; reduce exposure time mid-acquisition without an overtrigger error shows the safe sequence.
When the readback is still not the exposure you get
Two cases leave the readback truthful but not final. Under automatic exposure the camera re-times each frame and your manual value is only a starting point; the applied time then arrives in each frame's metadata, and read exposure time from frame metadata under auto exposure shows how to pull it. On triggered cameras, when the exposure starts relative to your trigger call is a separate question from how long it lasts — trigger call versus exposure time: understand capture timing separates the two. Snap correction and trigger timing are independent effects; check both before blaming either.
Checks that keep the snap from lying to you
- Set the value, then read it back with GetValue and compare before you use it anywhere.
- Read minimum, maximum and increment for every float feature you set, at initialization, per camera.
- Compute strobe delays, frame periods and blur budgets from the readback, never from the request.
- Keep setpoints off exact midpoints between rungs.
- Under auto exposure, take the applied exposure from frame metadata instead of trusting the node.
- Set exposure before streaming starts; the initialization order decides when your readback is trustworthy, as set manual exposure before streaming: initialization order explains.
- Save validated settings to a user set on the camera and load it at startup, so a power cycle cannot trade your rungs for defaults.
Shortlist the hardware, then wire the pattern in
If you are specifying cameras for a timing-sensitive cell, shortlist by sensor, resolution and interface in the area scan camera finder, then check the feature browser on the exact model before the pilot run — the rungs you find there are the ones your code will live with. The camera configurator pairs camera, lens and light in one pass, the area scan cameras category lists every model in the range, and more camera-side fixes sit on the cameras topic page. When a station needs this level of timing scrutiny and you want a second pair of eyes on the plan, the contact page reaches the applications team.
GigE, USB3, 10GigE and CoaXPress
1,287 models · from $149.00Questions
Do all float features snap, or only exposure time?
Every float node that carries an increment snaps: exposure time, gain, and timing features such as strobe or flash delay. Exposure time is where you notice it, because image brightness scales linearly with exposure, so a snap of a few microseconds on a short setting is a double-digit percentage signal change. A small gain step, by contrast, is easy to miss on a histogram. The habit is identical for every feature: set, read back, compute from the readback.
How do I see min, max and increment without writing code?
Yes — every vendor SDK ships a GenICam browser of some kind. Select the exposure feature and its minimum, maximum and increment appear alongside the value, usually in the tooltip as well. The same three fields come back from a capabilities query if you would rather script it. Write the numbers into the project notes once per camera model; the rungs belong to that feature on that model.
What does the GenICam standard say should happen when a float is rounded?
The GenICam control protocol treats a float that needs rounding as a warning case: the rounded value is set, and a warning can travel back to the host. In practice most libraries apply the nearest value quietly and surface nothing, which is why the behavior reads as silence. Treat the readback as the authoritative confirmation instead of waiting for an exception that will not come.
Does the snapped value survive a power cycle?
No better than any other feature value. Camera settings live in working memory, and unless you store them to a user set and load it at startup, the camera returns to its power-on defaults. A line that was verified on one rung can boot onto a different one tomorrow from a saved set — one more reason the startup readback log is worth keeping.


