Пример #1
0
    def extract_measurements(self, raw_data, waits_in_use):
        self.logger.debug('extract_measurements')
        if waits_in_use:
            # There were waits in this shot. We need to wait until the other process has
            # determined their durations before we proceed:
            self.wait_durations_analysed.wait(self.h5_file)

        with h5py.File(self.h5_file, 'a') as hdf5_file:
            if waits_in_use:
                # get the wait start times and durations
                waits = hdf5_file['/data/waits']
                wait_times = waits['time']
                wait_durations = waits['duration']
            try:
                acquisitions = hdf5_file['/devices/' + self.device_name +
                                         '/AI']
            except KeyError:
                # No acquisitions!
                return
            try:
                measurements = hdf5_file['/data/traces']
            except KeyError:
                # Group doesn't exist yet, create it:
                measurements = hdf5_file.create_group('/data/traces')

            t0 = self.AI_start_delay
            for connection, label, t_start, t_end, _, _, _ in acquisitions:
                connection = _ensure_str(connection)
                label = _ensure_str(label)
                if waits_in_use:
                    # add durations from all waits that start prior to t_start of
                    # acquisition
                    t_start += wait_durations[(wait_times < t_start)].sum()
                    # compare wait times to t_end to allow for waits during an
                    # acquisition
                    t_end += wait_durations[(wait_times < t_end)].sum()
                i_start = int(np.ceil(self.buffered_rate * (t_start - t0)))
                i_end = int(np.floor(self.buffered_rate * (t_end - t0)))
                # np.ceil does what we want above, but float errors can miss the
                # equality:
                if t0 + (i_start - 1) / self.buffered_rate - t_start > -2e-16:
                    i_start -= 1
                # We want np.floor(x) to yield the largest integer < x (not <=):
                if t_end - t0 - i_end / self.buffered_rate < 2e-16:
                    i_end -= 1
                # IBS: we sometimes find that t_end (with waits) gives a time
                # after the end of acquisition.  The following line
                # will produce return a shorter than expected array if i_end
                # is larger than the length of the array.
                values = raw_data[connection][i_start:i_end + 1]
                i_end = i_start + len(values) - 1  # re-measure i_end

                t_i = t0 + i_start / self.buffered_rate
                t_f = t0 + i_end / self.buffered_rate
                times = np.linspace(t_i, t_f, len(values), endpoint=True)
                dtypes = [('t', np.float64), ('values', np.float32)]
                data = np.empty(len(values), dtype=dtypes)
                data['t'] = times
                data['values'] = values
                measurements.create_dataset(label, data=data)
    def extract_measurements(self, device_name):
        self.logger.debug('extract_measurements')
        with h5py.File(self.h5_file,'a') as hdf5_file:
            waits_in_use = len(hdf5_file['waits']) > 0
        if waits_in_use:
            # There were waits in this shot. We need to wait until the other process has
            # determined their durations before we proceed:
            self.wait_durations_analysed.wait(self.h5_file)

        with h5py.File(self.h5_file,'a') as hdf5_file:
            if waits_in_use:
                # get the wait start times and durations
                waits = hdf5_file['/data/waits']
                wait_times = waits['time']
                wait_durations = waits['duration']
            try:
                acquisitions = hdf5_file['/devices/'+device_name+'/ACQUISITIONS']
            except:
                # No acquisitions!
                return
            try:
                measurements = hdf5_file['/data/traces']
            except:
                # Group doesn't exist yet, create it:
                measurements = hdf5_file.create_group('/data/traces')
            for connection,label,start_time,end_time,wait_label,scale_factor,units in acquisitions:
                connection = _ensure_str(connection)
                label = _ensure_str(label)
                wait_label = _ensure_str(wait_label)
                if waits_in_use:
                    # add durations from all waits that start prior to start_time of acquisition
                    start_time += wait_durations[(wait_times < start_time)].sum()
                    # compare wait_times to end_time to allow for waits during an acquisition
                    end_time += wait_durations[(wait_times < end_time)].sum()
                start_index = int(numpy.ceil(self.buffered_rate*(start_time-self.ai_start_delay)))
                end_index = int(numpy.floor(self.buffered_rate*(end_time-self.ai_start_delay)))
                # numpy.ceil does what we want above, but float errors can miss the equality
                if self.ai_start_delay + (start_index-1)/self.buffered_rate - start_time > -2e-16:
                    start_index -= 1
                # We actually want numpy.floor(x) to yield the largest integer < x (not <=) 
                if end_time - self.ai_start_delay - end_index/self.buffered_rate < 2e-16:
                    end_index -= 1
                acquisition_start_time = self.ai_start_delay + start_index/self.buffered_rate
                acquisition_end_time = self.ai_start_delay + end_index/self.buffered_rate
                times = numpy.linspace(acquisition_start_time, acquisition_end_time, 
                                       end_index-start_index+1,
                                       endpoint=True)
                values = self.buffered_data[connection][start_index:end_index+1]
                dtypes = [('t', numpy.float64),('values', numpy.float32)]
                data = numpy.empty(len(values),dtype=dtype_workaround(dtypes))
                data['t'] = times
                data['values'] = values
                measurements.create_dataset(label, data=data)
 def wait_monitor(self):
     try:
         # Read edge times from the counter input task, indiciating the times of the
         # pulses that occur at the start of the experiment and after every wait. If a
         # timeout occurs, pulse the timeout output to force a resume of the master
         # pseudoclock. Save the resulting
         self.logger.debug('Wait monitor thread starting')
         with self.kill_lock:
             self.logger.debug('Waiting for start of experiment')
             # Wait for the pulse indicating the start of the experiment:
             if self.incomplete_sample_detection:
                 semiperiods = self.read_edges(1, timeout=None)
             else:
                 semiperiods = self.read_edges(2, timeout=None)
             self.logger.debug('Experiment started, got edges:' +
                               str(semiperiods))
             # May have been one or two edges, depending on whether the device has
             # incomplete sample detection. We are only interested in the second one
             # anyway, it tells us how long the initial pulse was. Store the pulse width
             # for later, we will use it for making timeout pulses if necessary. Note
             # that the variable current_time is labscript time, so it will be reset
             # after each wait to the time of that wait plus pulse_width.
             current_time = pulse_width = semiperiods[-1]
             self.semiperiods.append(semiperiods[-1])
             # Alright, we're now a short way into the experiment.
             for wait in self.wait_table:
                 # How long until when the next wait should timeout?
                 timeout = wait['time'] + wait['timeout'] - current_time
                 timeout = max(timeout, 0)  # ensure non-negative
                 # Wait that long for the next pulse:
                 self.logger.debug(
                     'Waiting for pulse indicating end of wait')
                 semiperiods = self.read_edges(2, timeout)
                 # Did the wait finish of its own accord, or time out?
                 if semiperiods is None:
                     # It timed out. Better trigger the clock to resume!
                     msg = """Wait timed out; retriggering clock with {:.3e} s pulse
                         ({} edge)"""
                     msg = dedent(msg).format(pulse_width,
                                              self.timeout_trigger_type)
                     self.logger.debug(msg)
                     self.send_resume_trigger(pulse_width)
                     # Wait for it to respond to that:
                     self.logger.debug(
                         'Waiting for pulse indicating end of wait')
                     semiperiods = self.read_edges(2, timeout=None)
                 # Alright, now we're at the end of the wait.
                 self.semiperiods.extend(semiperiods)
                 self.logger.debug('Wait completed')
                 current_time = wait['time'] + semiperiods[-1]
                 # Inform any interested parties that a wait has completed:
                 postdata = _ensure_str(wait['label'])
                 self.wait_completed.post(self.h5_file, data=postdata)
             # Inform any interested parties that waits have all finished:
             self.logger.debug('All waits finished')
             self.all_waits_finished.post(self.h5_file)
     except Exception:
         self.logger.exception('Exception in wait monitor thread:')
         # Save the exception so it can be raised in transition_to_manual
         self.wait_monitor_thread_exception = sys.exc_info()
    def transition_to_buffered(self, device_name, h5file, initial_values,
                               fresh):
        self.logger.debug('transition_to_buffered')

        # read channels, acquisition rate, etc from H5 file
        with h5py.File(h5file, 'r') as f:
            group = f['/devices/' + device_name]
            if 'AI' not in group:
                # No acquisition
                return {}
            AI_table = group['AI'][:]
            device_properties = properties.get(f, device_name,
                                               'device_properties')

        chans = [_ensure_str(c) for c in AI_table['connection']]
        # Remove duplicates and sort:
        if chans:
            self.buffered_chans = sorted(set(chans), key=split_conn_AI)
        self.h5_file = h5file
        self.buffered_rate = device_properties['acquisition_rate']
        self.acquired_data = []
        # Stop the manual mode task and start the buffered mode task:
        self.stop_task()
        self.buffered_mode = True
        self.start_task(self.buffered_chans, self.buffered_rate)
        return {}
