Skip to content

Commit

Permalink
Improve the device kit exposure timing.
Browse files Browse the repository at this point in the history
  • Loading branch information
cmeyer committed Dec 30, 2024
1 parent 554f688 commit fb8e590
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 5 deletions.
7 changes: 5 additions & 2 deletions nion/device_kit/CameraDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,20 @@ def __direct_acquire(self, cancel_event: threading.Event, do_sync: bool = False)
# if do_sync is True, the scan device will sync with its acquisition thread before
# advancing the pixel. this avoids race conditions of when the pixel count gets reset.
# this will be set only for the first frame in a sequence.
start = time.time()
start = time.perf_counter()
readout_area = self.readout_area
binning_shape = Geometry.IntSize(self.__binning, self.__binning if self.__symmetric_binning else 1)
# scan device is only set during synchronized acquisition
if self.__scan_device:
self.__scan_device.advance_pixel(do_sync=do_sync)
xdata = self.__simulator.get_frame_data(Geometry.IntRect.from_tlbr(*readout_area), binning_shape, self.__exposure, self.__instrument.scan_context, self.__instrument.probe_position)
self.__acquired_one_event.set()
elapsed = time.time() - start
elapsed = time.perf_counter() - start
wait_s = max(self.__exposure - elapsed, 0)
if not cancel_event.wait(wait_s):
actual_elapsed_s = time.perf_counter() - start
if actual_elapsed_s < self.__exposure:
time.sleep(self.__exposure - actual_elapsed_s) # adjust in case the wait returns early (observed on python 3.13/windows)
# thread event was not triggered during wait; signal that we have data
xdata._set_timestamp(DateTime.utcnow())
self.__xdata_buffer = xdata
Expand Down
4 changes: 2 additions & 2 deletions nion/device_kit/ScanDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(self, frame_number: int, channels: typing.List[Channel], frame_para
self.complete = False
self.bad = False
self.data_count = 0
self.start_time = time.time()
self.start_time = time.perf_counter()
self.scan_data: typing.Optional[typing.List[_NDArray]] = None


Expand Down Expand Up @@ -298,7 +298,7 @@ def read_partial(self, frame_number: typing.Optional[int], pixels_to_skip: int)
pixels_remaining = min(total_pixels - current_frame.data_count, int(time_slice * 1e6 / frame_parameters.pixel_time_us) + 1)
pixel_wait = min(pixels_remaining * frame_parameters.pixel_time_us / 1E6, time_slice)
time.sleep(pixel_wait)
target_count = min(int((time.time() - current_frame.start_time) / (frame_parameters.pixel_time_us / 1E6)), total_pixels)
target_count = min(int((time.perf_counter() - current_frame.start_time) / (frame_parameters.pixel_time_us / 1E6)), total_pixels)
if (new_pixels := target_count - self.__scan_simulator.current_pixel_flat) > 0:
self.__scan_simulator._advance_pixel(new_pixels)

Expand Down
1 change: 0 additions & 1 deletion nion/instrumentation/test/CameraControl_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,6 @@ def test_first_view_uses_correct_exposure(self):
hardware_source.start_playing(sync_timeout=3.0)
try:
hardware_source.get_next_xdatas_to_finish() # view again
time.sleep(0.001) # try to avoid Windows timer low precision issues
elapsed = time.perf_counter() - start
document_controller.periodic()
self.assertEqual(document_model.data_items[0].data_shape, hardware_source.get_expected_dimensions(4))
Expand Down

0 comments on commit fb8e590

Please sign in to comment.