From c6fbe1a6f87f9eccb43ac7e9c95e85f18ddd6177 Mon Sep 17 00:00:00 2001
From: Pieter
Date: Thu, 7 Apr 2016 14:35:36 +0200
Subject: [PATCH 1/8] added keithley driver
---
docs/examples/Keithley_example.ipynb | 470 ++++++++++++++++++
.../instrument_drivers/tektronix/Keithley.py | 338 +++++++++++++
2 files changed, 808 insertions(+)
create mode 100644 docs/examples/Keithley_example.ipynb
create mode 100644 qcodes/instrument_drivers/tektronix/Keithley.py
diff --git a/docs/examples/Keithley_example.ipynb b/docs/examples/Keithley_example.ipynb
new file mode 100644
index 000000000000..3848a6854e6f
--- /dev/null
+++ b/docs/examples/Keithley_example.ipynb
@@ -0,0 +1,470 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Example script for Keithley driver"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/*\r\n",
+ " * Qcodes Jupyter/IPython widgets\r\n",
+ " */\r\n",
+ "require([\r\n",
+ " 'nbextensions/widgets/widgets/js/widget',\r\n",
+ " 'nbextensions/widgets/widgets/js/manager'\r\n",
+ "], function (widget, manager) {\r\n",
+ "\r\n",
+ " var UpdateView = widget.DOMWidgetView.extend({\r\n",
+ " render: function() {\r\n",
+ " window.MYWIDGET = this;\r\n",
+ " this._interval = 0;\r\n",
+ " this.update();\r\n",
+ " },\r\n",
+ " update: function() {\r\n",
+ " this.display(this.model.get('_message'));\r\n",
+ " this.setInterval();\r\n",
+ " },\r\n",
+ " display: function(message) {\r\n",
+ " /*\r\n",
+ " * display method: override this for custom display logic\r\n",
+ " */\r\n",
+ " this.el.innerHTML = message;\r\n",
+ " },\r\n",
+ " remove: function() {\r\n",
+ " clearInterval(this._updater);\r\n",
+ " },\r\n",
+ " setInterval: function(newInterval) {\r\n",
+ " var me = this;\r\n",
+ " if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+ " if(newInterval===me._interval) return;\r\n",
+ "\r\n",
+ " me._interval = newInterval;\r\n",
+ "\r\n",
+ " if(me._updater) clearInterval(me._updater);\r\n",
+ "\r\n",
+ " if(me._interval) {\r\n",
+ " me._updater = setInterval(function() {\r\n",
+ " me.send({myupdate: true});\r\n",
+ " if(!me.model.comm_live) {\r\n",
+ " console.log('missing comm, canceling widget updates', me);\r\n",
+ " clearInterval(me._updater);\r\n",
+ " }\r\n",
+ " }, me._interval * 1000);\r\n",
+ " }\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+ "\r\n",
+ " var HiddenUpdateView = UpdateView.extend({\r\n",
+ " display: function(message) {\r\n",
+ " this.$el.hide();\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+ "\r\n",
+ " var SubprocessView = UpdateView.extend({\r\n",
+ " render: function() {\r\n",
+ " var me = window.SPVIEW = this;\r\n",
+ " me._interval = 0;\r\n",
+ " me._minimize = '';\r\n",
+ " me._restore = '';\r\n",
+ "\r\n",
+ " // in case there is already an outputView present,\r\n",
+ " // like from before restarting the kernel\r\n",
+ " $('.qcodes-output-view').not(me.$el).remove();\r\n",
+ "\r\n",
+ " me.$el\r\n",
+ " .addClass('qcodes-output-view')\r\n",
+ " .attr('qcodes-state', 'docked')\r\n",
+ " .html(\r\n",
+ " '' +\r\n",
+ " ''\r\n",
+ " );\r\n",
+ "\r\n",
+ " me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+ " me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+ " me.outputArea = me.$el.find('pre');\r\n",
+ " me.subprocessList = me.$el.find('span');\r\n",
+ " me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+ "\r\n",
+ " me.clearButton.click(function() {\r\n",
+ " me.outputArea.html('');\r\n",
+ " me.clearButton.addClass('disabled');\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.abortButton.click(function() {\r\n",
+ " me.send({abort: true});\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.$el.find('.js-state').click(function() {\r\n",
+ " var oldState = me.$el.attr('qcodes-state'),\r\n",
+ " state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+ " .split('-')[1].split(' ')[0];\r\n",
+ "\r\n",
+ " // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+ " // some other bit of code resets the parent after render if I do it there.\r\n",
+ " // To be safe, just do it on every state click.\r\n",
+ " me.$el.appendTo('body');\r\n",
+ "\r\n",
+ " if(oldState === 'floated') {\r\n",
+ " me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+ " }\r\n",
+ "\r\n",
+ " me.$el.attr('qcodes-state', state);\r\n",
+ "\r\n",
+ " if(state === 'floated') {\r\n",
+ " me.$el.draggable().css({\r\n",
+ " left: window.innerWidth - me.$el.width() - 15,\r\n",
+ " top: window.innerHeight - me.$el.height() - 10\r\n",
+ " });\r\n",
+ " }\r\n",
+ " });\r\n",
+ "\r\n",
+ " $(window).resize(function() {\r\n",
+ " if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+ " var position = me.$el.position(),\r\n",
+ " minVis = 20,\r\n",
+ " maxLeft = window.innerWidth - minVis,\r\n",
+ " maxTop = window.innerHeight - minVis;\r\n",
+ "\r\n",
+ " if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+ " if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+ " }\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.update();\r\n",
+ " },\r\n",
+ "\r\n",
+ " display: function(message) {\r\n",
+ " if(message) {\r\n",
+ " var initialScroll = this.outputArea.scrollTop();\r\n",
+ " this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+ " var scrollBottom = this.outputArea.scrollTop();\r\n",
+ "\r\n",
+ " if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+ " this.$el.find('.qcodes-docked').click();\r\n",
+ " // always scroll to the bottom if we're restoring\r\n",
+ " // because of a new message\r\n",
+ " initialScroll = scrollBottom;\r\n",
+ " }\r\n",
+ "\r\n",
+ " this.outputArea.append(message);\r\n",
+ " this.clearButton.removeClass('disabled');\r\n",
+ "\r\n",
+ " // if we were scrolled to the bottom initially, make sure\r\n",
+ " // we stay that way.\r\n",
+ " this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+ " this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+ " }\r\n",
+ "\r\n",
+ " var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+ " this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+ " this.subprocessList.text(processes);\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+ "});\r\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "import time\n",
+ "import numpy as np\n",
+ "from imp import reload\n",
+ "\n",
+ "import qcodes as qc\n",
+ "\n",
+ "qc.set_mp_method('spawn') # force Windows behavior on mac\n",
+ "\n",
+ "# this makes a widget in the corner of the window to show and control\n",
+ "# subprocesses and any output they would print to the terminal\n",
+ "qc.show_subprocess_widget()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Keithley driver\n",
+ "\n",
+ "What to do:\n",
+ " \n",
+ "* implement add functionality of the driver\n",
+ "* add documentation to the functions\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['IntsValidator',\n",
+ " 'Keithley_2700',\n",
+ " 'NumbersValidator',\n",
+ " 'StringValidator',\n",
+ " 'VisaInstrument',\n",
+ " '__builtins__',\n",
+ " '__cached__',\n",
+ " '__doc__',\n",
+ " '__file__',\n",
+ " '__loader__',\n",
+ " '__name__',\n",
+ " '__package__',\n",
+ " '__spec__',\n",
+ " 'bool_to_str',\n",
+ " 'dummy',\n",
+ " 'logging',\n",
+ " 'pi',\n",
+ " 'time',\n",
+ " 'validators']"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import qcodes.instrument_drivers\n",
+ "import qcodes.instrument_drivers.tektronix.Keithley as keith; reload(keith)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.21s\n"
+ ]
+ }
+ ],
+ "source": [
+ "k1 = keith.Keithley_2700('Keithley', 'GPIB1::15::INSTR')\n",
+ "k1.add_parameter('READ', get_cmd='READ?', label='Keithley value', get_parser=float)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "current mode: VOLT:DC\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('current mode: %s' % k1.get('mode'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "measure: -0.762987\n",
+ "measure: -0.777320\n",
+ "measure: -0.783848\n",
+ "measure: -0.790359\n",
+ "measure: -0.796843\n",
+ "measure: -0.803321\n"
+ ]
+ }
+ ],
+ "source": [
+ "for i in range(6):\n",
+ " print('measure: %.6f' % k1.readnext() )"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[]"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "station = qc.Station('Keithley')\n",
+ "\n",
+ "# could measure any number of things by adding arguments to this\n",
+ "# function call, but here we're just measuring one, the meter mode\n",
+ "station.set_measurement(k1.mode)\n",
+ "\n",
+ "qc.active_children()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['VOLT:DC']"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "station.measure()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.5.1"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/qcodes/instrument_drivers/tektronix/Keithley.py b/qcodes/instrument_drivers/tektronix/Keithley.py
new file mode 100644
index 000000000000..4bedf38d00b0
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/Keithley.py
@@ -0,0 +1,338 @@
+# Keithley_2700.py driver for Keithley 2700 DMM
+#
+# Pieter Eendebak , 2016 (adapt to Qcodes framework)
+# Pieter de Groot , 2008
+# Martijn Schaafsma , 2008
+# Reinier Heeres , 2008
+#
+# Update december 2009:
+# Michiel Jol
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import time
+from numpy import pi
+from qcodes.instrument.visa import VisaInstrument
+#from qcodes.utils import validators
+from qcodes.utils.validators import Strings as StringValidator
+from qcodes.utils.validators import Ints as IntsValidator
+from qcodes.utils.validators import Numbers as NumbersValidator
+
+import logging
+
+#%% Helper functions
+
+def bool_to_str(val):
+ '''
+ Function to convert boolean to 'ON' or 'OFF'
+ '''
+ if val == True:
+ return "ON"
+ else:
+ return "OFF"
+
+
+
+#%% Driver for Keithley_2700
+
+
+class Keithley_2700(VisaInstrument):
+ '''
+ This is the qcodes driver for the Keithley_2700 Multimeter
+
+ Usage: Initialize with
+ = = Keithley_2700(, address='', reset=,
+ change_display=, change_autozero=)
+
+ Status: beta-version.
+
+ This driver will most likely work for multiple Keithley SourceMeters.
+
+ This driver does not contain all commands available, but only the ones most commonly used.
+ '''
+ def __init__(self, name, address, reset=False):
+ t0 = time.time()
+ super().__init__(name, address)
+
+ self._modes = ['']
+ self.add_parameter('IDN', get_cmd='*IDN?')
+
+ self._modes = ['VOLT:AC', 'VOLT:DC', 'CURR:AC', 'CURR:DC', 'RES',
+ 'FRES', 'TEMP', 'FREQ']
+ #self._change_display = change_display
+ #self._change_autozero = change_autozero
+ self._averaging_types = ['MOV','REP']
+ self._trigger_sent = False
+
+ # Add parameters to wrapper
+ self.add_parameter('mode', get_cmd=':CONF?', get_parser=lambda x: x.strip().strip('"'), set_cmd=':CONF:{}', vals=StringValidator() )
+
+ self.add_parameter('trigger_count', get_cmd=self._mode_par('INIT', 'CONT'), get_parser=int, set_cmd=self._mode_par_value('INIT','CONT','{}'), vals=IntsValidator(), units='#' )
+ self.add_parameter('trigger_delay', get_cmd=self._mode_par('TRIG', 'DEL'), get_parser=float, set_cmd=self._mode_par_value('TRIG', 'DEL', '{}'), vals=NumbersValidator(min_value=0, max_value=999999.999), units='s')
+
+ self.add_parameter('trigger_continuous', get_cmd=self._mode_par('INIT', 'CONT'), get_parser=bool, set_cmd=self._mode_par_value('INIT', 'CONT', '{}'), set_parser=bool_to_str )
+
+ self.add_parameter('averaging', get_cmd=lambda: self._current_mode_get( 'AVER:STAT'), get_parser=bool, set_cmd=lambda val: self._current_mode_set('AVER:STAT', val), set_parser=bool_to_str )
+
+ self.add_parameter('digits', get_cmd=lambda: self._current_mode_get('DIG'), get_parser=int, set_cmd=lambda val: self._current_mode_set('DIG', val) )
+
+ self.add_parameter('nplc', get_cmd=lambda: self._current_mode_get('NPLC'), get_parser=int, set_cmd=lambda val: self._current_mode_set('NPLC', val), units='APER' )
+ self.add_parameter('range', get_cmd=lambda: self._current_mode_get('RANG'), get_parser=int, set_cmd=lambda val: self._current_mode_set('RANG', val), units='RANG' )
+
+
+ '''
+ self.add_parameter('range',
+ flags=Instrument.FLAG_GETSET,
+ units='', minval=0.1, maxval=1000, type=float)
+ self.add_parameter('trigger_source',
+ flags=Instrument.FLAG_GETSET,
+ units='')
+ self.add_parameter('trigger_timer',
+ flags=Instrument.FLAG_GETSET,
+ units='s', minval=0.001, maxval=99999.999, type=float)
+ self.add_parameter('digits',
+ flags=Instrument.FLAG_GETSET,
+ units='#', minval=4, maxval=7, type=int)
+ self.add_parameter('readval', flags=Instrument.FLAG_GET,
+ units='AU',
+ type=float,
+ tags=['measure'])
+ self.add_parameter('readlastval', flags=Instrument.FLAG_GET,
+ units='AU',
+ type=float,
+ tags=['measure'])
+ self.add_parameter('readnextval', flags=Instrument.FLAG_GET,
+ units='AU',
+ type=float,
+ tags=['measure'])
+ self.add_parameter('integrationtime',
+ flags=Instrument.FLAG_GETSET,
+ units='s', type=float, minval=2e-4, maxval=1)
+ self.add_parameter('nplc',
+ flags=Instrument.FLAG_GETSET,
+ units='#', type=float, minval=0.01, maxval=50)
+ self.add_parameter('display', flags=Instrument.FLAG_GETSET,
+ type=bool)
+ self.add_parameter('autozero', flags=Instrument.FLAG_GETSET,
+ type=bool)
+ self.add_parameter('averaging_window',
+ flags=Instrument.FLAG_GETSET,
+ units='%', type=float, minval=0, maxval=10)
+ self.add_parameter('averaging_count',
+ flags=Instrument.FLAG_GETSET,
+ units='#', type=int, minval=1, maxval=100)
+ self.add_parameter('averaging_type',
+ flags=Instrument.FLAG_GETSET,
+ type=bytes, units='')
+ self.add_parameter('autorange',
+ flags=Instrument.FLAG_GETSET,
+ units='',
+ type=bool)
+'''
+
+
+ # add functions
+ self.add_function('readnext', units='AU', call_cmd=':DATA:FRESH?', return_parser=float)
+
+ if reset:
+ self.reset()
+ else:
+ self.get_all()
+ self.set_defaults()
+
+ t1 = time.time()
+ print('Connected to: ',
+ self.get('IDN').replace(',', ', ').replace('\n', ' '),
+ 'in %.2fs' % (t1-t0))
+
+
+ def get_all(self):
+ '''
+ Reads all relevant parameters from instrument
+
+ Input:
+ None
+
+ Output:
+ None
+ '''
+ logging.info('Get all relevant data from device')
+
+ for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging', 'digits', 'nplc']:
+ logging.debug('get %s' % p)
+ par=getattr(self,p)
+ par.get()
+
+# self.get_range()
+ # self.get_trigger_delay()
+ # self.get_trigger_source()
+ # self.get_trigger_timer()
+ # self.get_integrationtime()
+ # self.get_display()
+ # self.get_autozero()
+ #self.get_averaging_window()
+ #self.get_averaging_count()
+ #self.get_averaging_type()
+ #self.get_autorange()
+
+ def _current_mode_get(self, par, mode=None):
+ cmd=self._mode_par(mode, par)
+ return self.ask(cmd)
+
+ def _current_mode_set(self, par, val, mode=None):
+ cmd=self._mode_par_value(mode, par, val)
+ return self.write(cmd)
+
+
+# --------------------------------------
+# functions
+# --------------------------------------
+
+ def set_mode_volt_dc(self):
+ '''
+ Set mode to DC Voltage
+
+ Input:
+ None
+
+ Output:
+ None
+ '''
+ logging.debug('Set mode to DC Voltage')
+ self.mode.set('VOLT:DC')
+
+ def set_defaults(self):
+ '''
+ Set to driver defaults:
+ Output=data only
+ Mode=Volt:DC
+ Digits=7
+ Trigger=Continous
+ Range=10 V
+ NPLC=1
+ Averaging=off
+ '''
+
+ self.write('SYST:PRES')
+ self.write(':FORM:ELEM READ')
+ # Sets the format to only the read out, all options are:
+ # READing = DMM reading, UNITs = Units,
+ # TSTamp = Timestamp, RNUMber = Reading number,
+ # CHANnel = Channel number, LIMits = Limits reading
+
+ self.set_mode_volt_dc()
+ self.digits.set(7)
+ self.trigger_continuous.set(True)
+ self.range.set(10)
+ self.nplc.set(1)
+ self.averaging.set(False)
+ return
+
+ def _determine_mode(self, mode):
+ '''
+ Return the mode string to use.
+ If mode is None it will return the currently selected mode.
+ '''
+ logging.debug('Determine mode with mode=%s' % mode)
+ if mode is None:
+ mode = self.mode.get_latest() # _mode(query=False)
+ if mode not in self._modes and mode not in ('INIT', 'TRIG', 'SYST', 'DISP'):
+ logging.warning('Invalid mode %s, assuming current' % mode)
+ mode = self.mode.get_latest()
+ return mode
+
+ def set_mode(self, mode):
+ '''
+ Set the mode to the specified value
+
+ Input:
+ mode (string) : mode to be set. Choose from self._modes
+
+ Output:
+ None
+ '''
+
+ logging.debug('Set mode to %s', mode)
+ if mode in self._modes:
+ string = ':CONF:%s' % mode
+ self._visainstrument.write(string)
+
+ if mode.startswith('VOLT'):
+ self._change_units('V')
+ elif mode.startswith('CURR'):
+ self._change_units('A')
+ elif mode.startswith('RES'):
+ self._change_units('Ohm')
+ elif mode.startswith('FREQ'):
+ self._change_units('Hz')
+
+ else:
+ logging.error('invalid mode %s' % mode)
+
+ self.get_all()
+ # Get all values again because some parameters depend on mode
+
+ def _mode_par_value(self, mode, par, val):
+ '''
+ For internal use only!!
+ Create command string based on current mode
+
+ Input:
+ mode (string) : The mode to use
+ par (string) : Parameter
+ val (depends) : Value
+
+ Output:
+ None
+ '''
+ mode = self._determine_mode(mode)
+ string = ':%s:%s %s' % (mode, par, val)
+ return string
+ def _mode_par(self, mode, par):
+ '''
+ For internal use only!!
+ Create command string based on current mode
+
+ Input:
+ mode (string) : The mode to use
+ par (string) : Parameter
+ val (depends) : Value
+
+ Output:
+ None
+ '''
+ mode = self._determine_mode(mode)
+ string = ':%s:%s?' % (mode, par, )
+ return string
+
+ def reset(self):
+ '''
+ Resets instrument to default values
+
+ Input:
+ None
+
+ Output:
+ None
+ '''
+ logging.debug('Resetting instrument')
+ self._visainstrument.write('*RST')
+ self.get_all()
+
+ # def on(self):
+ # self.set('status', 'on')
+
+ # def off(self):
+ # self.set('status', 'off')
From 0207d295b3a24c936f312126fe44458f3c6a99df Mon Sep 17 00:00:00 2001
From: Pieter
Date: Fri, 8 Apr 2016 09:34:59 +0200
Subject: [PATCH 2/8] added docstrings to parameters
---
docs/examples/Keithley_example.ipynb | 305 ++----------------
qcodes/instrument/function.py | 5 +-
qcodes/instrument/parameter.py | 6 +-
.../instrument_drivers/tektronix/Keithley.py | 3 +-
4 files changed, 45 insertions(+), 274 deletions(-)
diff --git a/docs/examples/Keithley_example.ipynb b/docs/examples/Keithley_example.ipynb
index 3848a6854e6f..e36dbec5286e 100644
--- a/docs/examples/Keithley_example.ipynb
+++ b/docs/examples/Keithley_example.ipynb
@@ -9,249 +9,11 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 15,
"metadata": {
"collapsed": false
},
- "outputs": [
- {
- "data": {
- "application/javascript": [
- "/*\r\n",
- " * Qcodes Jupyter/IPython widgets\r\n",
- " */\r\n",
- "require([\r\n",
- " 'nbextensions/widgets/widgets/js/widget',\r\n",
- " 'nbextensions/widgets/widgets/js/manager'\r\n",
- "], function (widget, manager) {\r\n",
- "\r\n",
- " var UpdateView = widget.DOMWidgetView.extend({\r\n",
- " render: function() {\r\n",
- " window.MYWIDGET = this;\r\n",
- " this._interval = 0;\r\n",
- " this.update();\r\n",
- " },\r\n",
- " update: function() {\r\n",
- " this.display(this.model.get('_message'));\r\n",
- " this.setInterval();\r\n",
- " },\r\n",
- " display: function(message) {\r\n",
- " /*\r\n",
- " * display method: override this for custom display logic\r\n",
- " */\r\n",
- " this.el.innerHTML = message;\r\n",
- " },\r\n",
- " remove: function() {\r\n",
- " clearInterval(this._updater);\r\n",
- " },\r\n",
- " setInterval: function(newInterval) {\r\n",
- " var me = this;\r\n",
- " if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
- " if(newInterval===me._interval) return;\r\n",
- "\r\n",
- " me._interval = newInterval;\r\n",
- "\r\n",
- " if(me._updater) clearInterval(me._updater);\r\n",
- "\r\n",
- " if(me._interval) {\r\n",
- " me._updater = setInterval(function() {\r\n",
- " me.send({myupdate: true});\r\n",
- " if(!me.model.comm_live) {\r\n",
- " console.log('missing comm, canceling widget updates', me);\r\n",
- " clearInterval(me._updater);\r\n",
- " }\r\n",
- " }, me._interval * 1000);\r\n",
- " }\r\n",
- " }\r\n",
- " });\r\n",
- " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
- "\r\n",
- " var HiddenUpdateView = UpdateView.extend({\r\n",
- " display: function(message) {\r\n",
- " this.$el.hide();\r\n",
- " }\r\n",
- " });\r\n",
- " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
- "\r\n",
- " var SubprocessView = UpdateView.extend({\r\n",
- " render: function() {\r\n",
- " var me = window.SPVIEW = this;\r\n",
- " me._interval = 0;\r\n",
- " me._minimize = '';\r\n",
- " me._restore = '';\r\n",
- "\r\n",
- " // in case there is already an outputView present,\r\n",
- " // like from before restarting the kernel\r\n",
- " $('.qcodes-output-view').not(me.$el).remove();\r\n",
- "\r\n",
- " me.$el\r\n",
- " .addClass('qcodes-output-view')\r\n",
- " .attr('qcodes-state', 'docked')\r\n",
- " .html(\r\n",
- " '' +\r\n",
- " ''\r\n",
- " );\r\n",
- "\r\n",
- " me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
- " me.minButton = me.$el.find('.qcodes-minimize');\r\n",
- " me.outputArea = me.$el.find('pre');\r\n",
- " me.subprocessList = me.$el.find('span');\r\n",
- " me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
- "\r\n",
- " me.clearButton.click(function() {\r\n",
- " me.outputArea.html('');\r\n",
- " me.clearButton.addClass('disabled');\r\n",
- " });\r\n",
- "\r\n",
- " me.abortButton.click(function() {\r\n",
- " me.send({abort: true});\r\n",
- " });\r\n",
- "\r\n",
- " me.$el.find('.js-state').click(function() {\r\n",
- " var oldState = me.$el.attr('qcodes-state'),\r\n",
- " state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
- " .split('-')[1].split(' ')[0];\r\n",
- "\r\n",
- " // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
- " // some other bit of code resets the parent after render if I do it there.\r\n",
- " // To be safe, just do it on every state click.\r\n",
- " me.$el.appendTo('body');\r\n",
- "\r\n",
- " if(oldState === 'floated') {\r\n",
- " me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
- " }\r\n",
- "\r\n",
- " me.$el.attr('qcodes-state', state);\r\n",
- "\r\n",
- " if(state === 'floated') {\r\n",
- " me.$el.draggable().css({\r\n",
- " left: window.innerWidth - me.$el.width() - 15,\r\n",
- " top: window.innerHeight - me.$el.height() - 10\r\n",
- " });\r\n",
- " }\r\n",
- " });\r\n",
- "\r\n",
- " $(window).resize(function() {\r\n",
- " if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
- " var position = me.$el.position(),\r\n",
- " minVis = 20,\r\n",
- " maxLeft = window.innerWidth - minVis,\r\n",
- " maxTop = window.innerHeight - minVis;\r\n",
- "\r\n",
- " if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
- " if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
- " }\r\n",
- " });\r\n",
- "\r\n",
- " me.update();\r\n",
- " },\r\n",
- "\r\n",
- " display: function(message) {\r\n",
- " if(message) {\r\n",
- " var initialScroll = this.outputArea.scrollTop();\r\n",
- " this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
- " var scrollBottom = this.outputArea.scrollTop();\r\n",
- "\r\n",
- " if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
- " this.$el.find('.qcodes-docked').click();\r\n",
- " // always scroll to the bottom if we're restoring\r\n",
- " // because of a new message\r\n",
- " initialScroll = scrollBottom;\r\n",
- " }\r\n",
- "\r\n",
- " this.outputArea.append(message);\r\n",
- " this.clearButton.removeClass('disabled');\r\n",
- "\r\n",
- " // if we were scrolled to the bottom initially, make sure\r\n",
- " // we stay that way.\r\n",
- " this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
- " this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
- " }\r\n",
- "\r\n",
- " var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
- " this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
- " this.subprocessList.text(processes);\r\n",
- " }\r\n",
- " });\r\n",
- " manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
- "});\r\n"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import time\n",
@@ -282,7 +44,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 16,
"metadata": {
"collapsed": false
},
@@ -290,28 +52,10 @@
{
"data": {
"text/plain": [
- "['IntsValidator',\n",
- " 'Keithley_2700',\n",
- " 'NumbersValidator',\n",
- " 'StringValidator',\n",
- " 'VisaInstrument',\n",
- " '__builtins__',\n",
- " '__cached__',\n",
- " '__doc__',\n",
- " '__file__',\n",
- " '__loader__',\n",
- " '__name__',\n",
- " '__package__',\n",
- " '__spec__',\n",
- " 'bool_to_str',\n",
- " 'dummy',\n",
- " 'logging',\n",
- " 'pi',\n",
- " 'time',\n",
- " 'validators']"
+ ""
]
},
- "execution_count": 7,
+ "execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
@@ -323,7 +67,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 17,
"metadata": {
"collapsed": false
},
@@ -332,7 +76,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.21s\n"
+ "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.14s\n"
]
}
],
@@ -343,7 +87,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 18,
"metadata": {
"collapsed": false
},
@@ -362,7 +106,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 19,
"metadata": {
"collapsed": false,
"scrolled": true
@@ -372,12 +116,12 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "measure: -0.762987\n",
- "measure: -0.777320\n",
- "measure: -0.783848\n",
- "measure: -0.790359\n",
- "measure: -0.796843\n",
- "measure: -0.803321\n"
+ "measure: -1.044276\n",
+ "measure: -1.050299\n",
+ "measure: -1.056594\n",
+ "measure: -1.069865\n",
+ "measure: -1.075954\n",
+ "measure: -1.081997\n"
]
}
],
@@ -436,6 +180,25 @@
"station.measure()"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sds\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(k1.nplc.__doc__)"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
diff --git a/qcodes/instrument/function.py b/qcodes/instrument/function.py
index 0ef731224729..3094f3dd477f 100644
--- a/qcodes/instrument/function.py
+++ b/qcodes/instrument/function.py
@@ -50,12 +50,15 @@ class Function(Metadatable):
def __init__(self, name, instrument=None,
call_cmd=None, async_call_cmd=None,
args=[], arg_parser=None, return_parser=None,
- **kwargs):
+ docstring=None, **kwargs):
super().__init__(**kwargs)
self._instrument = instrument
self.name = name
+ if docstring is not None:
+ self.__doc__=docstring
+
self._set_args(args)
self._set_call(call_cmd, async_call_cmd,
arg_parser, return_parser)
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index a06b37eb58df..fa0ae832e326 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -134,7 +134,7 @@ def __init__(self,
units=None,
size=None, sizes=None,
setpoints=None, setpoint_names=None, setpoint_labels=None,
- vals=None, **kwargs):
+ vals=None, docstring=None, **kwargs):
super().__init__(**kwargs)
if names is not None:
@@ -167,6 +167,10 @@ def __init__(self,
self.setpoint_names = setpoint_names
self.setpoint_labels = setpoint_labels
+ if docstring is not None:
+ #logging.debug('add docstring to Parameter!')
+ self.__doc__ = docstring
+
# record of latest value and when it was set or measured
# what exactly this means is different for different subclasses
# but they all use the same attributes so snapshot is consistent.
diff --git a/qcodes/instrument_drivers/tektronix/Keithley.py b/qcodes/instrument_drivers/tektronix/Keithley.py
index 4bedf38d00b0..6ccbe4c4d44c 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley.py
@@ -88,7 +88,8 @@ def __init__(self, name, address, reset=False):
self.add_parameter('digits', get_cmd=lambda: self._current_mode_get('DIG'), get_parser=int, set_cmd=lambda val: self._current_mode_set('DIG', val) )
- self.add_parameter('nplc', get_cmd=lambda: self._current_mode_get('NPLC'), get_parser=int, set_cmd=lambda val: self._current_mode_set('NPLC', val), units='APER' )
+ self.add_parameter('nplc', get_cmd=lambda: self._current_mode_get('NPLC'), get_parser=int, set_cmd=lambda val: self._current_mode_set('NPLC', val), units='APER', docstring='Get integration time in Number of PowerLine Cycles. \
+ To get the integrationtime in seconds, use get_integrationtime().' )
self.add_parameter('range', get_cmd=lambda: self._current_mode_get('RANG'), get_parser=int, set_cmd=lambda val: self._current_mode_set('RANG', val), units='RANG' )
From d3335270b4decbc2bf18797752e2cbcb2e9d768c Mon Sep 17 00:00:00 2001
From: Pieter
Date: Fri, 8 Apr 2016 17:50:17 +0200
Subject: [PATCH 3/8] improve Keithley driver with comments from PR #69
---
qcodes/instrument/function.py | 2 +
qcodes/instrument/parameter.py | 4 +
.../instrument_drivers/tektronix/Keithley.py | 73 +++++++++++++------
3 files changed, 56 insertions(+), 23 deletions(-)
diff --git a/qcodes/instrument/function.py b/qcodes/instrument/function.py
index 3094f3dd477f..ca1b1fa67c77 100644
--- a/qcodes/instrument/function.py
+++ b/qcodes/instrument/function.py
@@ -46,6 +46,8 @@ class Function(Metadatable):
If None (default), will not wait for or read any response
NOTE: parsers only apply if call_cmd is a string. The function forms
of call_cmd and async_call_cmd should do their own parsing.
+ docstring: documentation string for the __doc__ field of the object
+ The __doc__ field of the instance is used by some help systems, but not all
'''
def __init__(self, name, instrument=None,
call_cmd=None, async_call_cmd=None,
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index fa0ae832e326..da76b5ebfd45 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -273,6 +273,8 @@ class StandardParameter(Parameter):
sweep_delay: time (in seconds) to wait after each sweep step
max_val_age: max time (in seconds) to trust a saved value from
this parameter as the starting point of a sweep
+ docstring: documentation string for the __doc__ field of the object
+ The __doc__ field of the instance is used by some help systems, but not all
'''
def __init__(self, name, instrument=None,
get_cmd=None, async_get_cmd=None, get_parser=None,
@@ -293,6 +295,8 @@ def __init__(self, name, instrument=None,
self._set_mapping = val_mapping
set_parser = self._set_mapping.__getitem__
+ if get_parser is not None and not isinstance(get_cmd, str):
+ logging.warning('get_parser is set, but will not be used')
super().__init__(name=name, vals=vals, **kwargs)
self._instrument = instrument
diff --git a/qcodes/instrument_drivers/tektronix/Keithley.py b/qcodes/instrument_drivers/tektronix/Keithley.py
index 6ccbe4c4d44c..47c3345650ed 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley.py
@@ -47,7 +47,21 @@ def bool_to_str(val):
#%% Driver for Keithley_2700
+from functools import partial
+def parseint(v):
+ logging.debug('parseint: %s -> %d' % (v, int(v)))
+ return int(v)
+
+def parsebool(v):
+ r=bool(int(v))
+ logging.debug('parsetobool: %s -> %d' % (v, r))
+ return r
+
+def parsestr(v):
+ return v.strip().strip('"')
+
+
class Keithley_2700(VisaInstrument):
'''
This is the qcodes driver for the Keithley_2700 Multimeter
@@ -77,22 +91,38 @@ def __init__(self, name, address, reset=False):
self._trigger_sent = False
# Add parameters to wrapper
- self.add_parameter('mode', get_cmd=':CONF?', get_parser=lambda x: x.strip().strip('"'), set_cmd=':CONF:{}', vals=StringValidator() )
+ self.add_parameter('mode', get_cmd=':CONF?', get_parser=parsestr, set_cmd=':CONF:{}', vals=StringValidator() )
- self.add_parameter('trigger_count', get_cmd=self._mode_par('INIT', 'CONT'), get_parser=int, set_cmd=self._mode_par_value('INIT','CONT','{}'), vals=IntsValidator(), units='#' )
- self.add_parameter('trigger_delay', get_cmd=self._mode_par('TRIG', 'DEL'), get_parser=float, set_cmd=self._mode_par_value('TRIG', 'DEL', '{}'), vals=NumbersValidator(min_value=0, max_value=999999.999), units='s')
+ self.add_parameter('trigger_count', get_cmd=self._mode_par('INIT', 'CONT'),
+ get_parser=int, set_cmd=self._mode_par_value('INIT','CONT','{}'),
+ vals=IntsValidator(), units='#' )
+ self.add_parameter('trigger_delay', get_cmd=self._mode_par('TRIG', 'DEL'),
+ get_parser=float, set_cmd=self._mode_par_value('TRIG', 'DEL', '{}'),
+ vals=NumbersValidator(min_value=0, max_value=999999.999), units='s')
- self.add_parameter('trigger_continuous', get_cmd=self._mode_par('INIT', 'CONT'), get_parser=bool, set_cmd=self._mode_par_value('INIT', 'CONT', '{}'), set_parser=bool_to_str )
+ self.add_parameter('trigger_continuous', get_cmd=self._mode_par('INIT', 'CONT'),
+ get_parser=parsebool, set_cmd=self._mode_par_value('INIT', 'CONT', '{}'), set_parser=bool_to_str )
- self.add_parameter('averaging', get_cmd=lambda: self._current_mode_get( 'AVER:STAT'), get_parser=bool, set_cmd=lambda val: self._current_mode_set('AVER:STAT', val), set_parser=bool_to_str )
+ self.add_parameter('averaging', get_cmd=partial(self._current_mode_get, 'AVER:STAT', parser=parsebool),
+ set_cmd=partial(self._current_mode_set, par='AVER:STAT'),
+ set_parser=bool_to_str )
- self.add_parameter('digits', get_cmd=lambda: self._current_mode_get('DIG'), get_parser=int, set_cmd=lambda val: self._current_mode_set('DIG', val) )
+ self.add_parameter('digits', get_cmd=partial(self._current_mode_get, 'DIG', parser=int),
+ set_cmd=partial(self._current_mode_set, par='DIG') )
- self.add_parameter('nplc', get_cmd=lambda: self._current_mode_get('NPLC'), get_parser=int, set_cmd=lambda val: self._current_mode_set('NPLC', val), units='APER', docstring='Get integration time in Number of PowerLine Cycles. \
+ self.add_parameter('nplc', get_cmd=partial( self._current_mode_get, 'NPLC', parser=float),
+ set_cmd=partial(self._current_mode_set, par='NPLC', mode=None), units='APER',
+ docstring='Get integration time in Number of PowerLine Cycles. \
To get the integrationtime in seconds, use get_integrationtime().' )
- self.add_parameter('range', get_cmd=lambda: self._current_mode_get('RANG'), get_parser=int, set_cmd=lambda val: self._current_mode_set('RANG', val), units='RANG' )
-
+ self.add_parameter('range', get_cmd=partial(self._current_mode_get, 'RANG',parser=float),
+ set_cmd=partial(self._current_mode_set, par='RANG'), units='RANG' )
+
+ self.add_parameter('integrationtime', get_cmd=partial(self._current_mode_get, 'APER', parser=float),
+ set_cmd=partial(self._current_mode_set, par='APER', mode=None), units='s',
+ vals=NumbersValidator(min_value=2e-4, max_value=1.),
+ docstring='Get integration time in seconds. To get the integrationtime as a Number of PowerLine Cycles, use get_nplc().' )
+
'''
self.add_parameter('range',
flags=Instrument.FLAG_GETSET,
@@ -103,9 +133,6 @@ def __init__(self, name, address, reset=False):
self.add_parameter('trigger_timer',
flags=Instrument.FLAG_GETSET,
units='s', minval=0.001, maxval=99999.999, type=float)
- self.add_parameter('digits',
- flags=Instrument.FLAG_GETSET,
- units='#', minval=4, maxval=7, type=int)
self.add_parameter('readval', flags=Instrument.FLAG_GET,
units='AU',
type=float,
@@ -118,9 +145,6 @@ def __init__(self, name, address, reset=False):
units='AU',
type=float,
tags=['measure'])
- self.add_parameter('integrationtime',
- flags=Instrument.FLAG_GETSET,
- units='s', type=float, minval=2e-4, maxval=1)
self.add_parameter('nplc',
flags=Instrument.FLAG_GETSET,
units='#', type=float, minval=0.01, maxval=50)
@@ -141,7 +165,7 @@ def __init__(self, name, address, reset=False):
flags=Instrument.FLAG_GETSET,
units='',
type=bool)
-'''
+ '''
# add functions
@@ -171,7 +195,7 @@ def get_all(self):
'''
logging.info('Get all relevant data from device')
- for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging', 'digits', 'nplc']:
+ for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging', 'digits', 'nplc', 'integrationtime']:
logging.debug('get %s' % p)
par=getattr(self,p)
par.get()
@@ -180,7 +204,6 @@ def get_all(self):
# self.get_trigger_delay()
# self.get_trigger_source()
# self.get_trigger_timer()
- # self.get_integrationtime()
# self.get_display()
# self.get_autozero()
#self.get_averaging_window()
@@ -188,12 +211,15 @@ def get_all(self):
#self.get_averaging_type()
#self.get_autorange()
- def _current_mode_get(self, par, mode=None):
+ def _current_mode_get(self, par, mode=None, parser=None):
cmd=self._mode_par(mode, par)
- return self.ask(cmd)
+ r=self.ask(cmd)
+ if parser is not None:
+ r=parser(r)
+ return r
- def _current_mode_set(self, par, val, mode=None):
- cmd=self._mode_par_value(mode, par, val)
+ def _current_mode_set(self, value, par, mode=None):
+ cmd=self._mode_par_value(mode, par, value)
return self.write(cmd)
@@ -236,7 +262,7 @@ def set_defaults(self):
self.set_mode_volt_dc()
self.digits.set(7)
self.trigger_continuous.set(True)
- self.range.set(10)
+ self.range.set(10)
self.nplc.set(1)
self.averaging.set(False)
return
@@ -252,6 +278,7 @@ def _determine_mode(self, mode):
if mode not in self._modes and mode not in ('INIT', 'TRIG', 'SYST', 'DISP'):
logging.warning('Invalid mode %s, assuming current' % mode)
mode = self.mode.get_latest()
+ logging.debug('Determine mode: mode=%s' % mode)
return mode
def set_mode(self, mode):
From 287ec12dd55efec3e8478a4462714f11d9ac6960 Mon Sep 17 00:00:00 2001
From: Pieter
Date: Thu, 14 Apr 2016 14:12:08 +0200
Subject: [PATCH 4/8] update docstring handling code
---
docs/examples/Keithley_example.ipynb | 326 ++++++++++++++++--
qcodes/instrument/parameter.py | 13 +-
.../instrument_drivers/tektronix/Keithley.py | 16 +-
3 files changed, 326 insertions(+), 29 deletions(-)
diff --git a/docs/examples/Keithley_example.ipynb b/docs/examples/Keithley_example.ipynb
index e36dbec5286e..ba3400e54cb7 100644
--- a/docs/examples/Keithley_example.ipynb
+++ b/docs/examples/Keithley_example.ipynb
@@ -9,11 +9,249 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 1,
"metadata": {
"collapsed": false
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/*\r\n",
+ " * Qcodes Jupyter/IPython widgets\r\n",
+ " */\r\n",
+ "require([\r\n",
+ " 'nbextensions/widgets/widgets/js/widget',\r\n",
+ " 'nbextensions/widgets/widgets/js/manager'\r\n",
+ "], function (widget, manager) {\r\n",
+ "\r\n",
+ " var UpdateView = widget.DOMWidgetView.extend({\r\n",
+ " render: function() {\r\n",
+ " window.MYWIDGET = this;\r\n",
+ " this._interval = 0;\r\n",
+ " this.update();\r\n",
+ " },\r\n",
+ " update: function() {\r\n",
+ " this.display(this.model.get('_message'));\r\n",
+ " this.setInterval();\r\n",
+ " },\r\n",
+ " display: function(message) {\r\n",
+ " /*\r\n",
+ " * display method: override this for custom display logic\r\n",
+ " */\r\n",
+ " this.el.innerHTML = message;\r\n",
+ " },\r\n",
+ " remove: function() {\r\n",
+ " clearInterval(this._updater);\r\n",
+ " },\r\n",
+ " setInterval: function(newInterval) {\r\n",
+ " var me = this;\r\n",
+ " if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+ " if(newInterval===me._interval) return;\r\n",
+ "\r\n",
+ " me._interval = newInterval;\r\n",
+ "\r\n",
+ " if(me._updater) clearInterval(me._updater);\r\n",
+ "\r\n",
+ " if(me._interval) {\r\n",
+ " me._updater = setInterval(function() {\r\n",
+ " me.send({myupdate: true});\r\n",
+ " if(!me.model.comm_live) {\r\n",
+ " console.log('missing comm, canceling widget updates', me);\r\n",
+ " clearInterval(me._updater);\r\n",
+ " }\r\n",
+ " }, me._interval * 1000);\r\n",
+ " }\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+ "\r\n",
+ " var HiddenUpdateView = UpdateView.extend({\r\n",
+ " display: function(message) {\r\n",
+ " this.$el.hide();\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+ "\r\n",
+ " var SubprocessView = UpdateView.extend({\r\n",
+ " render: function() {\r\n",
+ " var me = window.SPVIEW = this;\r\n",
+ " me._interval = 0;\r\n",
+ " me._minimize = '';\r\n",
+ " me._restore = '';\r\n",
+ "\r\n",
+ " // in case there is already an outputView present,\r\n",
+ " // like from before restarting the kernel\r\n",
+ " $('.qcodes-output-view').not(me.$el).remove();\r\n",
+ "\r\n",
+ " me.$el\r\n",
+ " .addClass('qcodes-output-view')\r\n",
+ " .attr('qcodes-state', 'docked')\r\n",
+ " .html(\r\n",
+ " '' +\r\n",
+ " ''\r\n",
+ " );\r\n",
+ "\r\n",
+ " me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+ " me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+ " me.outputArea = me.$el.find('pre');\r\n",
+ " me.subprocessList = me.$el.find('span');\r\n",
+ " me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+ "\r\n",
+ " me.clearButton.click(function() {\r\n",
+ " me.outputArea.html('');\r\n",
+ " me.clearButton.addClass('disabled');\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.abortButton.click(function() {\r\n",
+ " me.send({abort: true});\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.$el.find('.js-state').click(function() {\r\n",
+ " var oldState = me.$el.attr('qcodes-state'),\r\n",
+ " state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+ " .split('-')[1].split(' ')[0];\r\n",
+ "\r\n",
+ " // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+ " // some other bit of code resets the parent after render if I do it there.\r\n",
+ " // To be safe, just do it on every state click.\r\n",
+ " me.$el.appendTo('body');\r\n",
+ "\r\n",
+ " if(oldState === 'floated') {\r\n",
+ " me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+ " }\r\n",
+ "\r\n",
+ " me.$el.attr('qcodes-state', state);\r\n",
+ "\r\n",
+ " if(state === 'floated') {\r\n",
+ " me.$el.draggable().css({\r\n",
+ " left: window.innerWidth - me.$el.width() - 15,\r\n",
+ " top: window.innerHeight - me.$el.height() - 10\r\n",
+ " });\r\n",
+ " }\r\n",
+ " });\r\n",
+ "\r\n",
+ " $(window).resize(function() {\r\n",
+ " if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+ " var position = me.$el.position(),\r\n",
+ " minVis = 20,\r\n",
+ " maxLeft = window.innerWidth - minVis,\r\n",
+ " maxTop = window.innerHeight - minVis;\r\n",
+ "\r\n",
+ " if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+ " if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+ " }\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.update();\r\n",
+ " },\r\n",
+ "\r\n",
+ " display: function(message) {\r\n",
+ " if(message) {\r\n",
+ " var initialScroll = this.outputArea.scrollTop();\r\n",
+ " this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+ " var scrollBottom = this.outputArea.scrollTop();\r\n",
+ "\r\n",
+ " if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+ " this.$el.find('.qcodes-docked').click();\r\n",
+ " // always scroll to the bottom if we're restoring\r\n",
+ " // because of a new message\r\n",
+ " initialScroll = scrollBottom;\r\n",
+ " }\r\n",
+ "\r\n",
+ " this.outputArea.append(message);\r\n",
+ " this.clearButton.removeClass('disabled');\r\n",
+ "\r\n",
+ " // if we were scrolled to the bottom initially, make sure\r\n",
+ " // we stay that way.\r\n",
+ " this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+ " this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+ " }\r\n",
+ "\r\n",
+ " var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+ " this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+ " this.subprocessList.text(processes);\r\n",
+ " }\r\n",
+ " });\r\n",
+ " manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+ "});\r\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
"source": [
"import matplotlib.pyplot as plt\n",
"import time\n",
@@ -44,7 +282,7 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 2,
"metadata": {
"collapsed": false
},
@@ -55,7 +293,7 @@
""
]
},
- "execution_count": 16,
+ "execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
@@ -67,7 +305,7 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 3,
"metadata": {
"collapsed": false
},
@@ -76,7 +314,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.14s\n"
+ "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.20s\n"
]
}
],
@@ -87,7 +325,7 @@
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": 4,
"metadata": {
"collapsed": false
},
@@ -106,7 +344,7 @@
},
{
"cell_type": "code",
- "execution_count": 19,
+ "execution_count": 5,
"metadata": {
"collapsed": false,
"scrolled": true
@@ -116,12 +354,12 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "measure: -1.044276\n",
- "measure: -1.050299\n",
- "measure: -1.056594\n",
- "measure: -1.069865\n",
- "measure: -1.075954\n",
- "measure: -1.081997\n"
+ "measure: -0.095112\n",
+ "measure: -0.104225\n",
+ "measure: -0.112567\n",
+ "measure: -0.129525\n",
+ "measure: -0.137803\n",
+ "measure: -0.146068\n"
]
}
],
@@ -132,7 +370,7 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 6,
"metadata": {
"collapsed": false
},
@@ -143,7 +381,7 @@
"[]"
]
},
- "execution_count": 12,
+ "execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
@@ -160,7 +398,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 7,
"metadata": {
"collapsed": false
},
@@ -171,7 +409,7 @@
"['VOLT:DC']"
]
},
- "execution_count": 13,
+ "execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
@@ -182,7 +420,7 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 8,
"metadata": {
"collapsed": false
},
@@ -191,7 +429,13 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "sds\n"
+ "Get integration time in Number of PowerLine Cycles.\n",
+ "To get the integrationtime in seconds, use get_integrationtime().\r\n",
+ "Parameter class:\n",
+ "* `name` nplc\r\n",
+ "* `label` nplc\r\n",
+ "* `units` APER\r\n",
+ "\n"
]
}
],
@@ -199,6 +443,48 @@
"print(k1.nplc.__doc__)"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Test whether the object can be pickled"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "ValueError",
+ "evalue": "ctypes objects containing pointers cannot be pickled",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mtempfile\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mtempfile\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTemporaryFile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'wb'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0moutput\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mpickle\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdump\u001b[0m\u001b[1;33m(\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mk1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moutput\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mValueError\u001b[0m: ctypes objects containing pointers cannot be pickled"
+ ]
+ }
+ ],
+ "source": [
+ "import pickle\n",
+ "import tempfile\n",
+ "with tempfile.TemporaryFile('wb') as output:\n",
+ " pickle.dump( (k1, ), output)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": []
+ },
{
"cell_type": "code",
"execution_count": null,
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index da76b5ebfd45..6121e7fdce6a 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -37,6 +37,7 @@
import time
import asyncio
import logging
+import os
from qcodes.utils.helpers import (permissive_range, wait_secs,
DelegateAttributes)
@@ -167,9 +168,19 @@ def __init__(self,
self.setpoint_names = setpoint_names
self.setpoint_labels = setpoint_labels
+
+ # generate default docstring
+ self.__doc__ = 'Parameter class:\n* `name` %s' % self.name + os.linesep
+ self.__doc__ += '* `label` %s' % self.label + os.linesep
+ self.__doc__ += '* `units` %s' % self.units + os.linesep
+ #parameter label (if not None)
+ #units
+ #validator type
+ #validator min and max (if applicable)
+
if docstring is not None:
#logging.debug('add docstring to Parameter!')
- self.__doc__ = docstring
+ self.__doc__ = docstring + os.linesep + self.__doc__
# record of latest value and when it was set or measured
# what exactly this means is different for different subclasses
diff --git a/qcodes/instrument_drivers/tektronix/Keithley.py b/qcodes/instrument_drivers/tektronix/Keithley.py
index 47c3345650ed..bb660dec66c4 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley.py
@@ -80,7 +80,6 @@ def __init__(self, name, address, reset=False):
t0 = time.time()
super().__init__(name, address)
- self._modes = ['']
self.add_parameter('IDN', get_cmd='*IDN?')
self._modes = ['VOLT:AC', 'VOLT:DC', 'CURR:AC', 'CURR:DC', 'RES',
@@ -90,6 +89,7 @@ def __init__(self, name, address, reset=False):
self._averaging_types = ['MOV','REP']
self._trigger_sent = False
+
# Add parameters to wrapper
self.add_parameter('mode', get_cmd=':CONF?', get_parser=parsestr, set_cmd=':CONF:{}', vals=StringValidator() )
@@ -112,11 +112,11 @@ def __init__(self, name, address, reset=False):
self.add_parameter('nplc', get_cmd=partial( self._current_mode_get, 'NPLC', parser=float),
set_cmd=partial(self._current_mode_set, par='NPLC', mode=None), units='APER',
- docstring='Get integration time in Number of PowerLine Cycles. \
- To get the integrationtime in seconds, use get_integrationtime().' )
+ docstring='Get integration time in Number of PowerLine Cycles.' +
+ '\nTo get the integrationtime in seconds, use get_integrationtime().' )
self.add_parameter('range', get_cmd=partial(self._current_mode_get, 'RANG',parser=float),
- set_cmd=partial(self._current_mode_set, par='RANG'), units='RANG' )
+ set_cmd=partial(self._current_mode_set, par='RANG'), units='RANG', docstring='Sets the measurement range. Note that not only a discrete set of ranges can be set (see the manual for details).' )
self.add_parameter('integrationtime', get_cmd=partial(self._current_mode_get, 'APER', parser=float),
set_cmd=partial(self._current_mode_set, par='APER', mode=None), units='s',
@@ -134,15 +134,15 @@ def __init__(self, name, address, reset=False):
flags=Instrument.FLAG_GETSET,
units='s', minval=0.001, maxval=99999.999, type=float)
self.add_parameter('readval', flags=Instrument.FLAG_GET,
- units='AU',
+ units='arb.unit',
type=float,
tags=['measure'])
self.add_parameter('readlastval', flags=Instrument.FLAG_GET,
- units='AU',
+ units='arb.unit',
type=float,
tags=['measure'])
self.add_parameter('readnextval', flags=Instrument.FLAG_GET,
- units='AU',
+ units='arb.unit',
type=float,
tags=['measure'])
self.add_parameter('nplc',
@@ -169,7 +169,7 @@ def __init__(self, name, address, reset=False):
# add functions
- self.add_function('readnext', units='AU', call_cmd=':DATA:FRESH?', return_parser=float)
+ self.add_function('readnext', units='arb.unit', call_cmd=':DATA:FRESH?', return_parser=float)
if reset:
self.reset()
From cea5b7cada1bdc4f4fc6d117b7295cfc18680434 Mon Sep 17 00:00:00 2001
From: Pieter
Date: Thu, 14 Apr 2016 14:26:26 +0200
Subject: [PATCH 5/8] rename Keithley driver
---
docs/examples/Keithley_example.ipynb | 2 +-
.../tektronix/{Keithley.py => Keithley_2700.py} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename qcodes/instrument_drivers/tektronix/{Keithley.py => Keithley_2700.py} (100%)
diff --git a/docs/examples/Keithley_example.ipynb b/docs/examples/Keithley_example.ipynb
index ba3400e54cb7..fe71ad91c260 100644
--- a/docs/examples/Keithley_example.ipynb
+++ b/docs/examples/Keithley_example.ipynb
@@ -300,7 +300,7 @@
],
"source": [
"import qcodes.instrument_drivers\n",
- "import qcodes.instrument_drivers.tektronix.Keithley as keith; reload(keith)"
+ "import qcodes.instrument_drivers.tektronix.Keithley_2700 as keith; reload(keith)"
]
},
{
diff --git a/qcodes/instrument_drivers/tektronix/Keithley.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
similarity index 100%
rename from qcodes/instrument_drivers/tektronix/Keithley.py
rename to qcodes/instrument_drivers/tektronix/Keithley_2700.py
From 76dc2750e2b47b0a52e1b8680e7cc6e2af64279f Mon Sep 17 00:00:00 2001
From: alexcjohnson
Date: Sat, 16 Apr 2016 01:44:26 +0200
Subject: [PATCH 6/8] docstring for multi-return parameters, and some
parameter/function linting
---
qcodes/instrument/function.py | 7 ++++---
qcodes/instrument/parameter.py | 31 +++++++++++++++++--------------
2 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/qcodes/instrument/function.py b/qcodes/instrument/function.py
index ca1b1fa67c77..ee938d53b1a5 100644
--- a/qcodes/instrument/function.py
+++ b/qcodes/instrument/function.py
@@ -47,7 +47,8 @@ class Function(Metadatable):
NOTE: parsers only apply if call_cmd is a string. The function forms
of call_cmd and async_call_cmd should do their own parsing.
docstring: documentation string for the __doc__ field of the object
- The __doc__ field of the instance is used by some help systems, but not all
+ The __doc__ field of the instance is used by some help systems,
+ but not all (particularly not builtin `help(...)`)
'''
def __init__(self, name, instrument=None,
call_cmd=None, async_call_cmd=None,
@@ -59,8 +60,8 @@ def __init__(self, name, instrument=None,
self.name = name
if docstring is not None:
- self.__doc__=docstring
-
+ self.__doc__ = docstring
+
self._set_args(args)
self._set_call(call_cmd, async_call_cmd,
arg_parser, return_parser)
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 6121e7fdce6a..d596321ae5d1 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -145,7 +145,13 @@ def __init__(self,
# and names are the items it returns
self.names = names
self.labels = names if labels is None else names
- self.units = units if units is not None else ['']*len(names)
+ self.units = units if units is not None else [''] * len(names)
+
+ self.__doc__ = os.linesep.join((
+ 'Parameter class:',
+ '* `names` %s' % ', '.join(self.names),
+ '* `labels` %s' % ', '.join(self.labels),
+ '* `units` %s' % ', '.join(self.units)))
elif name is not None:
self.name = name
@@ -155,6 +161,14 @@ def __init__(self,
# vals / validate only applies to simple single-value parameters
self._set_vals(vals)
+ # generate default docstring
+ self.__doc__ = os.linesep.join((
+ 'Parameter class:',
+ '* `name` %s' % self.name,
+ '* `label` %s' % self.label,
+ '* `units` %s' % self.units,
+ '* `vals` %s' % repr(self._vals)))
+
else:
raise ValueError('either name or names is required')
@@ -168,20 +182,9 @@ def __init__(self,
self.setpoint_names = setpoint_names
self.setpoint_labels = setpoint_labels
-
- # generate default docstring
- self.__doc__ = 'Parameter class:\n* `name` %s' % self.name + os.linesep
- self.__doc__ += '* `label` %s' % self.label + os.linesep
- self.__doc__ += '* `units` %s' % self.units + os.linesep
- #parameter label (if not None)
- #units
- #validator type
- #validator min and max (if applicable)
-
if docstring is not None:
- #logging.debug('add docstring to Parameter!')
self.__doc__ = docstring + os.linesep + self.__doc__
-
+
# record of latest value and when it was set or measured
# what exactly this means is different for different subclasses
# but they all use the same attributes so snapshot is consistent.
@@ -285,7 +288,7 @@ class StandardParameter(Parameter):
max_val_age: max time (in seconds) to trust a saved value from
this parameter as the starting point of a sweep
docstring: documentation string for the __doc__ field of the object
- The __doc__ field of the instance is used by some help systems, but not all
+ The __doc__ field of the instance is used by some help systems, but not all
'''
def __init__(self, name, instrument=None,
get_cmd=None, async_get_cmd=None, get_parser=None,
From bd4ae885ab31bb2275ee21330471da4907bfc5b5 Mon Sep 17 00:00:00 2001
From: alexcjohnson
Date: Sat, 16 Apr 2016 02:09:50 +0200
Subject: [PATCH 7/8] lint K2700 driver
---
.../tektronix/Keithley_2700.py | 227 +++++++++++-------
1 file changed, 134 insertions(+), 93 deletions(-)
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
index bb660dec66c4..f89f6b47c377 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2700.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -23,45 +23,45 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import time
-from numpy import pi
+import logging
+from functools import partial
+
from qcodes.instrument.visa import VisaInstrument
-#from qcodes.utils import validators
from qcodes.utils.validators import Strings as StringValidator
from qcodes.utils.validators import Ints as IntsValidator
from qcodes.utils.validators import Numbers as NumbersValidator
-import logging
-#%% Helper functions
+# %% Helper functions
+
def bool_to_str(val):
'''
Function to convert boolean to 'ON' or 'OFF'
'''
- if val == True:
+ if val is True:
return "ON"
else:
return "OFF"
+# %% Driver for Keithley_2700
-#%% Driver for Keithley_2700
-
-from functools import partial
-
def parseint(v):
logging.debug('parseint: %s -> %d' % (v, int(v)))
return int(v)
+
def parsebool(v):
- r=bool(int(v))
+ r = bool(int(v))
logging.debug('parsetobool: %s -> %d' % (v, r))
return r
+
def parsestr(v):
return v.strip().strip('"')
-
-
+
+
class Keithley_2700(VisaInstrument):
'''
This is the qcodes driver for the Keithley_2700 Multimeter
@@ -71,58 +71,96 @@ class Keithley_2700(VisaInstrument):
change_display=, change_autozero=)
Status: beta-version.
-
+
This driver will most likely work for multiple Keithley SourceMeters.
- This driver does not contain all commands available, but only the ones most commonly used.
+ This driver does not contain all commands available, but only the ones
+ most commonly used.
'''
def __init__(self, name, address, reset=False):
t0 = time.time()
super().__init__(name, address)
self.add_parameter('IDN', get_cmd='*IDN?')
-
+
self._modes = ['VOLT:AC', 'VOLT:DC', 'CURR:AC', 'CURR:DC', 'RES',
- 'FRES', 'TEMP', 'FREQ']
- #self._change_display = change_display
- #self._change_autozero = change_autozero
- self._averaging_types = ['MOV','REP']
+ 'FRES', 'TEMP', 'FREQ']
+ # self._change_display = change_display
+ # self._change_autozero = change_autozero
+ self._averaging_types = ['MOV', 'REP']
self._trigger_sent = False
-
-
+
# Add parameters to wrapper
- self.add_parameter('mode', get_cmd=':CONF?', get_parser=parsestr, set_cmd=':CONF:{}', vals=StringValidator() )
-
- self.add_parameter('trigger_count', get_cmd=self._mode_par('INIT', 'CONT'),
- get_parser=int, set_cmd=self._mode_par_value('INIT','CONT','{}'),
- vals=IntsValidator(), units='#' )
- self.add_parameter('trigger_delay', get_cmd=self._mode_par('TRIG', 'DEL'),
- get_parser=float, set_cmd=self._mode_par_value('TRIG', 'DEL', '{}'),
- vals=NumbersValidator(min_value=0, max_value=999999.999), units='s')
-
- self.add_parameter('trigger_continuous', get_cmd=self._mode_par('INIT', 'CONT'),
- get_parser=parsebool, set_cmd=self._mode_par_value('INIT', 'CONT', '{}'), set_parser=bool_to_str )
-
- self.add_parameter('averaging', get_cmd=partial(self._current_mode_get, 'AVER:STAT', parser=parsebool),
- set_cmd=partial(self._current_mode_set, par='AVER:STAT'),
- set_parser=bool_to_str )
-
- self.add_parameter('digits', get_cmd=partial(self._current_mode_get, 'DIG', parser=int),
- set_cmd=partial(self._current_mode_set, par='DIG') )
-
- self.add_parameter('nplc', get_cmd=partial( self._current_mode_get, 'NPLC', parser=float),
- set_cmd=partial(self._current_mode_set, par='NPLC', mode=None), units='APER',
- docstring='Get integration time in Number of PowerLine Cycles.' +
- '\nTo get the integrationtime in seconds, use get_integrationtime().' )
-
- self.add_parameter('range', get_cmd=partial(self._current_mode_get, 'RANG',parser=float),
- set_cmd=partial(self._current_mode_set, par='RANG'), units='RANG', docstring='Sets the measurement range. Note that not only a discrete set of ranges can be set (see the manual for details).' )
-
- self.add_parameter('integrationtime', get_cmd=partial(self._current_mode_get, 'APER', parser=float),
- set_cmd=partial(self._current_mode_set, par='APER', mode=None), units='s',
- vals=NumbersValidator(min_value=2e-4, max_value=1.),
- docstring='Get integration time in seconds. To get the integrationtime as a Number of PowerLine Cycles, use get_nplc().' )
-
+ self.add_parameter('mode',
+ get_cmd=':CONF?',
+ get_parser=parsestr,
+ set_cmd=':CONF:{}',
+ vals=StringValidator())
+
+ self.add_parameter('trigger_count',
+ get_cmd=self._mode_par('INIT', 'CONT'),
+ get_parser=int,
+ set_cmd=self._mode_par_value('INIT', 'CONT', '{}'),
+ vals=IntsValidator(),
+ units='#')
+ self.add_parameter('trigger_delay',
+ get_cmd=self._mode_par('TRIG', 'DEL'),
+ get_parser=float,
+ set_cmd=self._mode_par_value('TRIG', 'DEL', '{}'),
+ vals=NumbersValidator(min_value=0,
+ max_value=999999.999),
+ units='s')
+
+ self.add_parameter('trigger_continuous',
+ get_cmd=self._mode_par('INIT', 'CONT'),
+ get_parser=parsebool,
+ set_cmd=self._mode_par_value('INIT', 'CONT', '{}'),
+ set_parser=bool_to_str)
+
+ self.add_parameter('averaging',
+ get_cmd=partial(self._current_mode_get, 'AVER:STAT',
+ parser=parsebool),
+ set_cmd=partial(self._current_mode_set,
+ par='AVER:STAT'),
+ set_parser=bool_to_str)
+
+ self.add_parameter('digits',
+ get_cmd=partial(self._current_mode_get, 'DIG',
+ parser=int),
+ set_cmd=partial(self._current_mode_set, par='DIG'))
+
+ self.add_parameter('nplc',
+ get_cmd=partial(self._current_mode_get, 'NPLC',
+ parser=float),
+ set_cmd=partial(self._current_mode_set, par='NPLC',
+ mode=None),
+ units='APER',
+ docstring=('Get integration time in Number of '
+ 'PowerLine Cycles.\n'
+ 'To get the integrationtime in seconds, '
+ 'use get_integrationtime().'))
+
+ self.add_parameter('range',
+ get_cmd=partial(self._current_mode_get, 'RANG',
+ parser=float),
+ set_cmd=partial(self._current_mode_set, par='RANG'),
+ units='RANG',
+ docstring=('Sets the measurement range.\n'
+ 'Note that not only a discrete set of '
+ 'ranges can be set (see the manual for '
+ 'details).'))
+
+ self.add_parameter('integrationtime',
+ get_cmd=partial(self._current_mode_get, 'APER',
+ parser=float),
+ set_cmd=partial(self._current_mode_set, par='APER',
+ mode=None),
+ units='s',
+ vals=NumbersValidator(min_value=2e-4, max_value=1.),
+ docstring=('Get integration time in seconds.\n'
+ 'To get the integrationtime as a Number '
+ 'of PowerLine Cycles, use get_nplc().'))
+
'''
self.add_parameter('range',
flags=Instrument.FLAG_GETSET,
@@ -166,10 +204,12 @@ def __init__(self, name, address, reset=False):
units='',
type=bool)
'''
-
# add functions
- self.add_function('readnext', units='arb.unit', call_cmd=':DATA:FRESH?', return_parser=float)
+ self.add_function('readnext',
+ units='arb.unit',
+ call_cmd=':DATA:FRESH?',
+ return_parser=float)
if reset:
self.reset()
@@ -182,7 +222,6 @@ def __init__(self, name, address, reset=False):
self.get('IDN').replace(',', ', ').replace('\n', ' '),
'in %.2fs' % (t1-t0))
-
def get_all(self):
'''
Reads all relevant parameters from instrument
@@ -194,38 +233,38 @@ def get_all(self):
None
'''
logging.info('Get all relevant data from device')
-
- for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging', 'digits', 'nplc', 'integrationtime']:
+
+ for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging',
+ 'digits', 'nplc', 'integrationtime']:
logging.debug('get %s' % p)
- par=getattr(self,p)
+ par = getattr(self, p)
par.get()
-
-# self.get_range()
- # self.get_trigger_delay()
- # self.get_trigger_source()
- # self.get_trigger_timer()
- # self.get_display()
- # self.get_autozero()
- #self.get_averaging_window()
- #self.get_averaging_count()
- #self.get_averaging_type()
- #self.get_autorange()
-
+
+ # self.get_range()
+ # self.get_trigger_delay()
+ # self.get_trigger_source()
+ # self.get_trigger_timer()
+ # self.get_display()
+ # self.get_autozero()
+ # self.get_averaging_window()
+ # self.get_averaging_count()
+ # self.get_averaging_type()
+ # self.get_autorange()
+
def _current_mode_get(self, par, mode=None, parser=None):
- cmd=self._mode_par(mode, par)
- r=self.ask(cmd)
+ cmd = self._mode_par(mode, par)
+ r = self.ask(cmd)
if parser is not None:
- r=parser(r)
+ r = parser(r)
return r
def _current_mode_set(self, value, par, mode=None):
- cmd=self._mode_par_value(mode, par, value)
+ cmd = self._mode_par_value(mode, par, value)
return self.write(cmd)
-
-# --------------------------------------
-# functions
-# --------------------------------------
+ # --------------------------------------
+ # functions
+ # --------------------------------------
def set_mode_volt_dc(self):
'''
@@ -239,7 +278,7 @@ def set_mode_volt_dc(self):
'''
logging.debug('Set mode to DC Voltage')
self.mode.set('VOLT:DC')
-
+
def set_defaults(self):
'''
Set to driver defaults:
@@ -254,19 +293,19 @@ def set_defaults(self):
self.write('SYST:PRES')
self.write(':FORM:ELEM READ')
- # Sets the format to only the read out, all options are:
- # READing = DMM reading, UNITs = Units,
- # TSTamp = Timestamp, RNUMber = Reading number,
- # CHANnel = Channel number, LIMits = Limits reading
+ # Sets the format to only the read out, all options are:
+ # READing = DMM reading, UNITs = Units,
+ # TSTamp = Timestamp, RNUMber = Reading number,
+ # CHANnel = Channel number, LIMits = Limits reading
self.set_mode_volt_dc()
self.digits.set(7)
self.trigger_continuous.set(True)
- self.range.set(10)
+ self.range.set(10)
self.nplc.set(1)
self.averaging.set(False)
return
-
+
def _determine_mode(self, mode):
'''
Return the mode string to use.
@@ -274,13 +313,14 @@ def _determine_mode(self, mode):
'''
logging.debug('Determine mode with mode=%s' % mode)
if mode is None:
- mode = self.mode.get_latest() # _mode(query=False)
- if mode not in self._modes and mode not in ('INIT', 'TRIG', 'SYST', 'DISP'):
+ mode = self.mode.get_latest() # _mode(query=False)
+ if mode not in self._modes and mode not in ('INIT', 'TRIG', 'SYST',
+ 'DISP'):
logging.warning('Invalid mode %s, assuming current' % mode)
mode = self.mode.get_latest()
logging.debug('Determine mode: mode=%s' % mode)
return mode
-
+
def set_mode(self, mode):
'''
Set the mode to the specified value
@@ -309,14 +349,14 @@ def set_mode(self, mode):
else:
logging.error('invalid mode %s' % mode)
+ # Get all values again because some parameters depend on mode
self.get_all()
- # Get all values again because some parameters depend on mode
def _mode_par_value(self, mode, par, val):
'''
For internal use only!!
Create command string based on current mode
-
+
Input:
mode (string) : The mode to use
par (string) : Parameter
@@ -328,11 +368,12 @@ def _mode_par_value(self, mode, par, val):
mode = self._determine_mode(mode)
string = ':%s:%s %s' % (mode, par, val)
return string
+
def _mode_par(self, mode, par):
'''
For internal use only!!
Create command string based on current mode
-
+
Input:
mode (string) : The mode to use
par (string) : Parameter
@@ -344,7 +385,7 @@ def _mode_par(self, mode, par):
mode = self._determine_mode(mode)
string = ':%s:%s?' % (mode, par, )
return string
-
+
def reset(self):
'''
Resets instrument to default values
From b6f8ee271171fdc55fc25cbe1be5e4c53a506e7b Mon Sep 17 00:00:00 2001
From: Pieter
Date: Mon, 18 Apr 2016 13:34:53 +0200
Subject: [PATCH 8/8] fix bool_to_str function
---
docs/examples/Keithley_example.ipynb | 10 ++++----
.../tektronix/Keithley_2700.py | 25 ++++++-------------
2 files changed, 13 insertions(+), 22 deletions(-)
diff --git a/docs/examples/Keithley_example.ipynb b/docs/examples/Keithley_example.ipynb
index fe71ad91c260..1d9799c229f8 100644
--- a/docs/examples/Keithley_example.ipynb
+++ b/docs/examples/Keithley_example.ipynb
@@ -282,7 +282,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 12,
"metadata": {
"collapsed": false
},
@@ -290,10 +290,10 @@
{
"data": {
"text/plain": [
- ""
+ ""
]
},
- "execution_count": 2,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
@@ -305,7 +305,7 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 13,
"metadata": {
"collapsed": false
},
@@ -314,7 +314,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.20s\n"
+ "Connected to: KEITHLEY INSTRUMENTS INC., MODEL 2700, 0792116, B06 /A02 in 0.17s\n"
]
}
],
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
index f89f6b47c377..39e11a2b8a04 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2700.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -39,7 +39,7 @@ def bool_to_str(val):
'''
Function to convert boolean to 'ON' or 'OFF'
'''
- if val is True:
+ if val:
return "ON"
else:
return "OFF"
@@ -116,6 +116,11 @@ def __init__(self, name, address, reset=False):
get_parser=parsebool,
set_cmd=self._mode_par_value('INIT', 'CONT', '{}'),
set_parser=bool_to_str)
+ self.add_parameter('display',
+ get_cmd=self._mode_par('DISP', 'ENAB'),
+ get_parser=parsebool,
+ set_cmd=self._mode_par_value('DISP', 'ENAB', '{}'),
+ set_parser=bool_to_str)
self.add_parameter('averaging',
get_cmd=partial(self._current_mode_get, 'AVER:STAT',
@@ -162,9 +167,6 @@ def __init__(self, name, address, reset=False):
'of PowerLine Cycles, use get_nplc().'))
'''
- self.add_parameter('range',
- flags=Instrument.FLAG_GETSET,
- units='', minval=0.1, maxval=1000, type=float)
self.add_parameter('trigger_source',
flags=Instrument.FLAG_GETSET,
units='')
@@ -183,11 +185,6 @@ def __init__(self, name, address, reset=False):
units='arb.unit',
type=float,
tags=['measure'])
- self.add_parameter('nplc',
- flags=Instrument.FLAG_GETSET,
- units='#', type=float, minval=0.01, maxval=50)
- self.add_parameter('display', flags=Instrument.FLAG_GETSET,
- type=bool)
self.add_parameter('autozero', flags=Instrument.FLAG_GETSET,
type=bool)
self.add_parameter('averaging_window',
@@ -235,16 +232,14 @@ def get_all(self):
logging.info('Get all relevant data from device')
for p in ['mode', 'trigger_count', 'trigger_continuous', 'averaging',
- 'digits', 'nplc', 'integrationtime']:
+ 'digits', 'nplc', 'integrationtime', 'range', 'display']:
logging.debug('get %s' % p)
par = getattr(self, p)
par.get()
- # self.get_range()
# self.get_trigger_delay()
# self.get_trigger_source()
# self.get_trigger_timer()
- # self.get_display()
# self.get_autozero()
# self.get_averaging_window()
# self.get_averaging_count()
@@ -400,8 +395,4 @@ def reset(self):
self._visainstrument.write('*RST')
self.get_all()
- # def on(self):
- # self.set('status', 'on')
-
- # def off(self):
- # self.set('status', 'off')
+
\ No newline at end of file