Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TRCL-570][feat] introduce startScan Event to synchronize CCD with e-beam during SPARC acq #3027

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

pieleric
Copy link
Member

@pieleric pieleric commented Feb 6, 2025

From the moment that the acquisition ask the e-beam scanner to start and the e-beam is actually at the right position, it takes some time. It's in the order of a few ms. So far, the only e-beam scanner was semcomedi, and it was (surprisingly) constant in terms of time. It would take between 2 and 5 ms. So it was good enough to just always wait 5ms.

We now also have semnidaq, and the NI-DAQ library introduces a lot longer latency. While it can be as "fast" as 10ms, it sometimes takes 40ms to start a scan. There are probably ways to make it a little faster, but it's unlikely it will be possible to always keep all scanners < 5ms.

=> Use a new Event, startScan, for the e-beam scanner to report the e-beam is ready. Then, we can use it to directly start a CCD acquisition.

No code ever used this functionality. The semnidaq has something a
little similar, but it's a hardware event. So it actually could even
brinkg confusion. Now that we'll add another Event, remove this code.
Introduce a new (and almost first) software Event on the e-beam
scanners: startScan. It is emitted at the very beginning of the first
frame of a scan. If a scan acquires multiple frames, startScan is
emitted just once.

This will be used for better software synchronization of SPARC
acquisitions.
… e-beam

From the momement that the acquisition ask the e-beam scanner to start
and the e-beam is actually at the right position, it takes *some* time.
It's in the order of a few ms. So far, the only e-beam scanner was
semcomedi, and it was (surprisingly) constant in terms of time. It would
take between 2 and 5 ms. So it was good enough to just always wait 5ms.

We now also have semnidaq, and the NI-DAQ library introduces a lot longer latency.
While it can be as "fast" as 10ms, it sometimes takes 40ms to start a
scan. There are probably ways to make it a little faster, but it's
unlikely it will be possible to always keep all scanners < 5ms.

=> Use a new Event, startScan, for the e-beam scanner to report the
e-beam is ready. Then, we can use it to directly start a CCD
acquisition.
@pieleric pieleric changed the title [feat] introduce startScan Event to synchronize CCD with e-beam during SPARC acq [TRCL-570][feat] introduce startScan Event to synchronize CCD with e-beam during SPARC acq Feb 6, 2025
self.assertEqual(evt_counter.count, 1)
self.scanner.startScan.unsubscribe(evt_counter)


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to remove the extra space between the functions

@@ -1887,26 +1888,10 @@ def _acquireImage(self, n, px_idx, img_time, sem_time,
raise CancelledError()

# subscribe to _subscribers
# As soon as the e-beam start scanning (which can take a couple of ms), the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# As soon as the e-beam start scanning (which can take a couple of ms), the
# As soon as the e-beam starts scanning (which can take a couple of ms), the

@@ -1887,26 +1888,10 @@ def _acquireImage(self, n, px_idx, img_time, sem_time,
raise CancelledError()

# subscribe to _subscribers
# As soon as the e-beam start scanning (which can take a couple of ms), the
# startScan event is sent, which triggers the acquisition of one CCD frame.
for s, sub in zip(self._streams[:-1], self._subscribers[:-1]):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you comment on why the last element is excluded?

@@ -2119,12 +2112,11 @@ def _runAcquisitionScanStage(self, future):
if self._acq_state == CANCELLED:
raise CancelledError()

# Start e-beam scan. As soon as it really start, a startScan event is sent, which
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Start e-beam scan. As soon as it really start, a startScan event is sent, which
# Start e-beam scan. As soon as it really starts, a startScan event is sent, which

@@ -2008,9 +2001,9 @@ def _runAcquisitionScanStage(self, future):
# The idea of the acquiring with a scan stage:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# The idea of the acquiring with a scan stage:
# The idea of acquisition with a scan stage:

@@ -2251,6 +2253,23 @@ def _set_state(self, active):
time.sleep(self._activation_delay)


class EventOnce(model.Event):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplication of the function at the semcomedi driver. Maybe put it in a shared module?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. moved to driver.EventOnce

@@ -540,6 +544,9 @@ def _acquire_thread(self, callback):
# as in Odemis the convention for SEM is that the ebeam waits
# for _all_ the detectors to be ready before scanning.
self.data._waitSync()
if first_frame:
self.parent._scanner.startScan.notify()
first_frame = False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this automatically stop notifying something which is similar to the unsubscribe used in the testcases when self._acquisition_must_stop.clear() is called in finally: section?

# Temporarily switch the CCD to a different event trigger, so that it
# doesn't get triggered while the leech is running (because it could use the
# e-beam, which would send a startScan event)
self._ccd_df.synchronizedOn(self._ccd.softwareTrigger)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an assert line can be used to check that the notification boolean value of startscan is False before reusing the real trigger? Same for _acquireImage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants