Пример #1
0
    def open(self) -> None:
        """Doc."""

        try:
            self.open_instrument()
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #2
0
def _fit_and_get_param_dict(fit_func, x, y, p0, **kwargs) -> FitParams:
    """Doc."""

    try:
        popt, pcov = opt.curve_fit(fit_func, x, y, p0=p0, **kwargs)
    except (RuntimeWarning, RuntimeError, opt.OptimizeWarning) as exc:
        raise FitError(err_hndlr(exc, sys._getframe(), None, lvl="debug"))

    func_name = fit_func.__name__
    beta = popt
    try:
        beta_error = np.sqrt(np.diag(pcov))
    except Exception as exc:
        raise FitError(err_hndlr(exc, sys._getframe(), None, lvl="debug"))
    sigma = kwargs.get("sigma", 1)
    chi_sq_arr = np.square((fit_func(x, *beta) - y) / sigma)
    try:
        chi_sq_norm = chi_sq_arr.sum() / x.size
    except AttributeError:  # x is a tuple (2D Gaussian)
        chi_sq_norm = chi_sq_arr.sum() / x[0].size

    return FitParams(
        func_name,
        beta,
        beta_error,
        x,
        y,
        sigma,
        kwargs.get("x_limits", Limits()),
        kwargs.get("y_limits", Limits()),
        chi_sq_norm,
    )
Пример #3
0
    def __init__(self, param_dict, scanners_ai_tasks):
        super().__init__(
            param_dict,
            task_types=("ci", ),
        )

        try:
            cont_ai_task = [
                task for task in scanners_ai_tasks
                if (task.name == "Continuous AI")
            ][0]
            self.ai_cont_rate = cont_ai_task.timing.samp_clk_rate
            self.ai_cont_src = cont_ai_task.timing.samp_clk_term
        except IndexError:
            exc = DeviceError(
                f"{self.log_ref} can't be synced because scanners failed to Initialize"
            )
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.cont_read_buffer = np.zeros(shape=(self.CONT_READ_BFFR_SZ, ),
                                             dtype=np.uint32)
            self.last_avg_time = time.perf_counter()
            self.num_reads_since_avg = 0
            self.ci_chan_specs = {
                "name_to_assign_to_channel": "photon counter",
                "counter": self.address,
                "edge": ni_consts.Edge.RISING,
                "initial_count": 0,
                "count_direction": ni_consts.CountDirection.COUNT_UP,
            }

            with suppress(DeviceError):
                self.start_continuous_read_task()
                self.toggle_led_and_switch(True)
Пример #4
0
    def get_status(self):
        """Doc."""

        try:
            return self.get_queue_status()
        except Exception as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #5
0
    def __init__(self, param_dict):
        [setattr(self, key, val) for key, val in param_dict.items()]
        self.log_ref = param_dict["log_ref"]
        self._inst = None

        if not list_instruments(module="cameras"):
            exc = IOError("No UC480 cameras detected.")
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #6
0
 def __init__(self, param_dict):
     super().__init__(param_dict=param_dict, )
     try:
         self.open_instrument()
     except IOError as exc:
         err_hndlr(exc, sys._getframe(), locals(), dvc=self)
     else:
         self.init_data()
         self.purge()
Пример #7
0
    def __init__(self, param_dict, task_types, **kwargs):
        [setattr(self, key, val) for key, val in param_dict.items()]
        self.task_types = task_types
        self.tasks = SimpleNamespace(**{type: [] for type in task_types})

        try:
            len(ni.system.system.System().devices)
        except FileNotFoundError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #8
0
    def toggle(self, is_being_switched_on):
        """Doc."""

        try:
            self.open_instrument(
            ) if is_being_switched_on else self.close_instrument()
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.toggle_led_and_switch(is_being_switched_on)
            self.state = is_being_switched_on
Пример #9
0
    def set_auto_exposure(self, should_turn_on: bool) -> None:
        """Doc."""

        try:
            self._inst.set_auto_exposure(should_turn_on)
        except uc480.UC480Error:
            exc = IOError(
                f"{self.log_ref} was not properly closed.\nRestart to fix.")
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.is_auto_exposure_on = should_turn_on
Пример #10
0
    def laser_toggle(self, is_being_switched_on):
        """Doc."""

        cmnd = f"setLDenable {int(is_being_switched_on)}"
        try:
            self.write(cmnd)
        except Exception as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.emission_state = is_being_switched_on
            self.change_icons("on" if is_being_switched_on else "off")
