AlexShkarin / pyLabLib

Python package for device control and experiment automation
http://pylablib.readthedocs.io
GNU General Public License v3.0
142 stars 34 forks source link

PicamLibError: Invalid Acquisition Buffer on measurements with binning != 1 #12

Closed LMSC-NTappy closed 2 years ago

LMSC-NTappy commented 2 years ago

Hello,

I run into issues when trying to set ROIs with x and/or y binning using the picam library and a PYLon BR Excelon camera. The trace is the following:

cam = PI.PicamCamera('555555') #With serial number for my camera
cam.set_roi(hstart=0, hend=1340, vstart=0, vend=100, hbin=2, vbin=1)
#(0, 1340, 0, 100, 2, 1)
cam.grab()
PicamLibError                             Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_5820/57262705.py in <module>
----> 1 cam.grab()

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\interface\camera.py in grab(self, nframes, frame_timeout, missing_frame, return_info, buff_size)
    524         acq_params=self._get_grab_acquisition_parameters(nframes,buff_size)
    525         frames,info=[],[]
--> 526         self.start_acquisition(**acq_params)
    527         try:
    528             while len(frames)<nframes:

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\PrincetonInstruments\picam.py in start_acquisition(self, *args, **kwargs)
    498         self._frame_counter.reset(self._acq_params["nframes"])
    499         self._commit_parameters()
--> 500         lib.Picam_StartAcquisition(self.handle)
    501     def stop_acquisition(self):
    502         if self.acquisition_in_progress():

<string> in <lambda>(camera)

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\core\utils\ctypes_wrap.py in wrapped_func(*vargs, **kwargs)
    276                     return a
    277             call_args=[_to_call_arg(n,t,a) for (n,t,a) in zip(argnames,prep_argtypes,func_args)]
--> 278             retval=func(*call_args)
    279             res=self._convert_results(rvals or [None],dict(zip(argnames,func_args)),retval,kwargs,rconv)
    280             if (not self.tuple_single_retval) and len(res)==0:

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\PrincetonInstruments\picam_lib.py in errchecker(result, func, arguments)
     42     def errchecker(result, func, arguments):  # pylint: disable=unused-argument
     43         if result not in passing:
---> 44             raise PicamLibError(func.__name__,result,lib=lib)
     45         return result
     46     return errchecker

PicamLibError: function 'Picam_StartAcquisition' raised error 30(PicamError_InvalidAcquisitionBuffer): Invalid Acquisition Buffer

Interestingly, if I do the following I am able to grab one single frame correctly and then I get a different error.

cam = PI.PicamCamera('555555') #With serial number for my camera
cam.set_roi(hstart=0, hend=1340, vstart=0, vend=100, hbin=2, vbin=1)
#(0, 1340, 0, 100, 2, 1)
cam.start_acquisition()
cam.read_oldest_image()
# array([[ 8642,  8930,  8769, ..., 10725, 10941, 11006],
#       [ 9702,  9723,  9791, ..., 11412, 11205, 11122],
#       [10224, 10151, 10315, ..., 12148, 11835, 12082],
#       ...,
#       [59284, 58933, 58707, ..., 64423, 64048, 64103],
#       [59473, 59159, 59371, ..., 64822, 65382, 64892],
#       [57627, 57855, 57832, ..., 62657, 63563, 62808]], dtype=uint16)
_.shape 
(100, 670)
cam.read_oldest_image()
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_4736/680920542.py in <module>
----> 1 cam.read_oldest_image()

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\interface\camera.py in read_oldest_image(self, peek, return_info)
    474         If ``return_info==True``, return tuple ``(frame, info)``, where ``info`` is an info tuples (camera-dependent, see :meth:`read_multiple_images`).
    475         """
--> 476         rng=self.get_new_images_range()
    477         if rng is None or rng[0]==rng[1]:
    478             return None

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\interface\camera.py in get_new_images_range(self)
    403         If some images were in the buffer were overwritten, exclude them from the range.
    404         """
--> 405         acquired_frames=self._get_acquired_frames()
    406         if acquired_frames is None:
    407             return None

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\PrincetonInstruments\picam.py in _get_acquired_frames(self)
    528                     break
    529     def _get_acquired_frames(self):
--> 530         self._wait_for_acquisition_update(reps=3)
    531         return self._waited_frames
    532 

~\.conda\envs\pmd_dev\lib\site-packages\pylablib\devices\PrincetonInstruments\picam.py in _wait_for_acquisition_update(self, timeout, reps)
    521                 try:
    522                     avail,_=lib.Picam_WaitForAcquisitionUpdate(self.handle,timeout)
--> 523                     assert avail.initial_readout==ctypes.addressof(self._buffer)+(self._waited_frames%self._buffer_frames)*self._frame_bytes
    524                     self._waited_frames+=avail.readout_count
    525                 except PicamLibError as err:

AssertionError:

Any idea why it should be the case?

LMSC-NTappy commented 2 years ago

Ah, furthermore on this: I have noticed that the camera has a Readout Stride Different from Frame Stride or Frame Size only if the binning is set different from 1 in the ROI. See for example:

bintests = [(0,1340,0,100,1,1),
            (0,500,0,100,1,1),
            (0,500,0,50,1,1),
            (0,1340,0,100,2,1),
            (0,1340,0,100,1,2),
            (0,1340,0,100,2,2),
            (0,1024,0,50,2,2),]
for binning in bintests:
    cam.set_roi(*binning)
    cam._commit_parameters()
    print(f"""X0 {binning[0]}, X1 {binning[1]:04d}, Y0 {binning[2]}, Y1 {binning[3]:03d}, BinX {binning[4]} BinY {binning[5]}    """
          f"""Frame stride   {cam.cav['Frame Stride']:06d}, """ \
          f"""Frame size {cam.cav['Frame Size']:06d}, """ \
          f"""Readout Stride {cam.cav['Readout Stride']:06d}""")
# X0 0, X1 1340, Y0 0, Y1 100, BinX 1 BinY 1    Frame stride   268000, Frame size 268000, Readout Stride 268000
# X0 0, X1 0500, Y0 0, Y1 100, BinX 1 BinY 1    Frame stride   100000, Frame size 100000, Readout Stride 100000
# X0 0, X1 0500, Y0 0, Y1 050, BinX 1 BinY 1    Frame stride   050000, Frame size 050000, Readout Stride 050016
# X0 0, X1 1340, Y0 0, Y1 100, BinX 2 BinY 1    Frame stride   134000, Frame size 134000, Readout Stride 134400
# X0 0, X1 1340, Y0 0, Y1 100, BinX 1 BinY 2    Frame stride   134000, Frame size 134000, Readout Stride 134016
# X0 0, X1 1340, Y0 0, Y1 100, BinX 2 BinY 2    Frame stride   067000, Frame size 067000, Readout Stride 067200
# X0 0, X1 1024, Y0 0, Y1 050, BinX 2 BinY 2    Frame stride   025600, Frame size 025600, Readout Stride 025600

I am starting to suspect pyLabLib.pylablib.devices.PrincetonInstruments.picam.PicamCamera which does: https://github.com/AlexShkarin/pyLabLib/blob/8026a79a3241cd2c3ec4cbe30d960b57614eb52d/pylablib/devices/PrincetonInstruments/picam.py#L483

I will try to see if changing this to self.cav['Readout Stride'] solves this.

Cheers

Nicolas

LMSC-NTappy commented 2 years ago

Update: allocating buffer to self.cav['Readout Stride'] fixed my problem. I'll let you decide wether this should be pushed in the main repository or not. It might cause issue with other princeton instrument cameras, I don't know

Best Regards

Nicolas