1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
#
# This file is part of the PyMeasure package.
#
# Copyright (c) 2013-2024 PyMeasure Developers
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
import logging
from time import sleep, time
import numpy as np
from pymeasure.instruments import Instrument
from pymeasure.instruments.validators import truncated_range
from pymeasure.adapters import PrologixAdapter
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())
class KeithleyBuffer:
""" Implements the basic buffering capability found in
many Keithley instruments. """
buffer_points = Instrument.control(
":TRAC:POIN?", ":TRAC:POIN %d",
""" Control the number of buffer points. This does not represent actual points
in the buffer, but the configuration value instead. """,
validator=truncated_range,
values=[2, 1024],
cast=int
)
def config_buffer(self, points=64, delay=0):
""" Configures the measurement buffer for a number of points, to be
taken with a specified delay.
:param points: The number of points in the buffer.
:param delay: The delay time in seconds.
"""
# Enable measurement status bit
# Enable buffer full measurement bit
self.write(":STAT:PRES;*CLS;*SRE 1;:STAT:MEAS:ENAB 512;")
self.write(":TRAC:CLEAR;")
self.buffer_points = points
self.trigger_count = points
self.trigger_delay = delay
self.write(":TRAC:FEED SENSE;:TRAC:FEED:CONT NEXT;")
self.check_errors()
def is_buffer_full(self):
""" Returns True if the buffer is full of measurements. """
status_byte = int(self.ask("*STB?"))
return (status_byte & 65) == 65
def wait_for_buffer(self, should_stop=lambda: False,
timeout=60, interval=0.1):
""" Blocks the program, waiting for a full buffer. This function
returns early if the :code:`should_stop` function returns True or
the timeout is reached before the buffer is full.
:param should_stop: A function that returns True when this function should return early
:param timeout: A time in seconds after which this function should return early
:param interval: A time in seconds for how often to check if the buffer is full
"""
# TODO: Use SRQ initially instead of constant polling
# self.adapter.wait_for_srq()
t = time()
while not self.is_buffer_full():
sleep(interval)
if should_stop():
return
if (time() - t) > timeout:
raise Exception("Timed out waiting for Keithley buffer to fill.")
@property
def buffer_data(self):
""" Get a numpy array of values from the buffer. """
self.write(":FORM:DATA ASCII")
return np.array(self.values(":TRAC:DATA?"), dtype=np.float64)
def start_buffer(self):
""" Starts the buffer. """
self.write(":INIT")
def reset_buffer(self):
""" Resets the buffer. """
self.write(":STAT:PRES;*CLS;:TRAC:CLEAR;:TRAC:FEED:CONT NEXT;")
def stop_buffer(self):
""" Aborts the buffering measurement, by stopping the measurement
arming and triggering sequence. If possible, a Selected Device
Clear (SDC) is used. """
if type(self.adapter) is PrologixAdapter:
self.write("++clr")
else:
self.write(":ABOR")
def disable_buffer(self):
""" Disables the connection between measurements and the
buffer, but does not abort the measurement process.
"""
self.write(":TRAC:FEED:CONT NEV")
|