Пример #5
0
    def check_status(self):
        """Checks the operational status of the PrawnBlaster.

        This is automatically called by BLACS to update the status
        of the PrawnBlaster. It also reads the lengths of any 
        accumulated waits during a shot.

        Returns:
            (int, int, bool): Tuple containing:

            - **run_status** (int): Possible values are: 

                * 0 : manual-mode
                * 1 : transitioning to buffered execution
                * 2 : buffered execution
                * 3 : abort requested
                * 4 : currently aborting buffered execution
                * 5 : last buffered execution aborted
                * 6 : transitioning to manual mode

            - **clock_status** (int): Possible values are:

                * 0 : internal clock
                * 1 : external clock

            - **waits_pending** (bool): Indicates if all expected waits have
              not been read out yet.
        """

        if (self.started and self.wait_table is not None
                and self.current_wait < len(self.wait_table)):
            # Try to read out wait. For now, we're only reading out waits from
            # pseudoclock 0 since they should all be the same (requirement imposed by labscript)
            self.prawnblaster.write(b"getwait %d %d\r\n" %
                                    (0, self.current_wait))
            response = self.prawnblaster.readline().decode()
            if response != "wait not yet available\r\n":
                # Parse the response from the PrawnBlaster
                wait_remaining = int(response)
                # Divide by two since the clock_resolution is for clock pulses, which
                # have twice the clock_resolution of waits
                # Technically, waits also only have a resolution of `clock_resolution`
                # but the PrawnBlaster firmware accepts them in half of that so that
                # they are easily converted to seconds via the clock frequency.
                # Maybe this was a mistake, but it's done now.
                clock_resolution = self.device_properties[
                    "clock_resolution"] / 2
                input_response_time = self.device_properties[
                    "input_response_time"]
                timeout_length = round(
                    self.wait_table[self.current_wait]["timeout"] /
                    clock_resolution)

                if wait_remaining == (2**32 - 1):
                    # The wait hit the timeout - save the timeout duration as wait length
                    # and flag that this wait timedout
                    self.measured_waits[self.current_wait] = (timeout_length *
                                                              clock_resolution)
                    self.wait_timeout[self.current_wait] = True
                else:
                    # Calculate wait length
                    # This is a measurement of between the end of the last pulse and the
                    # retrigger signal. We obtain this by subtracting off the time it takes
                    # to detect the pulse in the ASM code once the trigger has hit the input
                    # pin (stored in input_response_time)
                    self.measured_waits[self.current_wait] = (
                        (timeout_length - wait_remaining) *
                        clock_resolution) - input_response_time
                    self.wait_timeout[self.current_wait] = False

                self.logger.info(
                    f"Wait {self.current_wait} finished. Length={self.measured_waits[self.current_wait]:.9f}s. Timed-out={self.wait_timeout[self.current_wait]}"
                )

                # Inform any interested parties that a wait has completed:
                self.wait_completed.post(
                    self.h5_file,
                    data=_ensure_str(
                        self.wait_table[self.current_wait]["label"]),
                )

                # increment the wait we are looking for!
                self.current_wait += 1

                # post message if all waits are done
                if len(self.wait_table) == self.current_wait:
                    self.logger.info("All waits finished")
                    self.all_waits_finished.post(self.h5_file)

        # Determine if we are still waiting for wait information
        waits_pending = False
        if self.wait_table is not None:
            if self.current_wait == len(self.wait_table):
                waits_pending = False
            else:
                waits_pending = True

        run_status, clock_status = self.read_status()
        return run_status, clock_status, waits_pending