Пример #11
0
    async def timeout(self) -> None:
        """awaits all individual async loops, each with its own repeat time."""

        try:
            await asyncio.gather(
                self._read_ci_and_ai(),
                self._update_dep(),
                self._update_main_gui(),
                self._update_video(),
            )
        except Exception as exc:
            err_hndlr(exc, sys._getframe(), locals())
        logging.debug("timeout function exited")
Пример #12
0
    def toggle(self, is_being_switched_on):
        """Doc."""

        try:
            self.digital_write(self.address, is_being_switched_on)
        except DaqError:
            exc = IOError(
                f"NI device address ({self.address}) is wrong, or data acquisition board is unplugged"
            )
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.toggle_led_and_switch(is_being_switched_on)
            self.state = is_being_switched_on
Пример #13
0
    def get_image(self, should_display=True) -> np.ndarray:
        """Doc."""

        try:
            if self.is_in_video_mode:
                self.latest_image = np.flipud((self.get_latest_frame()))
            else:
                self.latest_image = np.flipud((self.grab_image()))
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            if should_display:
                self.display.obj.display_image(self.latest_image, cursor=True)
            return self.latest_image
Пример #14
0
    async def move(self, dir, steps):
        """Doc."""

        cmd_dict = {
            "UP": f"my {-steps}",
            "DOWN": f"my {steps}",
            "LEFT": f"mx {steps}",
            "RIGHT": f"mx {-steps}",
        }
        try:
            self.write(cmd_dict[dir])
            await asyncio.sleep(500 * 1e-3)
            self.write("ryx ")  # release
        except Exception as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #15
0
    def start_scan_read_task(self, samp_clk_cnfg, timing_params) -> None:
        """Doc."""

        try:
            self.close_tasks("ai")
            self.create_ai_task(
                name="Continuous AI",
                address=self.ai_x_addr,
                chan_specs=self.ai_chan_specs + self.ao_int_chan_specs,
                samp_clk_cnfg=samp_clk_cnfg,
                timing_params=timing_params,
            )
            self.start_tasks("ai")
        except DaqError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #16
0
    def toggle(self, is_being_switched_on, **kwargs):
        """Doc."""

        try:
            if is_being_switched_on:
                self.open_instrument(model=self.model_query)
                self.laser_toggle(False)
            else:
                if self.state is True:
                    self.laser_toggle(False)
                self.close_instrument()
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.toggle_led_and_switch(is_being_switched_on, **kwargs)
            self.state = is_being_switched_on
Пример #17
0
    def toggle(self, is_being_switched_on):
        """Doc."""

        try:
            if is_being_switched_on:
                self._start_co_clock_sync()
            else:
                self.close_all_tasks()
        except DaqError:
            exc = IOError(
                f"NI device address ({self.address}) is wrong, or data acquisition board is unplugged"
            )
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.toggle_led_and_switch(is_being_switched_on)
            self.state = is_being_switched_on
Пример #18
0
    def set_power(self, value_mW):
        """Doc."""

        # check that value is within range
        if value_mW in self.power_limits_mW:
            try:
                # change the mode to power
                cmnd = "powerenable 1"
                self.write(cmnd)
                # then set the power
                cmnd = f"setpower 0 {value_mW}"
                self.write(cmnd)
            except Exception as exc:
                err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            Error(custom_txt=f"Power out of range {self.power_limits_mW}"
                  ).display()
Пример #19
0
    def get_prop(self, prop):
        """Doc."""

        prop_cmnd_dict = {
            "temp": "SHGtemp",
            "curr": "LDcurrent 1",
            "pow": "power 0",
        }
        cmnd = prop_cmnd_dict[prop]

        try:
            self.flush()  # get fresh response
            response = self.query(cmnd)
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            return response
Пример #20
0
    def toggle_video(self,
                     should_turn_on: bool,
                     keep_off=False,
                     **kwargs) -> bool:
        """Doc."""

        if keep_off:
            should_turn_on = False

        try:
            self.toggle_video_mode(should_turn_on, **kwargs)
            self.toggle_led_and_switch(should_turn_on)
            self.is_in_video_mode = should_turn_on
            return should_turn_on
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
            return not should_turn_on
Пример #21
0
    def set_current(self, value_mA):
        """Doc."""

        # check that value is within range
        if value_mA in self.current_limits_mA:
            try:
                # change the mode to power
                cmnd = "powerenable 0"
                self.write(cmnd)
                # then set the power
                cmnd = f"setLDcur 1 {value_mA}"
                self.write(cmnd)
            except Exception as exc:
                err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            Error(custom_txt=f"Current out of range {self.current_limits_mA}"
                  ).display()
Пример #22
0
        def smooth_start(axis: str,
                         ao_chan_specs: list,
                         final_pos: float,
                         step_sz: float = 0.25) -> None:
            """Doc."""
            # NOTE: Ask Oleg why we used 40 steps in LabVIEW (this is why I use a step size of 10/40 V)

            try:
                init_pos = self.ai_buffer[-1][3:][self.AXIS_INDEX[axis]]
            except IndexError:
                init_pos = self.last_int_ao[self.AXIS_INDEX[axis]]

            total_dist = abs(final_pos - init_pos)
            n_steps = div_ceil(total_dist, step_sz)

            if n_steps < 2:
                # one small step needs no smoothing
                return

            else:
                ao_data = np.linspace(init_pos, final_pos, n_steps)
                # move
                task_name = "Smooth AO Z"
                try:
                    self.close_tasks("ao")
                    ao_task = self.create_ao_task(
                        name=task_name,
                        chan_specs=ao_chan_specs,
                        samp_clk_cnfg={
                            "rate": self.
                            MIN_OUTPUT_RATE_Hz,  # WHY? see CreateAOTask.vi
                            "samps_per_chan": n_steps,
                            "sample_mode": ni_consts.AcquisitionType.FINITE,
                        },
                    )
                    ao_data = self._limit_ao_data(ao_task, ao_data)
                    self.analog_write(task_name, ao_data, auto_start=False)
                    self.start_tasks("ao")
                    self.wait_for_task("ao", task_name)
                    self.close_tasks("ao")
                except Exception as exc:
                    err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #23
0
    def start_scan_read_task(self, samp_clk_cnfg, timing_params) -> None:
        """Doc."""

        try:
            self.close_tasks("ci")
            self.create_ci_task(
                name="Scan CI",
                chan_specs=self.ci_chan_specs,
                chan_xtra_params={
                    "ci_count_edges_term":
                    self.CI_cnt_edges_term,
                    "ci_data_xfer_mech":
                    ni_consts.DataTransferActiveTransferMode.DMA,
                },
                samp_clk_cnfg=samp_clk_cnfg,
                timing_params=timing_params,
            )
            self.start_tasks("ci")
        except DaqError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #24
0
    def start_continuous_read_task(self) -> None:
        """Doc."""

        try:
            self.close_tasks("ai")
            self.create_ai_task(
                name="Continuous AI",
                address=self.ai_x_addr,
                chan_specs=self.ai_chan_specs + self.ao_int_chan_specs,
                samp_clk_cnfg={
                    "rate": self.MIN_OUTPUT_RATE_Hz,
                    "sample_mode": ni_consts.AcquisitionType.CONTINUOUS,
                    "samps_per_chan": self.CONT_READ_BFFR_SZ,
                },
            )
            self.init_ai_buffer()
            self.start_tasks("ai")
        except IOError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
        else:
            self.toggle_led_and_switch(False)
Пример #25
0
    def set_parameter(self, name, value) -> None:
        """Doc."""

        if name not in {"pixel_clock", "framerate", "exposure"}:
            raise ValueError(f"Unknown parameter '{name}'.")

        valid_value = Limits(getattr(self, f"{name}_range")).clamp(value)

        try:
            if name == "pixel_clock":
                self._inst._dev.PixelClock(uc480.lib.PIXELCLOCK_CMD_SET,
                                           int(valid_value))
                self.update_parameter_ranges()
            elif name == "framerate":
                self._inst._dev.SetFrameRate(valid_value)
                self.update_parameter_ranges()
            elif name == "exposure":
                self._inst._set_exposure(f"{valid_value}ms")
        except uc480.UC480Error:
            exc = IOError(
                f"{self.log_ref} was not properly closed.\nRestart to fix.")
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #26
0
    def start_continuous_read_task(self) -> None:
        """Doc."""

        try:
            self.close_tasks("ci")
            self.create_ci_task(
                name="Continuous CI",
                chan_specs=self.ci_chan_specs,
                chan_xtra_params={
                    "ci_count_edges_term": self.CI_cnt_edges_term
                },
                samp_clk_cnfg={
                    "rate": self.ai_cont_rate,
                    "source": self.ai_cont_src,
                    "sample_mode": ni_consts.AcquisitionType.CONTINUOUS,
                    "samps_per_chan": self.CONT_READ_BFFR_SZ,
                },
            )
            self.init_ci_buffer()
            self.start_tasks("ci")
        except DaqError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)
Пример #27
0
    def disp_ACF(self):
        """Doc."""
        def compute_acf(data):
            """Doc."""

            s = SolutionSFCSMeasurement()
            p = s.process_data_file(file_dict=self.prep_data_dict(),
                                    ignore_coarse_fine=True)
            s.data.append(p)
            s.correlate_and_average(cf_name=self.laser_mode)
            return s

        try:
            s = compute_acf(self.data_dvc.data)
        except RuntimeWarning as exc:
            # RuntimeWarning - some sort of zero-division in _calculate_weighted_avg
            # (due to invalid data during beam obstruction)
            errors.err_hndlr(exc, sys._getframe(), locals())
        except Exception as exc:
            print("THIS SHOULD NOT HAPPEN, HANDLE THE EXCEPTION PROPERLY!")
            errors.err_hndlr(exc, sys._getframe(), locals())
        else:
            cf = s.cf[self.laser_mode]
            try:
                cf.fit_correlation_function()
            except fit_tools.FitError as exc:
                # fit failed
                errors.err_hndlr(exc, sys._getframe(), locals(), lvl="debug")
                self.fit_led.set(self.icon_dict["led_red"])
                g0, tau = cf.g0, 0.1
                self.g0_wdgt.set(g0)
                self.tau_wdgt.set(0)
                self.plot_wdgt.obj.plot_acfs((cf.lag, "lag"), cf.avg_cf_cr, g0)
            else:
                # fit succeeded
                self.fit_led.set(self.icon_dict["led_off"])
                fp = cf.fit_params["diffusion_3d_fit"]
                g0, tau, _ = fp.beta
                fit_func = getattr(fit_tools, fp.func_name)
                self.g0_wdgt.set(g0)
                self.tau_wdgt.set(tau * 1e3)
                self.plot_wdgt.obj.plot_acfs((fp.x, "lag"),
                                             fp.y,
                                             g0,
                                             should_autoscale=True)
                y_fit = fit_func(cf.lag, *fp.beta)
                self.plot_wdgt.obj.plot(cf.lag, y_fit, "-.r")
                logging.info(
                    f"Aligning ({self.laser_mode}): g0: {g0/1e3:.1f}K, tau: {tau*1e3:.1f} us."
                )
Пример #28
0
    async def run(self):
        """Doc."""

        # initialize gui start/end times
        self.set_current_and_end_times()

        # turn on lasers
        try:
            await self.toggle_lasers()
        except (MeasurementError, errors.DeviceError) as exc:
            await self.stop()
            self.type = None
            errors.err_hndlr(exc, sys._getframe(), locals())
            return

        try:
            if self.scanning:
                self.setup_scan()
                self._app.gui.main.impl.device_toggle("pixel_clock",
                                                      leave_on=True)
                # make the circular ai buffer clip as long as the ao buffer
                self.scanners_dvc.init_ai_buffer(type="circular",
                                                 size=self.ao_buffer.shape[1])
                self.counter_dvc.init_ci_buffer()
            else:
                self.scanners_dvc.init_ai_buffer()

        except errors.DeviceError as exc:
            await self.stop()
            errors.err_hndlr(exc, sys._getframe(), locals())
            return

        else:
            self.is_running = True
            self.start_time = time.perf_counter()
            self.time_passed_s = 0
            file_num = 1
            logging.info(f"Running {self.type} measurement")

        try:
            while self.is_running and self.time_passed_s < self.duration_s:

                # initialize data buffer
                self.data_dvc.init_data()
                self.data_dvc.purge_buffers()

                if self.scanning:
                    self.counter_dvc.init_ci_buffer()
                    # re-start scan for each file
                    self.scanners_dvc.init_ai_buffer(
                        type="circular", size=self.ao_buffer.shape[1])
                    self.init_scan_tasks("CONTINUOUS")
                    self.scanners_dvc.start_tasks("ao")
                else:
                    self.scanners_dvc.init_ai_buffer()

                self.file_num_wdgt.set(file_num)

                logging.debug("FPGA reading starts.")

                # reading
                if self.repeat:
                    await self.record_data(self.start_time, timed=True)
                else:
                    await self.record_data(self.start_time,
                                           timed=True,
                                           size_limited=True)

                logging.debug("FPGA reading finished.")

                # collect final ai/CI
                self.counter_dvc.fill_ci_buffer()
                self.scanners_dvc.fill_ai_buffer()

                # case aligning and not manually stopped
                if self.repeat and self.is_running:
                    self.disp_ACF()
                    # reset measurement
                    self.set_current_and_end_times()
                    self.start_time = time.perf_counter()
                    self.time_passed_s = 0

                # case final alignment and not manually stopped
                elif self.final and self.is_running:
                    self.disp_ACF()
                    self.save_data(self.prep_data_dict(),
                                   self.build_filename(0))

                # case regular measurement and finished file or measurement
                elif not self.repeat:
                    self.save_data(self.prep_data_dict(),
                                   self.build_filename(file_num))
                    if self.scanning:
                        self.scanners_dvc.init_ai_buffer(
                            type="circular", size=self.ao_buffer.shape[1])

                file_num += 1

        except Exception as exc:  # TESTESTEST
            print("THIS SHOULD NOT HAPPEN!")
            errors.err_hndlr(exc, sys._getframe(), locals())

        if self.is_running:  # if not manually stopped
            await self.stop()

        self.type = None
Пример #29
0
    async def run(self):
        """Doc."""

        self.setup_scan()

        try:
            await self.toggle_lasers()
            self.data_dvc.init_data()
            self.data_dvc.purge_buffers()
            self._app.gui.main.impl.device_toggle("pixel_clock", leave_on=True)
            self.scanners_dvc.init_ai_buffer(type="inf")
            self.counter_dvc.init_ci_buffer(type="inf")

        except (MeasurementError, errors.DeviceError) as exc:
            await self.stop()
            self.type = None
            errors.err_hndlr(exc, sys._getframe(), locals())
            return

        else:
            n_planes = self.scan_params.n_planes
            self.plane_data = []
            self.start_time = time.perf_counter()
            self.time_passed_s = 0
            self.is_running = True
            logging.info(f"Running {self.type} measurement")

        # start all tasks (AO, AI, CI)
        self.init_scan_tasks("FINITE")
        self.scanners_dvc.start_tasks("ao")

        try:
            for plane_idx in range(n_planes):

                if self.is_running:

                    self.change_plane(plane_idx)
                    self.curr_plane_wdgt.set(plane_idx)
                    self.curr_plane = plane_idx

                    # Re-start only AO
                    self.init_scan_tasks("FINITE", ao_only=True)
                    self.scanners_dvc.start_tasks("ao")

                    # recording
                    await self.record_data(self.start_time, timed=False)

                    # collect final ai/CI
                    self.counter_dvc.fill_ci_buffer()
                    self.scanners_dvc.fill_ai_buffer()

                else:
                    break

        except MeasurementError as exc:
            await self.stop()
            errors.err_hndlr(exc, sys._getframe(), locals())
            return

        except Exception as exc:  # TESTESTEST
            print("THIS SHOULD NOT HAPPEN!")
            errors.err_hndlr(exc, sys._getframe(), locals())

        # finished measurement
        if self.is_running:  # if not manually stopped
            # prepare data
            data_dict = self.prep_data_dict()
            if self.always_save:  # save data
                self.save_data(data_dict, self.build_filename())
            self.keep_last_meas(data_dict)
            # show middle plane
            mid_plane = int(len(self.scan_params.set_pnts_planes) / 2)
            self.plane_shown.set(mid_plane)
            self.plane_choice.set(mid_plane)
            should_display_autocross = self.scan_params.auto_cross and (
                self.laser_mode == "exc")
            self._app.gui.main.impl.disp_plane_img(
                auto_cross=should_display_autocross)

        if self.is_running:  # if not manually before completion
            await self.stop()

        self.type = None
Пример #30
0
    def start_write_task(
        self,
        ao_data: np.ndarray,
        type: str,
        samp_clk_cnfg_xy: dict = {},
        samp_clk_cnfg_z: dict = {},
        start=True,
    ) -> None:
        """Doc."""
        def smooth_start(axis: str,
                         ao_chan_specs: list,
                         final_pos: float,
                         step_sz: float = 0.25) -> None:
            """Doc."""
            # NOTE: Ask Oleg why we used 40 steps in LabVIEW (this is why I use a step size of 10/40 V)

            try:
                init_pos = self.ai_buffer[-1][3:][self.AXIS_INDEX[axis]]
            except IndexError:
                init_pos = self.last_int_ao[self.AXIS_INDEX[axis]]

            total_dist = abs(final_pos - init_pos)
            n_steps = div_ceil(total_dist, step_sz)

            if n_steps < 2:
                # one small step needs no smoothing
                return

            else:
                ao_data = np.linspace(init_pos, final_pos, n_steps)
                # move
                task_name = "Smooth AO Z"
                try:
                    self.close_tasks("ao")
                    ao_task = self.create_ao_task(
                        name=task_name,
                        chan_specs=ao_chan_specs,
                        samp_clk_cnfg={
                            "rate": self.
                            MIN_OUTPUT_RATE_Hz,  # WHY? see CreateAOTask.vi
                            "samps_per_chan": n_steps,
                            "sample_mode": ni_consts.AcquisitionType.FINITE,
                        },
                    )
                    ao_data = self._limit_ao_data(ao_task, ao_data)
                    self.analog_write(task_name, ao_data, auto_start=False)
                    self.start_tasks("ao")
                    self.wait_for_task("ao", task_name)
                    self.close_tasks("ao")
                except Exception as exc:
                    err_hndlr(exc, sys._getframe(), locals(), dvc=self)

        axes_to_use = self.AXES_TO_BOOL_TUPLE_DICT[type]

        xy_chan_spcs = []
        z_chan_spcs = []
        ao_data_xy = np.empty(shape=(0, ))
        ao_data_row_idx = 0
        for ax, is_ax_used, ax_chn_spcs in zip("XYZ", axes_to_use,
                                               self.ao_chan_specs):
            if is_ax_used:
                if ax in "XY":
                    xy_chan_spcs.append(ax_chn_spcs)
                    if ao_data_xy.size == 0:
                        # first concatenate the X/Y data to empty array to have 1D array
                        ao_data_xy = np.concatenate(
                            (ao_data_xy, ao_data[ao_data_row_idx]))
                    else:
                        # then, if XY scan, stack the Y data below the X data to have 2D array
                        ao_data_xy = np.vstack(
                            (ao_data_xy, ao_data[ao_data_row_idx]))
                    ao_data_row_idx += 1
                else:  # "Z"
                    z_chan_spcs.append(ax_chn_spcs)
                    ao_data_z = ao_data[ao_data_row_idx]

        # start smooth
        if z_chan_spcs:
            smooth_start(axis="z",
                         ao_chan_specs=z_chan_spcs,
                         final_pos=ao_data_z[0])

        try:
            self.close_tasks("ao")

            if xy_chan_spcs:
                xy_task_name = "AO XY"
                ao_task = self.create_ao_task(
                    name=xy_task_name,
                    chan_specs=xy_chan_spcs,
                    samp_clk_cnfg=samp_clk_cnfg_xy,
                )
                ao_data_xy = self._limit_ao_data(ao_task, ao_data_xy)
                ao_data_xy = self._diff_vltg_data(ao_data_xy)
                self.analog_write(xy_task_name, ao_data_xy)

            if z_chan_spcs:
                z_task_name = "AO Z"
                ao_task = self.create_ao_task(
                    name=z_task_name,
                    chan_specs=z_chan_spcs,
                    samp_clk_cnfg=samp_clk_cnfg_z,
                )
                ao_data_z = self._limit_ao_data(ao_task, ao_data_z)
                self.analog_write(z_task_name, ao_data_z)

            if start is True:
                self.start_tasks("ao")

        except DaqError as exc:
            err_hndlr(exc, sys._getframe(), locals(), dvc=self)

        else:
            self.toggle_led_and_switch(True)