diff --git a/.gitignore b/.gitignore
index 587118e9e30..86724a0faeb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,4 +74,13 @@ target/
*.py~
tmp/
+# DS-store
+*.DS_Store
+
+# Sublime text automation
+*.sublime-project
+*.sublime-workspace
+
+venv/
+
docs/examples/data/*
diff --git a/docs/examples/Qcodes example ATS9870.ipynb b/docs/examples/Qcodes example ATS9870.ipynb
new file mode 100644
index 00000000000..d5dec7e0566
--- /dev/null
+++ b/docs/examples/Qcodes example ATS9870.ipynb
@@ -0,0 +1,1669 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Anaconda3\\lib\\site-packages\\IPython\\kernel\\__init__.py:13: ShimWarning: The `IPython.kernel` package has been deprecated. You should import from ipykernel or jupyter_client instead.\n",
+ " \"You should import from ipykernel or jupyter_client instead.\", ShimWarning)\n"
+ ]
+ },
+ {
+ "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 = this;\r\n",
+ " me._interval = 0;\r\n",
+ " me._minimize = '';\r\n",
+ " me._restore = '';\r\n",
+ "\r\n",
+ " // max lines of output to show\r\n",
+ " me.maxOutputLength = 500;\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('.qcodes-process-list');\r\n",
+ " me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+ " me.processLinesButton = me.$el.find('.qcodes-processlines')\r\n",
+ "\r\n",
+ " me.outputLines = [];\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.processLinesButton.click(function() {\r\n",
+ " // toggle multiline process list display\r\n",
+ " me.subprocessesMultiline = !me.subprocessesMultiline;\r\n",
+ " me.showSubprocesses();\r\n",
+ " });\r\n",
+ "\r\n",
+ " me.$el.find('.js-state').click(function() {\r\n",
+ " var state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+ " .split('-')[1].split(' ')[0];\r\n",
+ " me.model.set('_state', state);\r\n",
+ " });\r\n",
+ "\r\n",
+ " $(window)\r\n",
+ " .off('resize.qcodes')\r\n",
+ " .on('resize.qcodes', function() {me.clipBounds();});\r\n",
+ "\r\n",
+ " me.update();\r\n",
+ " },\r\n",
+ "\r\n",
+ " updateState: function() {\r\n",
+ " var me = this,\r\n",
+ " oldState = me.$el.attr('qcodes-state'),\r\n",
+ " state = me.model.get('_state');\r\n",
+ "\r\n",
+ " if(state === oldState) return;\r\n",
+ "\r\n",
+ " setTimeout(function() {\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",
+ " console.log('here');\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\r\n",
+ " .draggable({stop: function() { me.clipBounds(); }})\r\n",
+ " .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",
+ " // any previous highlighting is now moot\r\n",
+ " me.$el.removeClass('qcodes-highlight');\r\n",
+ " }, 0);\r\n",
+ "\r\n",
+ " },\r\n",
+ "\r\n",
+ " clipBounds: function() {\r\n",
+ " var me = this;\r\n",
+ " if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+ " var bounds = me.$el[0].getBoundingClientRect(),\r\n",
+ " minVis = 40,\r\n",
+ " maxLeft = window.innerWidth - minVis,\r\n",
+ " minLeft = minVis - bounds.width,\r\n",
+ " maxTop = window.innerHeight - minVis;\r\n",
+ "\r\n",
+ " if(bounds.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+ " else if(bounds.left < minLeft) me.$el.css('left', minLeft);\r\n",
+ "\r\n",
+ " if(bounds.top > maxTop) me.$el.css('top', maxTop);\r\n",
+ " else if(bounds.top < 0) me.$el.css('top', 0);\r\n",
+ " }\r\n",
+ " },\r\n",
+ "\r\n",
+ " display: function(message) {\r\n",
+ " var me = this;\r\n",
+ " if(message) {\r\n",
+ " var initialScroll = me.outputArea.scrollTop();\r\n",
+ " me.outputArea.scrollTop(me.outputArea.prop('scrollHeight'));\r\n",
+ " var scrollBottom = me.outputArea.scrollTop();\r\n",
+ "\r\n",
+ " if(me.$el.attr('qcodes-state') === 'minimized') {\r\n",
+ " // if we add text and the box is minimized, highlight the\r\n",
+ " // title bar to alert the user that there are new messages.\r\n",
+ " // remove then add the class, so we get the animation again\r\n",
+ " // if it's already highlighted\r\n",
+ " me.$el.removeClass('qcodes-highlight');\r\n",
+ " setTimeout(function(){\r\n",
+ " me.$el.addClass('qcodes-highlight');\r\n",
+ " }, 0);\r\n",
+ " }\r\n",
+ "\r\n",
+ " var newLines = message.split('\\n'),\r\n",
+ " out = me.outputLines,\r\n",
+ " outLen = out.length;\r\n",
+ " if(outLen) out[outLen - 1] += newLines[0];\r\n",
+ " else out.push(newLines[0]);\r\n",
+ "\r\n",
+ " for(var i = 1; i < newLines.length; i++) {\r\n",
+ " out.push(newLines[i]);\r\n",
+ " }\r\n",
+ "\r\n",
+ " if(out.length > me.maxOutputLength) {\r\n",
+ " out.splice(0, out.length - me.maxOutputLength + 1,\r\n",
+ " '<<< Output clipped >>>');\r\n",
+ " }\r\n",
+ "\r\n",
+ " me.outputArea.text(out.join('\\n'));\r\n",
+ " me.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",
+ " me.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+ " me.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+ " }\r\n",
+ "\r\n",
+ " me.showSubprocesses();\r\n",
+ " me.updateState();\r\n",
+ " },\r\n",
+ "\r\n",
+ " showSubprocesses: function() {\r\n",
+ " var me = this,\r\n",
+ " replacer = me.subprocessesMultiline ? '
' : ', ',\r\n",
+ " processes = (me.model.get('_processes') || '')\r\n",
+ " .replace(/\\n/g, '>' + replacer + '<');\r\n",
+ "\r\n",
+ " if(processes) processes = '<' + processes + '>';\r\n",
+ " else processes = 'No subprocesses';\r\n",
+ "\r\n",
+ " me.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+ "\r\n",
+ " me.subprocessList.html(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"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "No loop running\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "a:\\qcodesfolder\\qcodes\\process\\helpers.py:27: UserWarning: Multiprocessing is in beta, use at own risk\n",
+ " warnings.warn(\"Multiprocessing is in beta, use at own risk\", UserWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# import all necessary things\n",
+ "%matplotlib nbagg\n",
+ "\n",
+ "import qcodes as qc\n",
+ "import qcodes.instrument.parameter as parameter\n",
+ "import qcodes.instrument_drivers.AlazarTech.ATS9360 as ATSdriver\n",
+ "import qcodes.instrument_drivers.AlazarTech.ATS_acquisition_controllers as ats_contr\n",
+ "\n",
+ "qc.halt_bg()\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": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[{'bits_per_sample': 12,\n",
+ " 'board_id': 1,\n",
+ " 'board_kind': 'ATS9360',\n",
+ " 'max_samples': 4294967294,\n",
+ " 'system_id': 1}]"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Command to list all alazar boards connected to the system\n",
+ "ATSdriver.AlazarTech_ATS.find_boards()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "a:\\qcodesfolder\\qcodes\\instrument\\metaclass.py:37: UserWarning: Multiprocessing is in beta, use at own risk\n",
+ " UserWarning)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "{'CPLD_version': '25.16',\n",
+ " 'SDK_version': '5.10.6',\n",
+ " 'asopc_type': '1779598176',\n",
+ " 'driver_version': '5.10.6',\n",
+ " 'firmware': None,\n",
+ " 'latest_cal_date': '11-09-15',\n",
+ " 'memory_size': '4294967294',\n",
+ " 'model': 'ATS9360',\n",
+ " 'pcie_link_speed': '0.5GB/s',\n",
+ " 'pcie_link_width': '8',\n",
+ " 'serial': '970273',\n",
+ " 'vendor': 'AlazarTech'}"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Create the ATS9870 instrument on the new server \"alazar_server\"\n",
+ "ats_inst = ATSdriver.AlazarTech_ATS9360(name='Alazar1', server_name=\"alazar_server\")\n",
+ "# Print all information about this Alazar card\n",
+ "ats_inst.get_idn()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "a:\\qcodesfolder\\qcodes\\instrument\\metaclass.py:37: UserWarning: Multiprocessing is in beta, use at own risk\n",
+ " UserWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Instantiate an acquisition controller (In this case we are doing a simple DFT) on the same server (\"alazar_server\") and \n",
+ "# provide the name of the name of the alazar card that this controller should control\n",
+ "acquisition_controller = ats_contr.Demodulation_AcquisitionController(name='acquisition_controller', \n",
+ " demodulation_frequency=10e6, \n",
+ " alazar_name='Alazar1', \n",
+ " server_name=\"alazar_server\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "# Configure all settings in the Alazar card\n",
+ "ats_inst.config(#clock_source='INTERNAL_CLOCK',\n",
+ " sample_rate=100000000,\n",
+ " #clock_edge='CLOCK_EDGE_RISING',\n",
+ " #decimation=0,\n",
+ " #coupling=['AC','AC'],\n",
+ " channel_range=[2.,2.],\n",
+ " #impedance=[50,50],\n",
+ " #bwlimit=['DISABLED','DISABLED'],\n",
+ " #trigger_operation='TRIG_ENGINE_OP_J',\n",
+ " #trigger_engine1='TRIG_ENGINE_J',\n",
+ " trigger_source1='EXTERNAL',\n",
+ " #trigger_slope1='TRIG_SLOPE_POSITIVE',\n",
+ " #trigger_level1=128,\n",
+ " #trigger_engine2='TRIG_ENGINE_K',\n",
+ " #trigger_source2='DISABLE',\n",
+ " #trigger_slope2='TRIG_SLOPE_POSITIVE',\n",
+ " #trigger_level2=128,\n",
+ " #external_trigger_coupling='AC',\n",
+ " #external_trigger_range='ETR_5V',\n",
+ " #trigger_delay=0,\n",
+ " #timeout_ticks=0\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# This command is specific to this acquisition controller. The kwargs provided here are being forwarded to ats_inst.acquire\n",
+ "# This way, it becomes easy to change acquisition specific settings from the ipython notebook\n",
+ "acquisition_controller.update_acquisitionkwargs(#mode='NPT',\n",
+ " samples_per_record=1024,\n",
+ " records_per_buffer=70,\n",
+ " buffers_per_acquisition=1,\n",
+ " #channel_selection='AB',\n",
+ " #transfer_offset=0,\n",
+ " #external_startcapture='ENABLED',\n",
+ " #enable_record_headers='DISABLED',\n",
+ " #alloc_buffers='DISABLED',\n",
+ " #fifo_only_streaming='DISABLED',\n",
+ " #interleave_samples='DISABLED',\n",
+ " #get_processed_data='DISABLED',\n",
+ " allocated_buffers=1,\n",
+ " #buffer_timeout=1000\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3.035316733376046"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Getting the value of the parameter 'acquisition' of the instrument 'acquisition_controller' performes the entire acquisition \n",
+ "# protocol. This again depends on the specific implementation of the acquisition controller\n",
+ "acquisition_controller.acquisition()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS9870.AlazarTech_ATS9870',\n",
+ " 'functions': {},\n",
+ " 'name': 'Alazar1',\n",
+ " 'parameters': {'IDN': {'__class__': 'qcodes.instrument.parameter.StandardParameter',\n",
+ " 'instrument': 'qcodes.instrument_drivers.AlazarTech.ATS9870.AlazarTech_ATS9870',\n",
+ " 'instrument_name': 'Alazar1',\n",
+ " 'label': 'IDN',\n",
+ " 'name': 'IDN',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': {'CPLD_version': '13.8',\n",
+ " 'SDK_version': '5.10.15',\n",
+ " 'asopc_type': '2435577968',\n",
+ " 'driver_version': '5.10.15',\n",
+ " 'firmware': None,\n",
+ " 'latest_cal_date': '30-01-13',\n",
+ " 'memory_size': '4294966272',\n",
+ " 'model': 'ATS9870',\n",
+ " 'pcie_link_speed': '0.25GB/s',\n",
+ " 'pcie_link_width': '8',\n",
+ " 'serial': '910266',\n",
+ " 'vendor': 'AlazarTech'}},\n",
+ " 'alloc_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Alloc Buffers',\n",
+ " 'name': 'alloc_buffers',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'allocated_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Allocated Buffers',\n",
+ " 'name': 'allocated_buffers',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 1},\n",
+ " 'buffer_timeout': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Buffer Timeout',\n",
+ " 'name': 'buffer_timeout',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'ms',\n",
+ " 'value': 1000},\n",
+ " 'buffers_per_acquisition': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Buffers per Acquisition',\n",
+ " 'name': 'buffers_per_acquisition',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 1},\n",
+ " 'bwlimit1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Bandwidth limit channel 1',\n",
+ " 'name': 'bwlimit1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'bwlimit2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Bandwidth limit channel 2',\n",
+ " 'name': 'bwlimit2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'channel_range1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Range channel 1',\n",
+ " 'name': 'channel_range1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'V',\n",
+ " 'value': 2.0},\n",
+ " 'channel_range2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Range channel 2',\n",
+ " 'name': 'channel_range2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'V',\n",
+ " 'value': 2.0},\n",
+ " 'channel_selection': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Channel Selection',\n",
+ " 'name': 'channel_selection',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'AB'},\n",
+ " 'clock_edge': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Clock Edge',\n",
+ " 'name': 'clock_edge',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'CLOCK_EDGE_RISING'},\n",
+ " 'clock_source': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Clock Source',\n",
+ " 'name': 'clock_source',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'INTERNAL_CLOCK'},\n",
+ " 'coupling1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Coupling channel 1',\n",
+ " 'name': 'coupling1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'AC'},\n",
+ " 'coupling2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Coupling channel 2',\n",
+ " 'name': 'coupling2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'AC'},\n",
+ " 'decimation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Decimation',\n",
+ " 'name': 'decimation',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 0},\n",
+ " 'enable_record_headers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Enable Record Headers',\n",
+ " 'name': 'enable_record_headers',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'external_startcapture': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'External Startcapture',\n",
+ " 'name': 'external_startcapture',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'ENABLED'},\n",
+ " 'external_trigger_coupling': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'External Trigger Coupling',\n",
+ " 'name': 'external_trigger_coupling',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'AC'},\n",
+ " 'external_trigger_range': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'External Trigger Range',\n",
+ " 'name': 'external_trigger_range',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'ETR_5V'},\n",
+ " 'fifo_only_streaming': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Fifo Only Streaming',\n",
+ " 'name': 'fifo_only_streaming',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'get_processed_data': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Get Processed Data',\n",
+ " 'name': 'get_processed_data',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'impedance1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Impedance channel 1',\n",
+ " 'name': 'impedance1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'Ohm',\n",
+ " 'value': 50},\n",
+ " 'impedance2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Impedance channel 2',\n",
+ " 'name': 'impedance2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'Ohm',\n",
+ " 'value': 50},\n",
+ " 'interleave_samples': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Interleave Samples',\n",
+ " 'name': 'interleave_samples',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLED'},\n",
+ " 'mode': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Acquisiton mode',\n",
+ " 'name': 'mode',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'NPT'},\n",
+ " 'records_per_buffer': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Records per Buffer',\n",
+ " 'name': 'records_per_buffer',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 70},\n",
+ " 'sample_rate': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Sample Rate',\n",
+ " 'name': 'sample_rate',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'S/s',\n",
+ " 'value': 100000000},\n",
+ " 'samples_per_record': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Samples per Record',\n",
+ " 'name': 'samples_per_record',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 1024},\n",
+ " 'timeout_ticks': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Timeout Ticks',\n",
+ " 'name': 'timeout_ticks',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '10 us',\n",
+ " 'value': 0},\n",
+ " 'transfer_offset': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Transer Offset',\n",
+ " 'name': 'transfer_offset',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'Samples',\n",
+ " 'value': 0},\n",
+ " 'trigger_delay': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Delay',\n",
+ " 'name': 'trigger_delay',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': 'Sample clock cycles',\n",
+ " 'value': 0},\n",
+ " 'trigger_engine1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Engine 1',\n",
+ " 'name': 'trigger_engine1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'TRIG_ENGINE_K'},\n",
+ " 'trigger_engine2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Engine 2',\n",
+ " 'name': 'trigger_engine2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'TRIG_ENGINE_K'},\n",
+ " 'trigger_level1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Level 1',\n",
+ " 'name': 'trigger_level1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 128},\n",
+ " 'trigger_level2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Level 2',\n",
+ " 'name': 'trigger_level2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 128},\n",
+ " 'trigger_operation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Operation',\n",
+ " 'name': 'trigger_operation',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'TRIG_ENGINE_OP_J'},\n",
+ " 'trigger_slope1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Slope 1',\n",
+ " 'name': 'trigger_slope1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'TRIG_SLOPE_POSITIVE'},\n",
+ " 'trigger_slope2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Slope 2',\n",
+ " 'name': 'trigger_slope2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'TRIG_SLOPE_POSITIVE'},\n",
+ " 'trigger_source1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Source 1',\n",
+ " 'name': 'trigger_source1',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'EXTERNAL'},\n",
+ " 'trigger_source2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
+ " 'label': 'Trigger Source 2',\n",
+ " 'name': 'trigger_source2',\n",
+ " 'ts': '2016-09-21 18:04:30',\n",
+ " 'units': '',\n",
+ " 'value': 'DISABLE'}}}"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# make a snapshot of the 'ats_inst' instrument\n",
+ "ats_inst.snapshot()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DataSet:\n",
+ " mode = DataMode.LOCAL\n",
+ " location = '2016-10-26/14-50-44_AlazarTest'\n",
+ " | | | \n",
+ " Setpoint | dummy_set | dummy | (50,)\n",
+ " Measured | acquisition_controller_acquisition | acquisition | (50,)\n",
+ "started at 2016-10-26 14:51:05\n"
+ ]
+ },
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support.' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " fig.waiting = false;\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " this.ws.close();\n",
+ " }\n",
+ "\n",
+ " this.ws.onmessage = this._make_on_message_function(this);\n",
+ "\n",
+ " this.ondownload = ondownload;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_header = function() {\n",
+ " var titlebar = $(\n",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\n",
+ " titlebar.append(titletext)\n",
+ " this.root.append(titlebar);\n",
+ " this.header = titletext[0];\n",
+ "}\n",
+ "\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_canvas = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var canvas_div = $('');\n",
+ "\n",
+ " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
+ "\n",
+ " function canvas_keyboard_event(event) {\n",
+ " return fig.key_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
+ " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
+ " this.canvas_div = canvas_div\n",
+ " this._canvas_extra_style(canvas_div)\n",
+ " this.root.append(canvas_div);\n",
+ "\n",
+ " var canvas = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width);\n",
+ " canvas.attr('height', height);\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('')\n",
+ " nav_element.attr('style', 'width: 100%');\n",
+ " this.root.append(nav_element);\n",
+ "\n",
+ " // Define a callback function for later on.\n",
+ " function toolbar_event(event) {\n",
+ " return fig.toolbar_button_onclick(event['data']);\n",
+ " }\n",
+ " function toolbar_mouse_event(event) {\n",
+ " return fig.toolbar_button_onmouseover(event['data']);\n",
+ " }\n",
+ "\n",
+ " for(var toolbar_ind in mpl.toolbar_items) {\n",
+ " var name = mpl.toolbar_items[toolbar_ind][0];\n",
+ " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
+ " var image = mpl.toolbar_items[toolbar_ind][2];\n",
+ " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
+ "\n",
+ " if (!name) {\n",
+ " // put a spacer in here.\n",
+ " continue;\n",
+ " }\n",
+ " var button = $('');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $('');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $('');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " '', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option)\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'];\n",
+ " var y0 = fig.canvas.height - msg['y0'];\n",
+ " var x1 = msg['x1'];\n",
+ " var y1 = fig.canvas.height - msg['y1'];\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x;\n",
+ " var y = canvas_pos.y;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('');\n",
+ " fig.send_message('closing', {});\n",
+ " fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('')\n",
+ " nav_element.attr('style', 'width: 100%');\n",
+ " this.root.append(nav_element);\n",
+ "\n",
+ " // Define a callback function for later on.\n",
+ " function toolbar_event(event) {\n",
+ " return fig.toolbar_button_onclick(event['data']);\n",
+ " }\n",
+ " function toolbar_mouse_event(event) {\n",
+ " return fig.toolbar_button_onmouseover(event['data']);\n",
+ " }\n",
+ "\n",
+ " for(var toolbar_ind in mpl.toolbar_items){\n",
+ " var name = mpl.toolbar_items[toolbar_ind][0];\n",
+ " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
+ " var image = mpl.toolbar_items[toolbar_ind][2];\n",
+ " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
+ "\n",
+ " if (!name) { continue; };\n",
+ "\n",
+ " var button = $('');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Close figure', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Finally show that this instrument also works within a loop\n",
+ "dummy = parameter.ManualParameter(name=\"dummy\")\n",
+ "data = qc.Loop(dummy[0:50:1]).each(acquisition_controller.acquisition).run(name='AlazarTest')\n",
+ "qc.MatPlot(data.acquisition_controller_acquisition)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "data"
+ ]
+ }
+ ],
+ "metadata": {
+ "anaconda-cloud": {},
+ "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.2"
+ },
+ "widgets": {
+ "state": {},
+ "version": "1.0.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example ATS_ONWORK.ipynb b/docs/examples/Qcodes example ATS_ONWORK.ipynb
deleted file mode 100644
index eac33345b0a..00000000000
--- a/docs/examples/Qcodes example ATS_ONWORK.ipynb
+++ /dev/null
@@ -1,1658 +0,0 @@
-{
- "cells": [
- {
- "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 = this;\r\n",
- " me._interval = 0;\r\n",
- " me._minimize = '';\r\n",
- " me._restore = '';\r\n",
- "\r\n",
- " // max lines of output to show\r\n",
- " me.maxOutputLength = 500;\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('.qcodes-process-list');\r\n",
- " me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
- " me.processLinesButton = me.$el.find('.qcodes-processlines')\r\n",
- "\r\n",
- " me.outputLines = [];\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.processLinesButton.click(function() {\r\n",
- " // toggle multiline process list display\r\n",
- " me.subprocessesMultiline = !me.subprocessesMultiline;\r\n",
- " me.showSubprocesses();\r\n",
- " });\r\n",
- "\r\n",
- " me.$el.find('.js-state').click(function() {\r\n",
- " var state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
- " .split('-')[1].split(' ')[0];\r\n",
- " me.model.set('_state', state);\r\n",
- " });\r\n",
- "\r\n",
- " $(window)\r\n",
- " .off('resize.qcodes')\r\n",
- " .on('resize.qcodes', function() {me.clipBounds();});\r\n",
- "\r\n",
- " me.update();\r\n",
- " },\r\n",
- "\r\n",
- " updateState: function() {\r\n",
- " var me = this,\r\n",
- " oldState = me.$el.attr('qcodes-state'),\r\n",
- " state = me.model.get('_state');\r\n",
- "\r\n",
- " if(state === oldState) return;\r\n",
- "\r\n",
- " setTimeout(function() {\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",
- " console.log('here');\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\r\n",
- " .draggable({stop: function() { me.clipBounds(); }})\r\n",
- " .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",
- " // any previous highlighting is now moot\r\n",
- " me.$el.removeClass('qcodes-highlight');\r\n",
- " }, 0);\r\n",
- "\r\n",
- " },\r\n",
- "\r\n",
- " clipBounds: function() {\r\n",
- " var me = this;\r\n",
- " if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
- " var bounds = me.$el[0].getBoundingClientRect(),\r\n",
- " minVis = 40,\r\n",
- " maxLeft = window.innerWidth - minVis,\r\n",
- " minLeft = minVis - bounds.width,\r\n",
- " maxTop = window.innerHeight - minVis;\r\n",
- "\r\n",
- " if(bounds.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
- " else if(bounds.left < minLeft) me.$el.css('left', minLeft);\r\n",
- "\r\n",
- " if(bounds.top > maxTop) me.$el.css('top', maxTop);\r\n",
- " else if(bounds.top < 0) me.$el.css('top', 0);\r\n",
- " }\r\n",
- " },\r\n",
- "\r\n",
- " display: function(message) {\r\n",
- " var me = this;\r\n",
- " if(message) {\r\n",
- " var initialScroll = me.outputArea.scrollTop();\r\n",
- " me.outputArea.scrollTop(me.outputArea.prop('scrollHeight'));\r\n",
- " var scrollBottom = me.outputArea.scrollTop();\r\n",
- "\r\n",
- " if(me.$el.attr('qcodes-state') === 'minimized') {\r\n",
- " // if we add text and the box is minimized, highlight the\r\n",
- " // title bar to alert the user that there are new messages.\r\n",
- " // remove then add the class, so we get the animation again\r\n",
- " // if it's already highlighted\r\n",
- " me.$el.removeClass('qcodes-highlight');\r\n",
- " setTimeout(function(){\r\n",
- " me.$el.addClass('qcodes-highlight');\r\n",
- " }, 0);\r\n",
- " }\r\n",
- "\r\n",
- " var newLines = message.split('\\n'),\r\n",
- " out = me.outputLines,\r\n",
- " outLen = out.length;\r\n",
- " if(outLen) out[outLen - 1] += newLines[0];\r\n",
- " else out.push(newLines[0]);\r\n",
- "\r\n",
- " for(var i = 1; i < newLines.length; i++) {\r\n",
- " out.push(newLines[i]);\r\n",
- " }\r\n",
- "\r\n",
- " if(out.length > me.maxOutputLength) {\r\n",
- " out.splice(0, out.length - me.maxOutputLength + 1,\r\n",
- " '<<< Output clipped >>>');\r\n",
- " }\r\n",
- "\r\n",
- " me.outputArea.text(out.join('\\n'));\r\n",
- " me.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",
- " me.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
- " me.outputArea.prop('scrollHeight') : initialScroll);\r\n",
- " }\r\n",
- "\r\n",
- " me.showSubprocesses();\r\n",
- " me.updateState();\r\n",
- " },\r\n",
- "\r\n",
- " showSubprocesses: function() {\r\n",
- " var me = this,\r\n",
- " replacer = me.subprocessesMultiline ? '
' : ', ',\r\n",
- " processes = (me.model.get('_processes') || '')\r\n",
- " .replace(/\\n/g, '>' + replacer + '<');\r\n",
- "\r\n",
- " if(processes) processes = '<' + processes + '>';\r\n",
- " else processes = 'No subprocesses';\r\n",
- "\r\n",
- " me.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
- "\r\n",
- " me.subprocessList.html(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"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "No loop running\n"
- ]
- }
- ],
- "source": [
- "# import all necessary things\n",
- "%matplotlib nbagg\n",
- "\n",
- "import qcodes as qc\n",
- "import qcodes.instrument.parameter as parameter\n",
- "import qcodes.instrument_drivers.AlazarTech.ATS9870 as ATSdriver\n",
- "import qcodes.instrument_drivers.AlazarTech.ATS_acquisition_controllers as ats_contr\n",
- "\n",
- "qc.halt_bg()\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": "code",
- "execution_count": 2,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[{'bits_per_sample': 8,\n",
- " 'board_id': 1,\n",
- " 'board_kind': 'ATS9870',\n",
- " 'max_samples': 4294966272,\n",
- " 'system_id': 1}]"
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Command to list all alazar boards connected to the system\n",
- "ATSdriver.AlazarTech_ATS.find_boards()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{'CPLD_version': '13.8',\n",
- " 'SDK_version': '5.10.15',\n",
- " 'asopc_type': '2435577968',\n",
- " 'driver_version': '5.10.15',\n",
- " 'firmware': None,\n",
- " 'latest_cal_date': '30-01-13',\n",
- " 'memory_size': '4294966272',\n",
- " 'model': 'ATS9870',\n",
- " 'pcie_link_speed': '0.25GB/s',\n",
- " 'pcie_link_width': '8',\n",
- " 'serial': '910266',\n",
- " 'vendor': 'AlazarTech'}"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Create the ATS9870 instrument on the new server \"alazar_server\"\n",
- "ats_inst = ATSdriver.AlazarTech_ATS9870(name='Alazar1', server_name=\"alazar_server\")\n",
- "# Print all information about this Alazar card\n",
- "ats_inst.get_idn()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "# Instantiate an acquisition controller (In this case we are doing a simple DFT) on the same server (\"alazar_server\") and \n",
- "# provide the name of the name of the alazar card that this controller should control\n",
- "acquisition_controller = ats_contr.Demodulation_AcquisitionController(name='acquisition_controller', \n",
- " demodulation_frequency=10e6, \n",
- " alazar_name='Alazar1', \n",
- " server_name=\"alazar_server\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "# Configure all settings in the Alazar card\n",
- "ats_inst.config(#clock_source='INTERNAL_CLOCK',\n",
- " sample_rate=100000000,\n",
- " #clock_edge='CLOCK_EDGE_RISING',\n",
- " #decimation=0,\n",
- " #coupling=['AC','AC'],\n",
- " channel_range=[2.,2.],\n",
- " #impedance=[50,50],\n",
- " #bwlimit=['DISABLED','DISABLED'],\n",
- " #trigger_operation='TRIG_ENGINE_OP_J',\n",
- " #trigger_engine1='TRIG_ENGINE_J',\n",
- " trigger_source1='EXTERNAL',\n",
- " #trigger_slope1='TRIG_SLOPE_POSITIVE',\n",
- " #trigger_level1=128,\n",
- " #trigger_engine2='TRIG_ENGINE_K',\n",
- " #trigger_source2='DISABLE',\n",
- " #trigger_slope2='TRIG_SLOPE_POSITIVE',\n",
- " #trigger_level2=128,\n",
- " #external_trigger_coupling='AC',\n",
- " #external_trigger_range='ETR_5V',\n",
- " #trigger_delay=0,\n",
- " #timeout_ticks=0\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "# This command is specific to this acquisition controller. The kwargs provided here are being forwarded to ats_inst.acquire\n",
- "# This way, it becomes easy to change acquisition specific settings from the ipython notebook\n",
- "acquisition_controller.update_acquisitionkwargs(#mode='NPT',\n",
- " samples_per_record=1024,\n",
- " records_per_buffer=70,\n",
- " buffers_per_acquisition=1,\n",
- " #channel_selection='AB',\n",
- " #transfer_offset=0,\n",
- " #external_startcapture='ENABLED',\n",
- " #enable_record_headers='DISABLED',\n",
- " #alloc_buffers='DISABLED',\n",
- " #fifo_only_streaming='DISABLED',\n",
- " #interleave_samples='DISABLED',\n",
- " #get_processed_data='DISABLED',\n",
- " allocated_buffers=1,\n",
- " #buffer_timeout=1000\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "0.1205605630942215"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Getting the value of the parameter 'acquisition' of the instrument 'acquisition_controller' performes the entire acquisition \n",
- "# protocol. This again depends on the specific implementation of the acquisition controller\n",
- "acquisition_controller.acquisition()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS9870.AlazarTech_ATS9870',\n",
- " 'functions': {},\n",
- " 'name': 'Alazar1',\n",
- " 'parameters': {'IDN': {'__class__': 'qcodes.instrument.parameter.StandardParameter',\n",
- " 'instrument': 'qcodes.instrument_drivers.AlazarTech.ATS9870.AlazarTech_ATS9870',\n",
- " 'instrument_name': 'Alazar1',\n",
- " 'label': 'IDN',\n",
- " 'name': 'IDN',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': {'CPLD_version': '13.8',\n",
- " 'SDK_version': '5.10.15',\n",
- " 'asopc_type': '2435577968',\n",
- " 'driver_version': '5.10.15',\n",
- " 'firmware': None,\n",
- " 'latest_cal_date': '30-01-13',\n",
- " 'memory_size': '4294966272',\n",
- " 'model': 'ATS9870',\n",
- " 'pcie_link_speed': '0.25GB/s',\n",
- " 'pcie_link_width': '8',\n",
- " 'serial': '910266',\n",
- " 'vendor': 'AlazarTech'}},\n",
- " 'alloc_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Alloc Buffers',\n",
- " 'name': 'alloc_buffers',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'allocated_buffers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Allocated Buffers',\n",
- " 'name': 'allocated_buffers',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 1},\n",
- " 'buffer_timeout': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Buffer Timeout',\n",
- " 'name': 'buffer_timeout',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'ms',\n",
- " 'value': 1000},\n",
- " 'buffers_per_acquisition': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Buffers per Acquisition',\n",
- " 'name': 'buffers_per_acquisition',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 1},\n",
- " 'bwlimit1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Bandwidth limit channel 1',\n",
- " 'name': 'bwlimit1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'bwlimit2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Bandwidth limit channel 2',\n",
- " 'name': 'bwlimit2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'channel_range1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Range channel 1',\n",
- " 'name': 'channel_range1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'V',\n",
- " 'value': 2.0},\n",
- " 'channel_range2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Range channel 2',\n",
- " 'name': 'channel_range2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'V',\n",
- " 'value': 2.0},\n",
- " 'channel_selection': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Channel Selection',\n",
- " 'name': 'channel_selection',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'AB'},\n",
- " 'clock_edge': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Clock Edge',\n",
- " 'name': 'clock_edge',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'CLOCK_EDGE_RISING'},\n",
- " 'clock_source': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Clock Source',\n",
- " 'name': 'clock_source',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'INTERNAL_CLOCK'},\n",
- " 'coupling1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Coupling channel 1',\n",
- " 'name': 'coupling1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'AC'},\n",
- " 'coupling2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Coupling channel 2',\n",
- " 'name': 'coupling2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'AC'},\n",
- " 'decimation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Decimation',\n",
- " 'name': 'decimation',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 0},\n",
- " 'enable_record_headers': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Enable Record Headers',\n",
- " 'name': 'enable_record_headers',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'external_startcapture': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'External Startcapture',\n",
- " 'name': 'external_startcapture',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'ENABLED'},\n",
- " 'external_trigger_coupling': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'External Trigger Coupling',\n",
- " 'name': 'external_trigger_coupling',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'AC'},\n",
- " 'external_trigger_range': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'External Trigger Range',\n",
- " 'name': 'external_trigger_range',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'ETR_5V'},\n",
- " 'fifo_only_streaming': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Fifo Only Streaming',\n",
- " 'name': 'fifo_only_streaming',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'get_processed_data': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Get Processed Data',\n",
- " 'name': 'get_processed_data',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'impedance1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Impedance channel 1',\n",
- " 'name': 'impedance1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'Ohm',\n",
- " 'value': 50},\n",
- " 'impedance2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Impedance channel 2',\n",
- " 'name': 'impedance2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'Ohm',\n",
- " 'value': 50},\n",
- " 'interleave_samples': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Interleave Samples',\n",
- " 'name': 'interleave_samples',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLED'},\n",
- " 'mode': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Acquisiton mode',\n",
- " 'name': 'mode',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'NPT'},\n",
- " 'records_per_buffer': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Records per Buffer',\n",
- " 'name': 'records_per_buffer',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 70},\n",
- " 'sample_rate': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Sample Rate',\n",
- " 'name': 'sample_rate',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'S/s',\n",
- " 'value': 100000000},\n",
- " 'samples_per_record': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Samples per Record',\n",
- " 'name': 'samples_per_record',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 1024},\n",
- " 'timeout_ticks': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Timeout Ticks',\n",
- " 'name': 'timeout_ticks',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '10 us',\n",
- " 'value': 0},\n",
- " 'transfer_offset': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Transer Offset',\n",
- " 'name': 'transfer_offset',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'Samples',\n",
- " 'value': 0},\n",
- " 'trigger_delay': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Delay',\n",
- " 'name': 'trigger_delay',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': 'Sample clock cycles',\n",
- " 'value': 0},\n",
- " 'trigger_engine1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Engine 1',\n",
- " 'name': 'trigger_engine1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'TRIG_ENGINE_K'},\n",
- " 'trigger_engine2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Engine 2',\n",
- " 'name': 'trigger_engine2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'TRIG_ENGINE_K'},\n",
- " 'trigger_level1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Level 1',\n",
- " 'name': 'trigger_level1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 128},\n",
- " 'trigger_level2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Level 2',\n",
- " 'name': 'trigger_level2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 128},\n",
- " 'trigger_operation': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Operation',\n",
- " 'name': 'trigger_operation',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'TRIG_ENGINE_OP_J'},\n",
- " 'trigger_slope1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Slope 1',\n",
- " 'name': 'trigger_slope1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'TRIG_SLOPE_POSITIVE'},\n",
- " 'trigger_slope2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Slope 2',\n",
- " 'name': 'trigger_slope2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'TRIG_SLOPE_POSITIVE'},\n",
- " 'trigger_source1': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Source 1',\n",
- " 'name': 'trigger_source1',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'EXTERNAL'},\n",
- " 'trigger_source2': {'__class__': 'qcodes.instrument_drivers.AlazarTech.ATS.AlazarParameter',\n",
- " 'label': 'Trigger Source 2',\n",
- " 'name': 'trigger_source2',\n",
- " 'ts': '2016-09-21 18:04:30',\n",
- " 'units': '',\n",
- " 'value': 'DISABLE'}}}"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# make a snapshot of the 'ats_inst' instrument\n",
- "ats_inst.snapshot()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "DataSet:\n",
- " mode = DataMode.PULL_FROM_SERVER\n",
- " location = '2016-09-21/18-04-30_AlazarTest'\n",
- " | | | \n",
- " Setpoint | dummy_set | dummy | (50,)\n",
- " Measured | acquisition_controller_acquisition | acquisition | (50,)\n",
- "started at 2016-09-21 18:04:31\n"
- ]
- },
- {
- "data": {
- "application/javascript": [
- "/* Put everything inside the global mpl namespace */\n",
- "window.mpl = {};\n",
- "\n",
- "mpl.get_websocket_type = function() {\n",
- " if (typeof(WebSocket) !== 'undefined') {\n",
- " return WebSocket;\n",
- " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
- " return MozWebSocket;\n",
- " } else {\n",
- " alert('Your browser does not have WebSocket support.' +\n",
- " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
- " 'Firefox 4 and 5 are also supported but you ' +\n",
- " 'have to enable WebSockets in about:config.');\n",
- " };\n",
- "}\n",
- "\n",
- "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
- " this.id = figure_id;\n",
- "\n",
- " this.ws = websocket;\n",
- "\n",
- " this.supports_binary = (this.ws.binaryType != undefined);\n",
- "\n",
- " if (!this.supports_binary) {\n",
- " var warnings = document.getElementById(\"mpl-warnings\");\n",
- " if (warnings) {\n",
- " warnings.style.display = 'block';\n",
- " warnings.textContent = (\n",
- " \"This browser does not support binary websocket messages. \" +\n",
- " \"Performance may be slow.\");\n",
- " }\n",
- " }\n",
- "\n",
- " this.imageObj = new Image();\n",
- "\n",
- " this.context = undefined;\n",
- " this.message = undefined;\n",
- " this.canvas = undefined;\n",
- " this.rubberband_canvas = undefined;\n",
- " this.rubberband_context = undefined;\n",
- " this.format_dropdown = undefined;\n",
- "\n",
- " this.image_mode = 'full';\n",
- "\n",
- " this.root = $('');\n",
- " this._root_extra_style(this.root)\n",
- " this.root.attr('style', 'display: inline-block');\n",
- "\n",
- " $(parent_element).append(this.root);\n",
- "\n",
- " this._init_header(this);\n",
- " this._init_canvas(this);\n",
- " this._init_toolbar(this);\n",
- "\n",
- " var fig = this;\n",
- "\n",
- " this.waiting = false;\n",
- "\n",
- " this.ws.onopen = function () {\n",
- " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
- " fig.send_message(\"send_image_mode\", {});\n",
- " fig.send_message(\"refresh\", {});\n",
- " }\n",
- "\n",
- " this.imageObj.onload = function() {\n",
- " if (fig.image_mode == 'full') {\n",
- " // Full images could contain transparency (where diff images\n",
- " // almost always do), so we need to clear the canvas so that\n",
- " // there is no ghosting.\n",
- " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
- " }\n",
- " fig.context.drawImage(fig.imageObj, 0, 0);\n",
- " };\n",
- "\n",
- " this.imageObj.onunload = function() {\n",
- " this.ws.close();\n",
- " }\n",
- "\n",
- " this.ws.onmessage = this._make_on_message_function(this);\n",
- "\n",
- " this.ondownload = ondownload;\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._init_header = function() {\n",
- " var titlebar = $(\n",
- " '');\n",
- " var titletext = $(\n",
- " '');\n",
- " titlebar.append(titletext)\n",
- " this.root.append(titlebar);\n",
- " this.header = titletext[0];\n",
- "}\n",
- "\n",
- "\n",
- "\n",
- "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
- "\n",
- "}\n",
- "\n",
- "\n",
- "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
- "\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._init_canvas = function() {\n",
- " var fig = this;\n",
- "\n",
- " var canvas_div = $('');\n",
- "\n",
- " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
- "\n",
- " function canvas_keyboard_event(event) {\n",
- " return fig.key_event(event, event['data']);\n",
- " }\n",
- "\n",
- " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
- " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
- " this.canvas_div = canvas_div\n",
- " this._canvas_extra_style(canvas_div)\n",
- " this.root.append(canvas_div);\n",
- "\n",
- " var canvas = $('');\n",
- " canvas.addClass('mpl-canvas');\n",
- " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
- "\n",
- " this.canvas = canvas[0];\n",
- " this.context = canvas[0].getContext(\"2d\");\n",
- "\n",
- " var rubberband = $('');\n",
- " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
- "\n",
- " var pass_mouse_events = true;\n",
- "\n",
- " canvas_div.resizable({\n",
- " start: function(event, ui) {\n",
- " pass_mouse_events = false;\n",
- " },\n",
- " resize: function(event, ui) {\n",
- " fig.request_resize(ui.size.width, ui.size.height);\n",
- " },\n",
- " stop: function(event, ui) {\n",
- " pass_mouse_events = true;\n",
- " fig.request_resize(ui.size.width, ui.size.height);\n",
- " },\n",
- " });\n",
- "\n",
- " function mouse_event_fn(event) {\n",
- " if (pass_mouse_events)\n",
- " return fig.mouse_event(event, event['data']);\n",
- " }\n",
- "\n",
- " rubberband.mousedown('button_press', mouse_event_fn);\n",
- " rubberband.mouseup('button_release', mouse_event_fn);\n",
- " // Throttle sequential mouse events to 1 every 20ms.\n",
- " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
- "\n",
- " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
- " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
- "\n",
- " canvas_div.on(\"wheel\", function (event) {\n",
- " event = event.originalEvent;\n",
- " event['data'] = 'scroll'\n",
- " if (event.deltaY < 0) {\n",
- " event.step = 1;\n",
- " } else {\n",
- " event.step = -1;\n",
- " }\n",
- " mouse_event_fn(event);\n",
- " });\n",
- "\n",
- " canvas_div.append(canvas);\n",
- " canvas_div.append(rubberband);\n",
- "\n",
- " this.rubberband = rubberband;\n",
- " this.rubberband_canvas = rubberband[0];\n",
- " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
- " this.rubberband_context.strokeStyle = \"#000000\";\n",
- "\n",
- " this._resize_canvas = function(width, height) {\n",
- " // Keep the size of the canvas, canvas container, and rubber band\n",
- " // canvas in synch.\n",
- " canvas_div.css('width', width)\n",
- " canvas_div.css('height', height)\n",
- "\n",
- " canvas.attr('width', width);\n",
- " canvas.attr('height', height);\n",
- "\n",
- " rubberband.attr('width', width);\n",
- " rubberband.attr('height', height);\n",
- " }\n",
- "\n",
- " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
- " // upon first draw.\n",
- " this._resize_canvas(600, 600);\n",
- "\n",
- " // Disable right mouse context menu.\n",
- " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
- " return false;\n",
- " });\n",
- "\n",
- " function set_focus () {\n",
- " canvas.focus();\n",
- " canvas_div.focus();\n",
- " }\n",
- "\n",
- " window.setTimeout(set_focus, 100);\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._init_toolbar = function() {\n",
- " var fig = this;\n",
- "\n",
- " var nav_element = $('')\n",
- " nav_element.attr('style', 'width: 100%');\n",
- " this.root.append(nav_element);\n",
- "\n",
- " // Define a callback function for later on.\n",
- " function toolbar_event(event) {\n",
- " return fig.toolbar_button_onclick(event['data']);\n",
- " }\n",
- " function toolbar_mouse_event(event) {\n",
- " return fig.toolbar_button_onmouseover(event['data']);\n",
- " }\n",
- "\n",
- " for(var toolbar_ind in mpl.toolbar_items) {\n",
- " var name = mpl.toolbar_items[toolbar_ind][0];\n",
- " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
- " var image = mpl.toolbar_items[toolbar_ind][2];\n",
- " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
- "\n",
- " if (!name) {\n",
- " // put a spacer in here.\n",
- " continue;\n",
- " }\n",
- " var button = $('');\n",
- " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
- " 'ui-button-icon-only');\n",
- " button.attr('role', 'button');\n",
- " button.attr('aria-disabled', 'false');\n",
- " button.click(method_name, toolbar_event);\n",
- " button.mouseover(tooltip, toolbar_mouse_event);\n",
- "\n",
- " var icon_img = $('');\n",
- " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
- " icon_img.addClass(image);\n",
- " icon_img.addClass('ui-corner-all');\n",
- "\n",
- " var tooltip_span = $('');\n",
- " tooltip_span.addClass('ui-button-text');\n",
- " tooltip_span.html(tooltip);\n",
- "\n",
- " button.append(icon_img);\n",
- " button.append(tooltip_span);\n",
- "\n",
- " nav_element.append(button);\n",
- " }\n",
- "\n",
- " var fmt_picker_span = $('');\n",
- "\n",
- " var fmt_picker = $('');\n",
- " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
- " fmt_picker_span.append(fmt_picker);\n",
- " nav_element.append(fmt_picker_span);\n",
- " this.format_dropdown = fmt_picker[0];\n",
- "\n",
- " for (var ind in mpl.extensions) {\n",
- " var fmt = mpl.extensions[ind];\n",
- " var option = $(\n",
- " '', {selected: fmt === mpl.default_extension}).html(fmt);\n",
- " fmt_picker.append(option)\n",
- " }\n",
- "\n",
- " // Add hover states to the ui-buttons\n",
- " $( \".ui-button\" ).hover(\n",
- " function() { $(this).addClass(\"ui-state-hover\");},\n",
- " function() { $(this).removeClass(\"ui-state-hover\");}\n",
- " );\n",
- "\n",
- " var status_bar = $('');\n",
- " nav_element.append(status_bar);\n",
- " this.message = status_bar[0];\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
- " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
- " // which will in turn request a refresh of the image.\n",
- " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.send_message = function(type, properties) {\n",
- " properties['type'] = type;\n",
- " properties['figure_id'] = this.id;\n",
- " this.ws.send(JSON.stringify(properties));\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.send_draw_message = function() {\n",
- " if (!this.waiting) {\n",
- " this.waiting = true;\n",
- " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
- " }\n",
- "}\n",
- "\n",
- "\n",
- "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
- " var format_dropdown = fig.format_dropdown;\n",
- " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
- " fig.ondownload(fig, format);\n",
- "}\n",
- "\n",
- "\n",
- "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
- " var size = msg['size'];\n",
- " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
- " fig._resize_canvas(size[0], size[1]);\n",
- " fig.send_message(\"refresh\", {});\n",
- " };\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
- " var x0 = msg['x0'];\n",
- " var y0 = fig.canvas.height - msg['y0'];\n",
- " var x1 = msg['x1'];\n",
- " var y1 = fig.canvas.height - msg['y1'];\n",
- " x0 = Math.floor(x0) + 0.5;\n",
- " y0 = Math.floor(y0) + 0.5;\n",
- " x1 = Math.floor(x1) + 0.5;\n",
- " y1 = Math.floor(y1) + 0.5;\n",
- " var min_x = Math.min(x0, x1);\n",
- " var min_y = Math.min(y0, y1);\n",
- " var width = Math.abs(x1 - x0);\n",
- " var height = Math.abs(y1 - y0);\n",
- "\n",
- " fig.rubberband_context.clearRect(\n",
- " 0, 0, fig.canvas.width, fig.canvas.height);\n",
- "\n",
- " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
- " // Updates the figure title.\n",
- " fig.header.textContent = msg['label'];\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
- " var cursor = msg['cursor'];\n",
- " switch(cursor)\n",
- " {\n",
- " case 0:\n",
- " cursor = 'pointer';\n",
- " break;\n",
- " case 1:\n",
- " cursor = 'default';\n",
- " break;\n",
- " case 2:\n",
- " cursor = 'crosshair';\n",
- " break;\n",
- " case 3:\n",
- " cursor = 'move';\n",
- " break;\n",
- " }\n",
- " fig.rubberband_canvas.style.cursor = cursor;\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
- " fig.message.textContent = msg['message'];\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
- " // Request the server to send over a new figure.\n",
- " fig.send_draw_message();\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
- " fig.image_mode = msg['mode'];\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.updated_canvas_event = function() {\n",
- " // Called whenever the canvas gets updated.\n",
- " this.send_message(\"ack\", {});\n",
- "}\n",
- "\n",
- "// A function to construct a web socket function for onmessage handling.\n",
- "// Called in the figure constructor.\n",
- "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
- " return function socket_on_message(evt) {\n",
- " if (evt.data instanceof Blob) {\n",
- " /* FIXME: We get \"Resource interpreted as Image but\n",
- " * transferred with MIME type text/plain:\" errors on\n",
- " * Chrome. But how to set the MIME type? It doesn't seem\n",
- " * to be part of the websocket stream */\n",
- " evt.data.type = \"image/png\";\n",
- "\n",
- " /* Free the memory for the previous frames */\n",
- " if (fig.imageObj.src) {\n",
- " (window.URL || window.webkitURL).revokeObjectURL(\n",
- " fig.imageObj.src);\n",
- " }\n",
- "\n",
- " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
- " evt.data);\n",
- " fig.updated_canvas_event();\n",
- " fig.waiting = false;\n",
- " return;\n",
- " }\n",
- " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
- " fig.imageObj.src = evt.data;\n",
- " fig.updated_canvas_event();\n",
- " fig.waiting = false;\n",
- " return;\n",
- " }\n",
- "\n",
- " var msg = JSON.parse(evt.data);\n",
- " var msg_type = msg['type'];\n",
- "\n",
- " // Call the \"handle_{type}\" callback, which takes\n",
- " // the figure and JSON message as its only arguments.\n",
- " try {\n",
- " var callback = fig[\"handle_\" + msg_type];\n",
- " } catch (e) {\n",
- " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
- " return;\n",
- " }\n",
- "\n",
- " if (callback) {\n",
- " try {\n",
- " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
- " callback(fig, msg);\n",
- " } catch (e) {\n",
- " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
- " }\n",
- " }\n",
- " };\n",
- "}\n",
- "\n",
- "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
- "mpl.findpos = function(e) {\n",
- " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
- " var targ;\n",
- " if (!e)\n",
- " e = window.event;\n",
- " if (e.target)\n",
- " targ = e.target;\n",
- " else if (e.srcElement)\n",
- " targ = e.srcElement;\n",
- " if (targ.nodeType == 3) // defeat Safari bug\n",
- " targ = targ.parentNode;\n",
- "\n",
- " // jQuery normalizes the pageX and pageY\n",
- " // pageX,Y are the mouse positions relative to the document\n",
- " // offset() returns the position of the element relative to the document\n",
- " var x = e.pageX - $(targ).offset().left;\n",
- " var y = e.pageY - $(targ).offset().top;\n",
- "\n",
- " return {\"x\": x, \"y\": y};\n",
- "};\n",
- "\n",
- "/*\n",
- " * return a copy of an object with only non-object keys\n",
- " * we need this to avoid circular references\n",
- " * http://stackoverflow.com/a/24161582/3208463\n",
- " */\n",
- "function simpleKeys (original) {\n",
- " return Object.keys(original).reduce(function (obj, key) {\n",
- " if (typeof original[key] !== 'object')\n",
- " obj[key] = original[key]\n",
- " return obj;\n",
- " }, {});\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.mouse_event = function(event, name) {\n",
- " var canvas_pos = mpl.findpos(event)\n",
- "\n",
- " if (name === 'button_press')\n",
- " {\n",
- " this.canvas.focus();\n",
- " this.canvas_div.focus();\n",
- " }\n",
- "\n",
- " var x = canvas_pos.x;\n",
- " var y = canvas_pos.y;\n",
- "\n",
- " this.send_message(name, {x: x, y: y, button: event.button,\n",
- " step: event.step,\n",
- " guiEvent: simpleKeys(event)});\n",
- "\n",
- " /* This prevents the web browser from automatically changing to\n",
- " * the text insertion cursor when the button is pressed. We want\n",
- " * to control all of the cursor setting manually through the\n",
- " * 'cursor' event from matplotlib */\n",
- " event.preventDefault();\n",
- " return false;\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
- " // Handle any extra behaviour associated with a key event\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.key_event = function(event, name) {\n",
- "\n",
- " // Prevent repeat events\n",
- " if (name == 'key_press')\n",
- " {\n",
- " if (event.which === this._key)\n",
- " return;\n",
- " else\n",
- " this._key = event.which;\n",
- " }\n",
- " if (name == 'key_release')\n",
- " this._key = null;\n",
- "\n",
- " var value = '';\n",
- " if (event.ctrlKey && event.which != 17)\n",
- " value += \"ctrl+\";\n",
- " if (event.altKey && event.which != 18)\n",
- " value += \"alt+\";\n",
- " if (event.shiftKey && event.which != 16)\n",
- " value += \"shift+\";\n",
- "\n",
- " value += 'k';\n",
- " value += event.which.toString();\n",
- "\n",
- " this._key_event_extra(event, name);\n",
- "\n",
- " this.send_message(name, {key: value,\n",
- " guiEvent: simpleKeys(event)});\n",
- " return false;\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
- " if (name == 'download') {\n",
- " this.handle_save(this, null);\n",
- " } else {\n",
- " this.send_message(\"toolbar_button\", {name: name});\n",
- " }\n",
- "};\n",
- "\n",
- "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
- " this.message.textContent = tooltip;\n",
- "};\n",
- "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
- "\n",
- "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
- "\n",
- "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
- " // Create a \"websocket\"-like object which calls the given IPython comm\n",
- " // object with the appropriate methods. Currently this is a non binary\n",
- " // socket, so there is still some room for performance tuning.\n",
- " var ws = {};\n",
- "\n",
- " ws.close = function() {\n",
- " comm.close()\n",
- " };\n",
- " ws.send = function(m) {\n",
- " //console.log('sending', m);\n",
- " comm.send(m);\n",
- " };\n",
- " // Register the callback with on_msg.\n",
- " comm.on_msg(function(msg) {\n",
- " //console.log('receiving', msg['content']['data'], msg);\n",
- " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
- " ws.onmessage(msg['content']['data'])\n",
- " });\n",
- " return ws;\n",
- "}\n",
- "\n",
- "mpl.mpl_figure_comm = function(comm, msg) {\n",
- " // This is the function which gets called when the mpl process\n",
- " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
- "\n",
- " var id = msg.content.data.id;\n",
- " // Get hold of the div created by the display call when the Comm\n",
- " // socket was opened in Python.\n",
- " var element = $(\"#\" + id);\n",
- " var ws_proxy = comm_websocket_adapter(comm)\n",
- "\n",
- " function ondownload(figure, format) {\n",
- " window.open(figure.imageObj.src);\n",
- " }\n",
- "\n",
- " var fig = new mpl.figure(id, ws_proxy,\n",
- " ondownload,\n",
- " element.get(0));\n",
- "\n",
- " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
- " // web socket which is closed, not our websocket->open comm proxy.\n",
- " ws_proxy.onopen();\n",
- "\n",
- " fig.parent_element = element.get(0);\n",
- " fig.cell_info = mpl.find_output_cell(\"\");\n",
- " if (!fig.cell_info) {\n",
- " console.error(\"Failed to find cell for figure\", id, fig);\n",
- " return;\n",
- " }\n",
- "\n",
- " var output_index = fig.cell_info[2]\n",
- " var cell = fig.cell_info[0];\n",
- "\n",
- "};\n",
- "\n",
- "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
- " fig.root.unbind('remove')\n",
- "\n",
- " // Update the output cell to use the data from the current canvas.\n",
- " fig.push_to_output();\n",
- " var dataURL = fig.canvas.toDataURL();\n",
- " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
- " // the notebook keyboard shortcuts fail.\n",
- " IPython.keyboard_manager.enable()\n",
- " $(fig.parent_element).html('');\n",
- " fig.close_ws(fig, msg);\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.close_ws = function(fig, msg){\n",
- " fig.send_message('closing', msg);\n",
- " // fig.ws.close()\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
- " // Turn the data on the canvas into data in the output cell.\n",
- " var dataURL = this.canvas.toDataURL();\n",
- " this.cell_info[1]['text/html'] = '';\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.updated_canvas_event = function() {\n",
- " // Tell IPython that the notebook contents must change.\n",
- " IPython.notebook.set_dirty(true);\n",
- " this.send_message(\"ack\", {});\n",
- " var fig = this;\n",
- " // Wait a second, then push the new image to the DOM so\n",
- " // that it is saved nicely (might be nice to debounce this).\n",
- " setTimeout(function () { fig.push_to_output() }, 1000);\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._init_toolbar = function() {\n",
- " var fig = this;\n",
- "\n",
- " var nav_element = $('')\n",
- " nav_element.attr('style', 'width: 100%');\n",
- " this.root.append(nav_element);\n",
- "\n",
- " // Define a callback function for later on.\n",
- " function toolbar_event(event) {\n",
- " return fig.toolbar_button_onclick(event['data']);\n",
- " }\n",
- " function toolbar_mouse_event(event) {\n",
- " return fig.toolbar_button_onmouseover(event['data']);\n",
- " }\n",
- "\n",
- " for(var toolbar_ind in mpl.toolbar_items){\n",
- " var name = mpl.toolbar_items[toolbar_ind][0];\n",
- " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
- " var image = mpl.toolbar_items[toolbar_ind][2];\n",
- " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
- "\n",
- " if (!name) { continue; };\n",
- "\n",
- " var button = $('');\n",
- " button.click(method_name, toolbar_event);\n",
- " button.mouseover(tooltip, toolbar_mouse_event);\n",
- " nav_element.append(button);\n",
- " }\n",
- "\n",
- " // Add the status bar.\n",
- " var status_bar = $('');\n",
- " nav_element.append(status_bar);\n",
- " this.message = status_bar[0];\n",
- "\n",
- " // Add the close button to the window.\n",
- " var buttongrp = $('');\n",
- " var button = $('');\n",
- " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
- " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
- " buttongrp.append(button);\n",
- " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
- " titlebar.prepend(buttongrp);\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._root_extra_style = function(el){\n",
- " var fig = this\n",
- " el.on(\"remove\", function(){\n",
- "\tfig.close_ws(fig, {});\n",
- " });\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._canvas_extra_style = function(el){\n",
- " // this is important to make the div 'focusable\n",
- " el.attr('tabindex', 0)\n",
- " // reach out to IPython and tell the keyboard manager to turn it's self\n",
- " // off when our div gets focus\n",
- "\n",
- " // location in version 3\n",
- " if (IPython.notebook.keyboard_manager) {\n",
- " IPython.notebook.keyboard_manager.register_events(el);\n",
- " }\n",
- " else {\n",
- " // location in version 2\n",
- " IPython.keyboard_manager.register_events(el);\n",
- " }\n",
- "\n",
- "}\n",
- "\n",
- "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
- " var manager = IPython.notebook.keyboard_manager;\n",
- " if (!manager)\n",
- " manager = IPython.keyboard_manager;\n",
- "\n",
- " // Check for shift+enter\n",
- " if (event.shiftKey && event.which == 13) {\n",
- " this.canvas_div.blur();\n",
- " event.shiftKey = false;\n",
- " // Send a \"J\" for go to next cell\n",
- " event.which = 74;\n",
- " event.keyCode = 74;\n",
- " manager.command_mode();\n",
- " manager.handle_keydown(event);\n",
- " }\n",
- "}\n",
- "\n",
- "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
- " fig.ondownload(fig, null);\n",
- "}\n",
- "\n",
- "\n",
- "mpl.find_output_cell = function(html_output) {\n",
- " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
- " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
- " // IPython event is triggered only after the cells have been serialised, which for\n",
- " // our purposes (turning an active figure into a static one), is too late.\n",
- " var cells = IPython.notebook.get_cells();\n",
- " var ncells = cells.length;\n",
- " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
- " data = data.data;\n",
- " }\n",
- " if (data['text/html'] == html_output) {\n",
- " return [cell, data, j];\n",
- " }\n",
- " }\n",
- " }\n",
- " }\n",
- "}\n",
- "\n",
- "// Register the function which deals with the matplotlib target/channel.\n",
- "// The kernel may be null if the page has been refreshed.\n",
- "if (IPython.notebook.kernel != null) {\n",
- " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
- "}\n"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/html": [
- ""
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Finally show that this instrument also works within a loop\n",
- "dummy = parameter.ManualParameter(name=\"dummy\")\n",
- "data = qc.Loop(dummy[0:50:1]).each(acquisition_controller.acquisition).run(name='AlazarTest')\n",
- "qc.MatPlot(data.acquisition_controller_acquisition)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "anaconda-cloud": {},
- "kernelspec": {
- "display_name": "Python [qcodes-env]",
- "language": "python",
- "name": "Python [qcodes-env]"
- },
- "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.2"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/docs/examples/Qcodes example with Alazar ATS9360.ipynb b/docs/examples/Qcodes example with Alazar ATS9360.ipynb
new file mode 100644
index 00000000000..cf493af6acd
--- /dev/null
+++ b/docs/examples/Qcodes example with Alazar ATS9360.ipynb
@@ -0,0 +1,923 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "deletable": true,
+ "editable": true
+ },
+ "source": [
+ "### Qcodes example notebook for Alazar card ATS9360 and acq controllers"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "No loop running\n"
+ ]
+ }
+ ],
+ "source": [
+ "import qcodes as qc\n",
+ "import qcodes.instrument.parameter as parameter\n",
+ "import qcodes.instrument_drivers.AlazarTech.ATS9360 as ATSdriver\n",
+ "import qcodes.instrument_drivers.AlazarTech.basic_controller as basic_aqc_contr\n",
+ "import qcodes.instrument_drivers.AlazarTech.samp_controller as samp_acq_contr\n",
+ "import qcodes.instrument_drivers.AlazarTech.ave_controller_test as ave_acq_controller\n",
+ "import qcodes.instrument_drivers.AlazarTech.rec_controller_test as record_acq_controller\n",
+ "\n",
+ "import logging\n",
+ "# logging.basicConfig(filename='example.log',level=logging.INFO)\n",
+ "\n",
+ "qc.halt_bg()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "deletable": true,
+ "editable": true
+ },
+ "source": [
+ "NB: See ATS9360 example notebook for general commands "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'CPLD_version': '25.16',\n",
+ " 'SDK_version': '5.9.25',\n",
+ " 'asopc_type': '1712554848',\n",
+ " 'bits_per_sample': 12,\n",
+ " 'driver_version': '5.9.25',\n",
+ " 'firmware': None,\n",
+ " 'latest_cal_date': '13-11-15',\n",
+ " 'max_samples': 4294967294,\n",
+ " 'memory_size': '4294967294',\n",
+ " 'model': 'ATS9360',\n",
+ " 'pcie_link_speed': '0.5GB/s',\n",
+ " 'pcie_link_width': '8',\n",
+ " 'serial': '970344',\n",
+ " 'vendor': 'AlazarTech'}"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Create the ATS9360 instrument\n",
+ "alazar = ATSdriver.AlazarTech_ATS9360(name='Alazar')\n",
+ "# Print all information about this Alazar card\n",
+ "alazar.get_idn()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# Configure all settings in the Alazar card\n",
+ "alazar.config(clock_source='EXTERNAL_CLOCK_10MHz_REF',\n",
+ " sample_rate=500000000,\n",
+ " clock_edge='CLOCK_EDGE_RISING',\n",
+ " decimation=1,\n",
+ " coupling=['DC','DC'],\n",
+ " channel_range=[.4,.4],\n",
+ " impedance=[50,50],\n",
+ " trigger_operation='TRIG_ENGINE_OP_J',\n",
+ " trigger_engine1='TRIG_ENGINE_J',\n",
+ " trigger_source1='EXTERNAL',\n",
+ " trigger_slope1='TRIG_SLOPE_POSITIVE',\n",
+ " trigger_level1=140,\n",
+ " trigger_engine2='TRIG_ENGINE_K',\n",
+ " trigger_source2='DISABLE',\n",
+ " trigger_slope2='TRIG_SLOPE_POSITIVE',\n",
+ " trigger_level2=128,\n",
+ " external_trigger_coupling='DC',\n",
+ " external_trigger_range='ETR_2V5',\n",
+ " trigger_delay=0,\n",
+ " timeout_ticks=0,\n",
+ " aux_io_mode='AUX_IN_AUXILIARY', # AUX_IN_TRIGGER_ENABLE for seq mode on\n",
+ " aux_io_param='NONE' # TRIG_SLOPE_POSITIVE for seq mode on\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "deletable": true,
+ "editable": true
+ },
+ "source": [
+ "### Basic Acquisition\n",
+ "\n",
+ "Pulls the raw data the alazar acquires averaged over number of records buffers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# Create the acquisition controller which will take care of the data handling and tell it which \n",
+ "# alazar instrument to talk to.\n",
+ "basic_acq_controller = basic_aqc_contr.Basic_Acquisition_Controller(name='basic_acq_controller', \n",
+ " alazar_name='Alazar')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# Configure settings in the controller to be used in an acquisition\n",
+ "# nb this must be done before the first acquisition \n",
+ "basic_acq_controller.update_acquisition_kwargs(samples_per_record=128*11,\n",
+ " records_per_buffer=100,\n",
+ " buffers_per_acquisition=1,\n",
+ " allocated_buffers=1\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(array([-0.00903541, -0.00757021, 0.0002442 , ..., 0.2014652 ,\n",
+ " 0.197558 , 0.1965812 ]), array([-0.0002442, 0.0007326, -0.0002442, ..., 0.0007326, -0.0002442,\n",
+ " 0.0007326]))\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Pull data from the card by calling get of the controllers acquisition parameter\n",
+ "data1 = basic_acq_controller.acquisition()\n",
+ "print(data1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DataSet:\n",
+ " mode = DataMode.LOCAL\n",
+ " location = '2017-01-23/18-17-17'\n",
+ " | | | \n",
+ " Measured | index0 | index0 | (1408,)\n",
+ " Measured | basic_acq_controller_A | A | (1408,)\n",
+ " Measured | basic_acq_controller_B | B | (1408,)\n",
+ "acquired at 2017-01-23 18:17:18\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Do this in as qcodes measurement (ie the same but makes a data set)\n",
+ "data2 = qc.Measure(basic_acq_controller.acquisition).run()\n",
+ "plot = qc.MatPlot(data2.basic_acq_controller_A)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\nbZkkw0sNkQAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "plot.fig\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": true,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "ename": "gaierror",
+ "evalue": "[Errno 11004] getaddrinfo failed",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mgaierror\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[1;31m# Do this in as qcodes measurement (ie the same but makes a data set)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[1;31m#data3 = qc.Measure(basic_acq_controller.acquisition).run()\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mplot\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbasic_acq_controller_B\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, figsize, interval, window_title, theme, show_window, remote, *args, **kwargs)\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mremote\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mproc\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m---> 54\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_init_qt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 55\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[1;31m# overrule the remote pyqtgraph class\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36m_init_qt\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 72\u001b[0m \u001b[1;31m# run, so this only starts once and stores the process in the class\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 73\u001b[0m \u001b[0mpg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmkQApp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m---> 74\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mproc\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpgmp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtProcess\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# pyqtgraph multiprocessing\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 75\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrpg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mproc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_import\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'pyqtgraph'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 76\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyqtgraph\\multiprocess\\processes.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, **kwds)\u001b[0m\n\u001b[1;32m 389\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_processRequests\u001b[0m \u001b[1;32mand\u001b[0m \u001b[0mQtGui\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQApplication\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 390\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Must create QApplication before starting QtProcess, or use QtProcess(processRequests=False)\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 391\u001b[0;31m \u001b[0mProcess\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 392\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstartEventTimer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 393\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyqtgraph\\multiprocess\\processes.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, name, target, executable, copySysPath, debug, timeout, wrapStdout)\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[1;31m#print \"key:\", ' '.join([str(ord(x)) for x in authkey])\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[1;31m## Listen for connection from remote process (and find free port number)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m---> 81\u001b[0;31m \u001b[0ml\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmultiprocessing\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mconnection\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mListener\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'localhost'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mauthkey\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mauthkey\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 82\u001b[0m \u001b[0mport\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0ml\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0maddress\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\multiprocessing\\connection.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, address, family, backlog, authkey)\u001b[0m\n\u001b[1;32m 436\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_listener\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mPipeListener\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maddress\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbacklog\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 437\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 438\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_listener\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSocketListener\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maddress\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfamily\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbacklog\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 439\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 440\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mauthkey\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m \u001b[1;32mand\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mauthkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbytes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\multiprocessing\\connection.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, address, family, backlog)\u001b[0m\n\u001b[1;32m 574\u001b[0m socket.SO_REUSEADDR, 1)\n\u001b[1;32m 575\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_socket\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetblocking\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 576\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_socket\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbind\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maddress\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 577\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_socket\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlisten\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbacklog\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 578\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_address\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_socket\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetsockname\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mgaierror\u001b[0m: [Errno 11004] getaddrinfo failed"
+ ]
+ }
+ ],
+ "source": [
+ "# Do this in as qcodes measurement (ie the same but makes a data set)\n",
+ "#data3 = qc.Measure(basic_acq_controller.acquisition).run()\n",
+ "plot = qc.QtPlot(data2.basic_acq_controller_B)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# Finally show that this instrument also works within a loop\n",
+ "dummy = parameter.ManualParameter(name=\"dummy\")\n",
+ "\n",
+ "data3 = qc.Loop(dummy[0:5:1]).each(basic_acq_controller.acquisition).run(name='AlazarTest')\n",
+ "qc.QtPlot(data3.basic_acq_controller_A)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "deletable": true,
+ "editable": true
+ },
+ "source": [
+ "### Samples Acquisition\n",
+ "\n",
+ "This is the same as above except that it does some demodulation at the freqiencies specified"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# Create the acquisition controller which will take care of the data handling and tell it which \n",
+ "# alazar instrument to talk to and does the demodulation and signal processing\n",
+ "samp_acq_controller = samp_acq_contr.HD_Samples_Controller(name='samp_acq_controller', \n",
+ " alazar_name='Alazar',\n",
+ " demod_length=2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "WARNING:root:delay is less than recommended for filter choice: (expect delay >= 2e-07)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# set the two demodulation frequencies\n",
+ "samp_acq_controller.demod_freq_0(1e6)\n",
+ "samp_acq_controller.demod_freq_1(2e6)\n",
+ "\n",
+ "# set integration time and delay (nb this replaces need to set samples_per record)\n",
+ "# if int_delay is unset it will default to a value corresponding to the about needed for the filter to work well\n",
+ "samp_acq_controller.int_time(10e-6)\n",
+ "samp_acq_controller.int_delay(0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "collapsed": true,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# to_default() can be used to reset int_delay to recommended filter value and int_time to use the maximum remaining time\n",
+ "# with the current number of samples_per_record\n",
+ "samp_acq_controller.int_time.to_default()\n",
+ "samp_acq_controller.int_delay.to_default()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# update_acquisition_kwargs now should not be used with samples_per_record but instead just for changing averaging values\n",
+ "samp_acq_controller.update_acquisition_kwargs(\n",
+ " records_per_buffer=100,\n",
+ " buffers_per_acquisition=100,\n",
+ " allocated_buffers=1\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# demodulation _frequencies can be changed\n",
+ "samp_acq_controller.demod_freq_0(10e6)\n",
+ "samp_acq_controller.demod_freq_1(20e6)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "8.192e-06"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "4096 / samp_acq_controller.sample_rate #samples_per_record"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# check the acquisition kwargs\n",
+ "samp_acq_controller.acquisition.acquisition_kwargs.update({'samples_per_record':5184})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "samp_acq_controller.samples_per_record=5184"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true,
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DataSet:\n",
+ " mode = DataMode.LOCAL\n",
+ " location = '2017-01-23/18-25-22'\n",
+ " | | | \n",
+ " Measured | index1 | index1 | (2, 5000)\n",
+ " Measured | samp_acq_controller_magnitude | magnitude | (2, 5000)\n",
+ " Measured | samp_acq_controller_phase | phase | (2, 5000)\n",
+ "acquired at 2017-01-23 18:25:23\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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\nAABJRU5ErkJggg==\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 48,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# as with basic...\n",
+ "# nb: index1 is actually the list demodulation frequency index but setpoints are ind of broken\n",
+ "data4 = qc.Measure(samp_acq_controller.acquisition).run()\n",
+ "plot = qc.MatPlot(data4.samp_acq_controller_magnitude[0])\n",
+ "plot.add(data4.samp_acq_controller_magnitude[1])\n",
+ "plot.fig"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 3.59998900e-07, 7.23784543e-07, 1.81824540e-06, ...,\n",
+ " 3.18445386e-04, 3.15040241e-04, 3.14722229e-04])"
+ ]
+ },
+ "execution_count": 35,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data4.samp_acq_controller_magnitude[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\nvP/9772fO7f8uk8+afM+/nj67b74oq33XnvZa23gQO/HjbP707+/XfeTn/T+X/+KrnPBBd6vv773\nixdXvk9Zliyx/VrfvrZvSHs8O+J73/O+Z097LLO0tHj/la94X1fn/QkneL/eevZ+n/a8pZkyxW7j\nkku8f+UVe3xuvdX+N26c9+us4/0HH6Rfd+lS799+u/Ly99139XOE997Pnu39kCHeb7ml94MG2b7p\n9dej/7e22nbUp4/dh549vf/4x+0nvIdnbQN//avNc+WVHVu3hQttvdJyQfDZz3p/5JGVl/PGG/ZY\nbbCB9zvuONlL8pKG+a7KiF11Q139U2v43XdfC4OrI2w8P/uZ98OHW9j75jftjamSDTe0Z+KII+zv\nf/7T/r7wwvL5Jk1qu5MYNszmve667OW3tEQ7maeeiqafemo0/Zln7DJsuPHwmxYGv/1tC/V77OH9\nMcdUvn9pfv3raPlhB3v99W2DUdy669r/W1ujMPjvf0f/X7rUpm2zjfebbVZ+3YULvT/uOO+nT7eg\nFW47/gYxeLBNmzCh+vvx/e/bda6+OpoWAmilAxLvvb/vvsr3N+7yy23e7363fHq4HwsX2t8//7n9\nXem1HA/N770XTf/lL23amDHpt9+rl/1//Pj219d77087LbqdV1+1aQ0N9pp58cXqlhH38su2rM03\nrzzfBx94/z//Y9tRZ5g9u3x7+Pzn7Y09bNfnn+/9RhvZNvHRj0bP6/rr2+Wdd6Yv94037P8DBtjf\njY0WZK67zrb9j3zEpn/9696PGFHduv7gB/Z+csop3m+1VRRMdt01en9JmjHD1uPPf46mHXKI93vu\nmX07ra02j2T3/d570+ebONHmef992/422SQK4K2t3j/xhPdvvtn+/bryStv+K4Wchx6y2/rrX9tf\nXtK//uXbBFLvbfuQ7H5U0tzs/cYbpx84hgO+8N7b1GQh9dxz7e/WVu93283/N6jGiwRnn22PWVaQ\n8d77n/zE+2239f7448sLLC0ttv4tLeXzz5hhr7Nrr618n5IWLbKDsu22s/B54onR+05nWLXKtqlw\ngPuHP7Sd54Ybyl+r//iHBeCvfz09hP/733bQcfbZ9t5z1FG2fwiP8d57R9vxF79oOWB1XHqprc+y\nZau3nDFj7P1j1ix7/9l+ewucb75pr6MvfMEeh8MPtwOkX//ano9jjsk+UIo791x7DdxxR23rtXSp\n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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "qc.MatPlot(data4.samp_acq_controller_magnitude[1]).fig"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DataSet:\n",
+ " mode = DataMode.LOCAL\n",
+ " location = '2017-01-23/15-55-55_AlazarTest'\n",
+ " | | | \n",
+ " Setpoint | samp_acq_controller_demod_freq_0_set | demod_freq_0 | (11,)\n",
+ " Measured | index1 | index1 | (11, 1, 3000)\n",
+ " Measured | samp_acq_controller_magnitude | magnitude | (11, 1, 3000)\n",
+ " Measured | samp_acq_controller_phase | phase | (11, 1, 3000)\n",
+ "started at 2017-01-23 15:56:04\n"
+ ]
+ }
+ ],
+ "source": [
+ "# in a loop\n",
+ "\n",
+ "data5 = qc.Loop(samp_acq_controller.demod_freq_0.sweep(1e6, 21e6, 2e6)).each(\n",
+ " samp_acq_controller.acquisition).run(name='AlazarTest')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "ename": "ConnectionResetError",
+ "evalue": "[WinError 10054] An existing connection was forcibly closed by the remote host",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mConnectionResetError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[1;31m# plotting the measured demodulated amplitude (samples on y axis, different freqs on x), only looking at the one we swept\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata5\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msamp_acq_controller_magnitude\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, figsize, interval, window_title, theme, show_window, remote, *args, **kwargs)\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[1;31m# overrule the remote pyqtgraph class\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrpg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpg\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrpg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mGraphicsWindow\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtitle\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mwindow_title\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 59\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetBackground\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtheme\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mresize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mfigsize\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyqtgraph\\multiprocess\\remoteproxy.py\u001b[0m in \u001b[0;36m__getattr__\u001b[0;34m(self, attr, **kwds)\u001b[0m\n\u001b[1;32m 895\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 896\u001b[0m \u001b[1;31m#opts = self._getProxyOptions()\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 897\u001b[0;31m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_handler\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetObjAttr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mopts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 898\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 899\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_deferredAttr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyqtgraph\\multiprocess\\remoteproxy.py\u001b[0m in \u001b[0;36mgetObjAttr\u001b[0;34m(self, obj, attr, **kwds)\u001b[0m\n\u001b[1;32m 530\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 531\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mgetObjAttr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 532\u001b[0;31m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'getObjAttr'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mopts\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mattr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 533\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 534\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mgetObjValue\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyqtgraph\\multiprocess\\remoteproxy.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, request, opts, reqId, callSync, timeout, returnType, byteData, **kwds)\u001b[0m\n\u001b[1;32m 450\u001b[0m \u001b[0mrequest\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreqId\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnByteMsgs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moptStr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 451\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdebugMsg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'send request: cmd=%s nByteMsgs=%d id=%s opts=%s'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrequest\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnByteMsgs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreqId\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mopts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 452\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mconn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrequest\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 453\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 454\u001b[0m \u001b[1;31m## follow up by sending byte messages\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\multiprocessing\\connection.py\u001b[0m in \u001b[0;36msend\u001b[0;34m(self, obj)\u001b[0m\n\u001b[1;32m 204\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_closed\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 205\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_writable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 206\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_send_bytes\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mForkingPickler\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdumps\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 207\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 208\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mrecv_bytes\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmaxlength\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\multiprocessing\\connection.py\u001b[0m in \u001b[0;36m_send_bytes\u001b[0;34m(self, buf)\u001b[0m\n\u001b[1;32m 402\u001b[0m \u001b[1;31m# Also note we want to avoid sending a 0-length buffer separately,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 403\u001b[0m \u001b[1;31m# to avoid \"broken pipe\" errors if the other end closed the pipe.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 404\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_send\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mheader\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mbuf\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 405\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 406\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_recv_bytes\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmaxsize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\multiprocessing\\connection.py\u001b[0m in \u001b[0;36m_send\u001b[0;34m(self, buf, write)\u001b[0m\n\u001b[1;32m 366\u001b[0m \u001b[0mremaining\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbuf\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 367\u001b[0m \u001b[1;32mwhile\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 368\u001b[0;31m \u001b[0mn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_handle\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbuf\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 369\u001b[0m \u001b[0mremaining\u001b[0m \u001b[1;33m-=\u001b[0m \u001b[0mn\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 370\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mremaining\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mConnectionResetError\u001b[0m: [WinError 10054] An existing connection was forcibly closed by the remote host"
+ ]
+ }
+ ],
+ "source": [
+ "# plotting the measured demodulated amplitude (samples on y axis, different freqs on x), only looking at the one we swept\n",
+ "qc.QtPlot(data5.samp_acq_controller_magnitude[:, 0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "deletable": true,
+ "editable": true
+ },
+ "source": [
+ "### Averaged Acquisition\n",
+ "\n",
+ "As above but averages over the samples to give one magnitude per demodulation frequency"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "ave_controller = ave_controller.HD_Averaging_Controller(name='ave_controller', \n",
+ " alazar_name='Alazar', \n",
+ " demod_length = 8)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "WARNING:root:delay is less than recommended for filter choice: (expect delay >= 2e-07)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# set the demodulation frequencies\n",
+ "samp_acq_controller.demod_freq_0(1e6)\n",
+ "samp_acq_controller.demod_freq_1(2e6)\n",
+ "samp_acq_controller.demod_freq_2(3e6)\n",
+ "samp_acq_controller.demod_freq_3(4e6)\n",
+ "samp_acq_controller.demod_freq_4(5e6)\n",
+ "samp_acq_controller.demod_freq_5(6e6)\n",
+ "samp_acq_controller.demod_freq_6(7e6)\n",
+ "samp_acq_controller.demod_freq_7(8e6)\n",
+ "\n",
+ "\n",
+ "# This command is specific to this acquisition controller. The kwargs provided here are being forwarded to ats_inst.acquire\n",
+ "# This way, it becomes easy to change acquisition specific settings from the ipython notebook\n",
+ "ave_controller.update_acquisition_kwargs(#mode='NPT',\n",
+ " records_per_buffer=1,\n",
+ " buffers_per_acquisition=1,\n",
+ " allocated_buffers=1,\n",
+ ")\n",
+ "\n",
+ "# set integration time and delay (nb this replaces need to set samples_per record)\n",
+ "# if int_delay is unset it will default to a value corresponding to the about needed for the filter to work well\n",
+ "ave_controller.int_time(2e-6)\n",
+ "ave_controller.int_delay(0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'allocated_buffers': 1,\n",
+ " 'buffers_per_acquisition': 1,\n",
+ " 'records_per_buffer': 1,\n",
+ " 'samples_per_record': 1024}"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ave_controller.acquisition.acquisition_kwargs"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DataSet:\n",
+ " mode = DataMode.LOCAL\n",
+ " location = '2017-01-23/10-51-30'\n",
+ " | | | \n",
+ " Measured | index0 | index0 | (8,)\n",
+ " Measured | ave_controller_magnitude | magnitude | (8,)\n",
+ " Measured | ave_controller_phase | phase | (8,)\n",
+ "acquired at 2017-01-23 10:51:31\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# as with basic...\n",
+ "# nb: index1 is actually the list demodulation frequency index but setpoints are ind of broken\n",
+ "data6 = qc.Measure(ave_controller.acquisition).run()\n",
+ "qc.QtPlot(data6.ave_controller_magnitude)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "deletable": true,
+ "editable": true
+ },
+ "source": [
+ "### Records Acquisition\n",
+ "\n",
+ "As above but doesnt average over records so is useful with seq mode on"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# Configure settings on Alazar card for sequencing mode (ie use aux i/o for triggering as well)\n",
+ "ats_inst.config(aux_io_mode='AUX_IN_TRIGGER_ENABLE', \n",
+ " aux_io_param='TRIG_SLOPE_POSITIVE')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "rec_controller = record_controller.HD_Records_Controller(name='rec_controller', \n",
+ " alazar_name='Alazar', \n",
+ " demod_length = 4)\n",
+ "rec_controller.demod_freq_0(1e6)\n",
+ "rec_controller.demod_freq_1(4e6)\n",
+ "rec_controller.demod_freq_2(8e6)\n",
+ "rec_controller.demod_freq_3(12e6)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [],
+ "source": [
+ "# This command is specific to this acquisition controller. The kwargs provided here are being forwarded to \n",
+ "# ats_inst.acquire. This way, it becomes easy to change acquisition specific settings from the ipython notebook\n",
+ "rec_controller.update_acquisition_kwargs(#mode='NPT',\n",
+ " buffers_per_acquisition=100,\n",
+ " allocated_buffers=1,\n",
+ ")\n",
+ "\n",
+ "# records_num a parameter of the records acq controller which is mainly a move towards having the \n",
+ "# setpoints in the record direction be settable by the user and also to make it easier to write wrapper functions\n",
+ "# which change it when there is an AWG upload, (replaces need to set records_per_buffer)\n",
+ "rec_controller.record_num(20)\n",
+ "\n",
+ "# set integration time and delay (nb this replaces need to set samples_per record)\n",
+ "# if int_delay is unset it will default to a value corresponding to the about needed for the filter to work well\n",
+ "rec_controller.int_time(2e-6)\n",
+ "rec_controller.int_delay.to_default()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false,
+ "deletable": true,
+ "editable": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DataSet:\n",
+ " mode = DataMode.LOCAL\n",
+ " location = '2017-01-23/10-58-35'\n",
+ " | | | \n",
+ " Measured | index1 | index1 | (4, 20)\n",
+ " Measured | rec_controller_magnitude | magnitude | (4, 20)\n",
+ " Measured | rec_controller_phase | phase | (4, 20)\n",
+ "acquired at 2017-01-23 10:58:36\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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\nepea3q5na9WBe4uSrwN+Ny4wKdKK+2im5MLQKTkNoNSazeakTwEovdMySZZdvAt8sOraxs5h1eWN\nrH8a5MC9hzNkImrJZm9I5Mkt43VJs2gmEtznut2J1AUAgCGSJDlHj/sZYf18S+x9rTLXr899JPdz\n/1PEuPJ2iVfcAQDgpDNbZXItwA/N93rcAQDgEg1tf++t1vfdbHVKpsq4AdP5tBpJT6M16VMZs05a\nP/zSknraGX58ObUas/jl3fupnLWv7P7P5Ix9Za3G/S9o9t5Sjn11s/aucvwbd7RpNr62B7+0mXpL\nGfgDWfKvbMCfrNl7J7l0u4Mcvx/T0eNk3HcDptI4+wa/5da5Pb+RNasR0Wok62nSrBV5EXghWo2k\nGct57tBWJq1GcvhTOWM66fr2jTRrVmbqR7Lv/t4z9pbSf/fyGXpXGXhj9tl4S+n/0mboLeXBL22G\n3lJO/Mm6+uJMvZMU45TV9wG9NFOy4i64n0NrZ2t5aS2idwvf7f1OVMv6x/6k6tra4UeVa2X/i2iQ\nTlpvXkubSVZfn/SpjFVrZ28lbc74m/QM/UhWas0sSe/9EM7aW8qDX91Mvav0f2kz9JbS96XN0lvK\nye/avR0l/3ns/5M1a+8klyfnkJm+Hndz3GfCxW7hO9U62XbcWJ+tL6yT1tdjvVmrRKl/PTpAa2er\nvbWVbEZExGXM0pqcSq1ZbxxOE1tYSZuz9SN5wgy/pcQMvqt4SymhWXxLufcn6/bRltl+J8ln7FNl\npoTgzkCtRm37xmy8o93Xybbb7Xbt8O+iiFo90vL+krTfvb9bZ+5XpPfaSDppvbb5Yqs2O1/Zw2b2\n3lW8pZTSzL2lHP3J0tb+gONtLX0hvu+q0yOjBnor7iVU+C18C9FqJM1rM/T3zz2VWjOr9T68v1A2\nc2bsV6SdtLm3sr4WEZVaM436etqpzuK37Z7ZfEuJGX1X8ZZSQrP2lnLKn6yZfSc5p3x3UY2zx0Se\n7HGfSHA3VeYcqkvLWzutiN56y/zVEv+RP6mT1mfw79eZV11a3mr2pgrM2A9l5ep8e/PF3kLSjH1p\n9830W0p4Vykjbyll0P8na9bfSS7f4pkmfXaHrLifx9k3+C21Trbdjvu/+11Y8ZdtOVTX0v1679u2\nMDOXlEVERHUtXanX7jekzsaX1n9/79l6S+n76m7uz867ymXfmH2CTvxMzs5bSv+XNitvKQP+vp6t\nd5LpN5EV97lx3YIVAADGK0mSW7eyi7/O9etzX/nK+UNvX6vM9etzP5j7uX8VMa68bcUdAIDZd/36\nXEQMjO85Z0QeZ447AAA84M6df3rBV3jmmecj4pVXPhP34nvv4yMf+Uie03jg04kEd60yAABMqSRJ\nsmwMrTJzc3O9D1555TO9HH+RDDw3N/e3ch/8Da0yAACQUy86z83NPfPM873l9l6UP3ek1ioDAACX\n5Si+x71umXPHd8EdAAAuV198f+aZ588R3905FQAAitDtdo93zvTie/7sLrgDAEBBxtg5MxZ37959\n5JFHzjhAcAcA4OF1vvg+9mj/xhtv/OVf/uWP//iPn3HMlXEXBQCAkul2u91u95lnnj8+duZoiORJ\nB7kfQ33rW9/64z/+449//OO/9Vu/dfaRgjsAAETcW2XvZffjq+8Djsz9OMPbb7/93e9+97Of/exT\nTz31h3/4h0NPT6sMAAAcytk5c8GLUw8ODr73ve/9+q//+i/+4i/mf5bgDgAADxga3y8S3F9//fUv\nf/nLn/rUp/76r/96pCcK7gCj66T19Vhv1iqTPhEALs9pE9/jvBenvvnmm9/85jdv3rz5+7//++d4\nuh53gAd10no97Yz/dVuNS3lZAC7Xycb3iHg39yMi5ubmvve97929e3d1dfXDH/7w+VJ7WHEH6Fep\nNZtjfslOWq9ttmNh5eaYXxiAIpzsnBnJM888/+KLL/7cz/3cBU9DcAd4UK8NZj3W1+PG/ObmVkTE\n8ka2Vj0K4BERsbByePDhloWVtFmrtBrJ6t5K2qxVopPWa9s30matEpVaM0vS+vqEviIAxuF4fB/V\nxVN7aJUBOFV78/ZSlmVZtrG81Uw70WrUNuc3sizLsnRlISKi1ajdrme9LTe219NOVNfSldh8sRWd\ndP0wtQMwS3rxvZvbwcHBm2+++Ru/8RsXLy24A5xiYeVmNSIiKtcWIqKzv3e0paezvxdbq0mSJElS\n22y3b3ciolJbX9lbTWrbN9aldoCZdPZNVfvMzc09/vjjn/70p999993PfvazF6mrVQbgAnoNMg9u\nq1ydj2hP5nwAmErvec97IuJXfuVXPve5z928efP3fu/3zvEiVtwB8qlcnW9vZ52IiE623T7csvli\nq++4VmM1NrKN+c11Q2QAOO6JJ56oVCpf+MIXXn755Q996EOjPl1wB8ipurYxv1lLkiRZvz2/0NuS\nruwd9sokST3tRKuRrMbGWvXw4EYv1XfSelLbbLc3a0nS6A/6ADxcnnzyyY9//ON/9md/9qu/+qsj\nPXFupB4dAAAoTJIkWZZN+iwuy9tvvx0RP//zP//5z38+In75l395fX39jOOtuAMAwAS8733ve9/7\n3nfr1q0/+ZM/+ehHPzr0eBenAgDAxHzwgx/84Ac/+PLLL3/9618/+0itMgAAMHl379595JFHzjhA\ncAcAgBLQ4w4AACUguAMAQAkI7gAAUAKCOwAAlIDgDgAAJSC4AwBACQjuAABQAv8/BROcwhcddQgA\nAAAASUVORK5CYII=\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "data7 = qc.Measure(rec_controller.acquisition).run()\n",
+ "qc.QtPlot(data7.rec_controller_magnitude)"
+ ]
+ }
+ ],
+ "metadata": {
+ "anaconda-cloud": {},
+ "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.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Tektronix AWG5014C.ipynb b/docs/examples/Qcodes example with Tektronix AWG5014C.ipynb
new file mode 100644
index 00000000000..fbd09310add
--- /dev/null
+++ b/docs/examples/Qcodes example with Tektronix AWG5014C.ipynb
@@ -0,0 +1,1325 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "%matplotlib nbagg\n",
+ "\n",
+ "import os\n",
+ "import time\n",
+ "import logging\n",
+ "\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "logger = logging.getLogger()\n",
+ "logger.setLevel(logging.INFO)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "6.0"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "np.ceil(26/5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "ename": "VisaIOError",
+ "evalue": "VI_ERROR_RSRC_NFOUND (-1073807343): Insufficient location information or the requested device or resource is not present in the system.",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mVisaIOError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mqcodes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minstrument_drivers\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtektronix\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mAWGFileParser\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mparse_awg_file\u001b[0m \u001b[1;31m# <--- A helper function\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mawg1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mawg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTektronix_AWG5014\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'AWG1'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'TCPIP0::192.168.137.182::inst0::INSTR'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m40\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\instrument\\metaclass.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(cls, server_name, *args, **kwargs)\u001b[0m\n\u001b[1;32m 32\u001b[0m \"\"\"\n\u001b[1;32m 33\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mserver_name\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m---> 34\u001b[0;31m \u001b[0minstrument\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__call__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 35\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m warnings.warn('Multiprocessing is in beta, use at own risk',\n",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\instrument_drivers\\tektronix\\AWG5014.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, name, address, timeout, **kwargs)\u001b[0m\n\u001b[1;32m 137\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 138\u001b[0m \"\"\"\n\u001b[0;32m--> 139\u001b[0;31m \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maddress\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 140\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 141\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\instrument\\visa.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, name, address, timeout, terminator, **kwargs)\u001b[0m\n\u001b[1;32m 54\u001b[0m vals.Enum(None)))\n\u001b[1;32m 55\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m---> 56\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset_address\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maddress\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 57\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset_terminator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mterminator\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 58\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32ma:\\qcodes\\qcodes\\instrument\\visa.py\u001b[0m in \u001b[0;36mset_address\u001b[0;34m(self, address)\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[0mresource_manager\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvisa\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mResourceManager\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 103\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvisa_handle\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mresource_manager\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mopen_resource\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maddress\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 104\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvisa_handle\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mclear\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyvisa\\highlevel.py\u001b[0m in \u001b[0;36mopen_resource\u001b[0;34m(self, resource_name, access_mode, open_timeout, resource_pyclass, **kwargs)\u001b[0m\n\u001b[1;32m 1642\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'%r is not a valid attribute for type %s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mres\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__name__\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 1643\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1644\u001b[0;31m \u001b[0mres\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maccess_mode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mopen_timeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1645\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 1646\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyvisa\\resources\\resource.py\u001b[0m in \u001b[0;36mopen\u001b[0;34m(self, access_mode, open_timeout)\u001b[0m\n\u001b[1;32m 201\u001b[0m \u001b[0mlogger\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdebug\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'%s - opening ...'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_resource_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mextra\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_logging_extra\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 202\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_resource_manager\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mignore_warning\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconstants\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mVI_SUCCESS_DEV_NPRESENT\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 203\u001b[0;31m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msession\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstatus\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_resource_manager\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mopen_bare_resource\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_resource_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maccess_mode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mopen_timeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 204\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 205\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mstatus\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mconstants\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mVI_SUCCESS_DEV_NPRESENT\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyvisa\\highlevel.py\u001b[0m in \u001b[0;36mopen_bare_resource\u001b[0;34m(self, resource_name, access_mode, open_timeout)\u001b[0m\n\u001b[1;32m 1599\u001b[0m \u001b[1;33m:\u001b[0m\u001b[1;32mreturn\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mUnique\u001b[0m \u001b[0mlogical\u001b[0m \u001b[0midentifier\u001b[0m \u001b[0mreference\u001b[0m \u001b[0mto\u001b[0m \u001b[0ma\u001b[0m \u001b[0msession\u001b[0m\u001b[1;33m.\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 1600\u001b[0m \"\"\"\n\u001b[0;32m-> 1601\u001b[0;31m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvisalib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msession\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mresource_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maccess_mode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mopen_timeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1602\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 1603\u001b[0m def open_resource(self, resource_name,\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyvisa\\ctwrapper\\functions.py\u001b[0m in \u001b[0;36mopen\u001b[0;34m(library, session, resource_name, access_mode, open_timeout)\u001b[0m\n\u001b[1;32m 1209\u001b[0m \u001b[1;31m# [ViSession, ViRsrc, ViAccessMode, ViUInt32, ViPSession]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 1210\u001b[0m \u001b[1;31m# ViRsrc converts from (str, unicode, bytes) to bytes\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1211\u001b[0;31m \u001b[0mret\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlibrary\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mviOpen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msession\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mresource_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0maccess_mode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mopen_timeout\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mbyref\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mout_session\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1212\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mout_session\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mret\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 1213\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32mc:\\users\\triton2acq\\anaconda3\\envs\\qcodes-master\\lib\\site-packages\\pyvisa\\ctwrapper\\highlevel.py\u001b[0m in \u001b[0;36m_return_handler\u001b[0;34m(self, ret_value, func, arguments)\u001b[0m\n\u001b[1;32m 186\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mret_value\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 188\u001b[0;31m \u001b[1;32mraise\u001b[0m \u001b[0merrors\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mVisaIOError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mret_value\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 189\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mret_value\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0missue_warning_on\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mVisaIOError\u001b[0m: VI_ERROR_RSRC_NFOUND (-1073807343): Insufficient location information or the requested device or resource is not present in the system."
+ ]
+ }
+ ],
+ "source": [
+ "import qcodes.instrument_drivers.tektronix.AWG5014 as awg # <--- The instrument driver\n",
+ "from qcodes.instrument_drivers.tektronix.AWGFileParser import parse_awg_file # <--- A helper function\n",
+ "\n",
+ "awg1 = awg.Tektronix_AWG5014('AWG1', 'TCPIP0::192.168.137.182::inst0::INSTR', timeout=40)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Note: if you have had any initialisation problems, the VISA message queue of the instrument could be fouled up\n",
+ "#(e.g. if the cell above gave you back something like 'Connected to: 1.20000000E+009 ...')\n",
+ "# in that case, run the following command to reset the message queue\n",
+ "awg1.clear_message_queue()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As with any other QCoDeS instrument, parameters can be set and get (gotten)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0\n",
+ "\n",
+ "0.0\n",
+ "0.1\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(awg1.ch3_state.get())\n",
+ "print(awg1.ch2_offset.get())\n",
+ "awg1.ch2_offset.set(0.1)\n",
+ "print(awg1.ch2_offset.get())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A list of all available parameters can be found in the following manner:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "DC_output : DC Output (ON/OFF)\n",
+ "IDN : IDN\n",
+ "ch1_DC_out : DC output level channel 1\n",
+ "ch1_add_input : Add input channel {}\n",
+ "ch1_amp : Amplitude channel 1 (Vpp)\n",
+ "ch1_direct_output : Direct output channel 1\n",
+ "ch1_filter : Low pass filter channel 1\n",
+ "ch1_m1_del : Channel 1 Marker 1 delay (ns)\n",
+ "ch1_m1_high : Channel 1 Marker 1 high level (V)\n",
+ "ch1_m1_low : Channel 1 Marker 1 low level (V)\n",
+ "ch1_m2_del : Channel 1 Marker 2 delay (ns)\n",
+ "ch1_m2_high : Channel 1 Marker 2 high level (V)\n",
+ "ch1_m2_low : Channel 1 Marker 2 low level (V)\n",
+ "ch1_offset : Offset channel 1 (V)\n",
+ "ch1_state : Status channel 1\n",
+ "ch1_waveform : Waveform channel 1\n",
+ "ch2_DC_out : DC output level channel 2\n",
+ "ch2_add_input : Add input channel {}\n",
+ "ch2_amp : Amplitude channel 2 (Vpp)\n",
+ "ch2_direct_output : Direct output channel 2\n",
+ "ch2_filter : Low pass filter channel 2\n",
+ "ch2_m1_del : Channel 2 Marker 1 delay (ns)\n",
+ "ch2_m1_high : Channel 2 Marker 1 high level (V)\n",
+ "ch2_m1_low : Channel 2 Marker 1 low level (V)\n",
+ "ch2_m2_del : Channel 2 Marker 2 delay (ns)\n",
+ "ch2_m2_high : Channel 2 Marker 2 high level (V)\n",
+ "ch2_m2_low : Channel 2 Marker 2 low level (V)\n",
+ "ch2_offset : Offset channel 2 (V)\n",
+ "ch2_state : Status channel 2\n",
+ "ch2_waveform : Waveform channel 2\n",
+ "ch3_DC_out : DC output level channel 3\n",
+ "ch3_add_input : Add input channel {}\n",
+ "ch3_amp : Amplitude channel 3 (Vpp)\n",
+ "ch3_direct_output : Direct output channel 3\n",
+ "ch3_filter : Low pass filter channel 3\n",
+ "ch3_m1_del : Channel 3 Marker 1 delay (ns)\n",
+ "ch3_m1_high : Channel 3 Marker 1 high level (V)\n",
+ "ch3_m1_low : Channel 3 Marker 1 low level (V)\n",
+ "ch3_m2_del : Channel 3 Marker 2 delay (ns)\n",
+ "ch3_m2_high : Channel 3 Marker 2 high level (V)\n",
+ "ch3_m2_low : Channel 3 Marker 2 low level (V)\n",
+ "ch3_offset : Offset channel 3 (V)\n",
+ "ch3_state : Status channel 3\n",
+ "ch3_waveform : Waveform channel 3\n",
+ "ch4_DC_out : DC output level channel 4\n",
+ "ch4_add_input : Add input channel {}\n",
+ "ch4_amp : Amplitude channel 4 (Vpp)\n",
+ "ch4_direct_output : Direct output channel 4\n",
+ "ch4_filter : Low pass filter channel 4\n",
+ "ch4_m1_del : Channel 4 Marker 1 delay (ns)\n",
+ "ch4_m1_high : Channel 4 Marker 1 high level (V)\n",
+ "ch4_m1_low : Channel 4 Marker 1 low level (V)\n",
+ "ch4_m2_del : Channel 4 Marker 2 delay (ns)\n",
+ "ch4_m2_high : Channel 4 Marker 2 high level (V)\n",
+ "ch4_m2_low : Channel 4 Marker 2 low level (V)\n",
+ "ch4_offset : Offset channel 4 (V)\n",
+ "ch4_state : Status channel 4\n",
+ "ch4_waveform : Waveform channel 4\n",
+ "clock_freq : Clock frequency (Hz)\n",
+ "event_impedance : Event impedance (Ohm)\n",
+ "event_jump_timing : event_jump_timing\n",
+ "event_level : Event level (V)\n",
+ "event_polarity : event_polarity\n",
+ "ref_clock_source : Reference clock source\n",
+ "run_mode : run_mode\n",
+ "sequence_length : Sequence length\n",
+ "setup_filename : setup_filename\n",
+ "state : state\n",
+ "timeout : timeout\n",
+ "trigger_impedance : Trigger impedance (Ohm)\n",
+ "trigger_level : Trigger level (V)\n",
+ "trigger_mode : trigger_mode\n",
+ "trigger_slope : trigger_slope\n",
+ "trigger_source : trigger_source\n"
+ ]
+ }
+ ],
+ "source": [
+ "pars = np.sort(list(awg1.parameters.keys()))\n",
+ "for param in pars:\n",
+ " print(param, ': ', awg1.parameters[param].label)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false
+ },
+ "source": [
+ "## SENDING WAVEFORMS\n",
+ "\n",
+ "There are two supported ways of sending waveforms to the AWG; by making an .awg file, sending and loading that, or by sending waveforms to the User Defined list one by one and putting them in the sequencer. The first method is generally faster."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false
+ },
+ "source": [
+ "### MAKING SOME WAVEFORMS\n",
+ "\n",
+ "First, we make a handful of pulse shapes and marker signals to send to the AWG. This should be done with numpy arrays.\n",
+ "\n",
+ "Please note that the waveforms must **not** have values exceeding -1 to 1, and that the markers must **only** have values 0 or 1. Otherwise the AWG misinterprets the signals.\n",
+ "\n",
+ "In this example, we only use two channels of the AWG, namely channel 1 and 3. Extending to one or more should be straightforward."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "noofseqelems = 6\n",
+ "noofpoints = 1200\n",
+ "waveforms = [[], []] # one list for each channel\n",
+ "m1s = [[], []]\n",
+ "m2s = [[], []]\n",
+ "for ii in range(noofseqelems):\n",
+ " # waveform and markers for channel 1\n",
+ " waveforms[0].append(np.sin(np.pi*(ii+1)*np.linspace(0, 1, noofpoints))*np.hanning(noofpoints))\n",
+ " m1 = np.zeros(noofpoints)\n",
+ " m1[:int(noofpoints/(ii+1))] = 1\n",
+ " m1s[0].append(m1)\n",
+ " m2 = np.zeros(noofpoints)\n",
+ " m2s[0].append(m2)\n",
+ " \n",
+ " # waveform and markers for channel two\n",
+ " wf = np.sin(np.pi*(ii+1)*np.linspace(0, 1, noofpoints))\n",
+ " wf *= np.arctan(np.linspace(-20, 20, noofpoints))/np.pi*2\n",
+ " waveforms[1].append(wf)\n",
+ " m1 = np.zeros(noofpoints)\n",
+ " m1[:int(noofpoints/(ii+1))] = 1\n",
+ " m1s[1].append(m1)\n",
+ " m2 = np.zeros(noofpoints)\n",
+ " m2s[1].append(m2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support.' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " this.ws.close();\n",
+ " }\n",
+ "\n",
+ " this.ws.onmessage = this._make_on_message_function(this);\n",
+ "\n",
+ " this.ondownload = ondownload;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_header = function() {\n",
+ " var titlebar = $(\n",
+ " '');\n",
+ " var titletext = $(\n",
+ " '');\n",
+ " titlebar.append(titletext)\n",
+ " this.root.append(titlebar);\n",
+ " this.header = titletext[0];\n",
+ "}\n",
+ "\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_canvas = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var canvas_div = $('');\n",
+ "\n",
+ " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
+ "\n",
+ " function canvas_keyboard_event(event) {\n",
+ " return fig.key_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
+ " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
+ " this.canvas_div = canvas_div\n",
+ " this._canvas_extra_style(canvas_div)\n",
+ " this.root.append(canvas_div);\n",
+ "\n",
+ " var canvas = $('');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var rubberband = $('');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width);\n",
+ " canvas.attr('height', height);\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('')\n",
+ " nav_element.attr('style', 'width: 100%');\n",
+ " this.root.append(nav_element);\n",
+ "\n",
+ " // Define a callback function for later on.\n",
+ " function toolbar_event(event) {\n",
+ " return fig.toolbar_button_onclick(event['data']);\n",
+ " }\n",
+ " function toolbar_mouse_event(event) {\n",
+ " return fig.toolbar_button_onmouseover(event['data']);\n",
+ " }\n",
+ "\n",
+ " for(var toolbar_ind in mpl.toolbar_items) {\n",
+ " var name = mpl.toolbar_items[toolbar_ind][0];\n",
+ " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
+ " var image = mpl.toolbar_items[toolbar_ind][2];\n",
+ " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
+ "\n",
+ " if (!name) {\n",
+ " // put a spacer in here.\n",
+ " continue;\n",
+ " }\n",
+ " var button = $('');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $('');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $('');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $('');\n",
+ "\n",
+ " var fmt_picker = $('');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " '', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option)\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'];\n",
+ " var y0 = fig.canvas.height - msg['y0'];\n",
+ " var x1 = msg['x1'];\n",
+ " var y1 = fig.canvas.height - msg['y1'];\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x;\n",
+ " var y = canvas_pos.y;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('')\n",
+ " nav_element.attr('style', 'width: 100%');\n",
+ " this.root.append(nav_element);\n",
+ "\n",
+ " // Define a callback function for later on.\n",
+ " function toolbar_event(event) {\n",
+ " return fig.toolbar_button_onclick(event['data']);\n",
+ " }\n",
+ " function toolbar_mouse_event(event) {\n",
+ " return fig.toolbar_button_onmouseover(event['data']);\n",
+ " }\n",
+ "\n",
+ " for(var toolbar_ind in mpl.toolbar_items){\n",
+ " var name = mpl.toolbar_items[toolbar_ind][0];\n",
+ " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
+ " var image = mpl.toolbar_items[toolbar_ind][2];\n",
+ " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
+ "\n",
+ " if (!name) { continue; };\n",
+ "\n",
+ " var button = $('');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $('');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('');\n",
+ " var button = $('');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " // select the cell after this one\n",
+ " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
+ " IPython.notebook.select(index + 1);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# We can visualise the waveforms and markers\n",
+ "fig = plt.figure()\n",
+ "\n",
+ "ax1 = fig.add_subplot(411)\n",
+ "ax2 = fig.add_subplot(412)\n",
+ "ax3 = fig.add_subplot(413)\n",
+ "ax4 = fig.add_subplot(414)\n",
+ "ax1.set_title('Channel 1 waveform')\n",
+ "ax1.set_ylim([-1.1, 1.1])\n",
+ "ax2.set_title('Channel 1 markers')\n",
+ "ax2.set_ylim([-0.1, 1.1])\n",
+ "ax3.set_title('Channel 3 waveform')\n",
+ "ax3.set_ylim([-1.1, 1.1])\n",
+ "ax4.set_title('Channel 3 markers')\n",
+ "ax4.set_ylim([-0.1, 1.1])\n",
+ "\n",
+ "elemnum = 2 # choose which element to plot\n",
+ "ax1.plot(waveforms[0][elemnum], lw=4, color='#e1cb66')\n",
+ "ax2.plot(m1s[0][elemnum], lw=2, color='#FF4500', alpha=0.6)\n",
+ "ax2.plot(m2s[0][elemnum], lw=2, color='#FF8C00', alpha=0.6)\n",
+ "ax3.plot(waveforms[1][elemnum], lw=4, color='#800080')\n",
+ "ax4.plot(m1s[1][elemnum], lw=2, color='#6A5ACD', alpha=0.6)\n",
+ "ax4.plot(m2s[1][elemnum], lw=2, color='#EE82EE', alpha=0.6)\n",
+ "\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false
+ },
+ "source": [
+ "### GETTING THEM THERE VIA AN .AWG FILE\n",
+ "\n",
+ "The fastest way to transfer waveforms to the AWG is by using an .awg file. \n",
+ "\n",
+ "In addition to waveforms and markers, me must specify sequencing options for each sequence element.\n",
+ "\n",
+ "In this example notebook, we just put in some random numbers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# Sequencing options\n",
+ "\n",
+ "# number of repetitions\n",
+ "nreps = [2 for ii in range(noofseqelems)]\n",
+ "# Wait trigger (0 or 1)\n",
+ "trig_waits = [0]*noofseqelems\n",
+ "# Goto state\n",
+ "goto_states = [((ii+1) % noofseqelems)+1 for ii in range(noofseqelems)]\n",
+ "#goto_states = [0]*noofseqelems\n",
+ "# Event jump\n",
+ "jump_tos = [2]*noofseqelems"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Then all the magic happens in the following function call (type help(make_send_and_load_awg_file) to see all possible input parameters):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "awg1.make_send_and_load_awg_file(waveforms, m1s, m2s, \n",
+ " nreps, trig_waits,\n",
+ " goto_states, jump_tos, channels=[1, 3])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In order to build a local library of pulse sequences, one may generate and locally save the .awg file."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "filepath = os.path.join(os.getcwd(), 'test_awg_file.awg')\n",
+ "awgfile = awg1.make_and_save_awg_file(waveforms, m1s, m2s, nreps, trig_waits, goto_states,\n",
+ " jump_tos, channels=[1, 3], filename=filepath)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A saved .awg file may be loaded back into memrory using the helper function `parse_awg_file`,\n",
+ "which returns a tuple containing:\n",
+ "* A tuple matching the call signature of `awg1.make_and_save_awg_file` (see below)\n",
+ "* A dictionary with all the instrument settings of the .awg file"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "(callsig, instdict) = parse_awg_file(filepath)\n",
+ "(waveforms, m1s, m2s, nreps, trig_waits, goto_states, jump_tos, channels) = callsig"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To see how everything fits together, we may now upload the file we just parsed."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "awg1.make_send_and_load_awg_file(waveforms, m1s, m2s, \n",
+ " nreps, trig_waits,\n",
+ " goto_states, jump_tos, channels=channels)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### GETTING THEM THERE BY SENDING WAVEFORMS TO LIST\n",
+ "\n",
+ "An alternative way to transfer waveforms to the AWG is by sending them directly to the waveform list and then putting them into the sequencer. This method is more explicit, but slower for large waveforms."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "# First clear up the waveform list and empty the sequencer\n",
+ "awg1.delete_all_waveforms_from_list()\n",
+ "# Then set the sequence length to the correct number lest not all sequence elements get uploaded\n",
+ "awg1.sequence_length.set(noofseqelems)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "#Then transfer the waveforms to the list...\n",
+ "for elnum in range(noofseqelems):\n",
+ " for chnum in range(2):\n",
+ " wfmname = 'wfm{:03d}ch{}'.format(elnum, chnum+1)\n",
+ " awg1.send_waveform_to_list(waveforms[chnum][elnum], m1s[chnum][elnum], m2s[chnum][elnum], wfmname)\n",
+ "#...upload them to the sequencer...\n",
+ "for elnum in range(noofseqelems):\n",
+ " for chnum in range(2):\n",
+ " wfmname = 'wfm{:03d}ch{}'.format(elnum, chnum+1)\n",
+ " awg1.set_sqel_waveform(wfmname, chnum+1, elnum+1)\n",
+ "#...and set the sequence elements setting\n",
+ "for elnum in range(noofseqelems):\n",
+ " awg1.set_sqel_goto_target_index(elnum+1, goto_states[elnum])\n",
+ " awg1.set_sqel_loopcnt(nreps[elnum], elnum+1)\n",
+ " awg1.set_sqel_trigger_wait(elnum+1, trig_waits[elnum])\n",
+ " awg1.set_sqel_event_target_index(elnum+1, jump_tos[elnum])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Finally, close down the instrument."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "awg1.close()"
+ ]
+ },
+ {
+ "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.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/testsweep/gates_chan0_set.dat b/docs/examples/testsweep/gates_chan0_set.dat
deleted file mode 100644
index 7a747e0d052..00000000000
--- a/docs/examples/testsweep/gates_chan0_set.dat
+++ /dev/null
@@ -1,404 +0,0 @@
-# gates_chan0_set meter_amplitude
-# "Gate Channel 0 (mV)" "Current (nA)"
-# 401
--20 0.117
--19.9 0.117
--19.8 0.115
--19.7 0.111
--19.6 0.106
--19.5 0.099
--19.4 0.092
--19.3 0.085
--19.2 0.077
--19.1 0.071
--19 0.064
--18.9 0.058
--18.8 0.053
--18.7 0.048
--18.6 0.044
--18.5 0.04
--18.4 0.037
--18.3 0.034
--18.2 0.031
--18.1 0.029
--18 0.027
--17.9 0.025
--17.8 0.023
--17.7 0.022
--17.6 0.02
--17.5 0.019
--17.4 0.018
--17.3 0.017
--17.2 0.016
--17.1 0.015
--17 0.014
--16.9 0.013
--16.8 0.013
--16.7 0.012
--16.6 0.011
--16.5 0.011
--16.4 0.01
--16.3 0.01
--16.2 0.01
--16.1 0.009
--16 0.009
--15.9 0.008
--15.8 0.008
--15.7 0.008
--15.6 0.007
--15.5 0.007
--15.4 0.007
--15.3 0.007
--15.2 0.006
--15.1 0.006
--15 0.006
--14.9 0.006
--14.8 0.006
--14.7 0.007
--14.6 0.007
--14.5 0.007
--14.4 0.007
--14.3 0.008
--14.2 0.008
--14.1 0.008
--14 0.009
--13.9 0.009
--13.8 0.01
--13.7 0.01
--13.6 0.01
--13.5 0.011
--13.4 0.011
--13.3 0.012
--13.2 0.013
--13.1 0.013
--13 0.014
--12.9 0.015
--12.8 0.016
--12.7 0.017
--12.6 0.018
--12.5 0.019
--12.4 0.02
--12.3 0.022
--12.2 0.023
--12.1 0.025
--12 0.027
--11.9 0.029
--11.8 0.031
--11.7 0.034
--11.6 0.037
--11.5 0.04
--11.4 0.044
--11.3 0.048
--11.2 0.053
--11.1 0.058
--11 0.064
--10.9 0.071
--10.8 0.077
--10.7 0.085
--10.6 0.092
--10.5 0.099
--10.4 0.106
--10.3 0.111
--10.2 0.115
--10.1 0.117
--10 0.117
--9.9 0.117
--9.8 0.115
--9.7 0.111
--9.6 0.106
--9.5 0.099
--9.4 0.092
--9.3 0.085
--9.2 0.077
--9.1 0.071
--9 0.064
--8.9 0.058
--8.8 0.053
--8.7 0.048
--8.6 0.044
--8.5 0.04
--8.4 0.037
--8.3 0.034
--8.2 0.031
--8.1 0.029
--8 0.027
--7.9 0.025
--7.8 0.023
--7.7 0.022
--7.6 0.02
--7.5 0.019
--7.4 0.018
--7.3 0.017
--7.2 0.016
--7.1 0.015
--7 0.014
--6.9 0.013
--6.8 0.013
--6.7 0.012
--6.6 0.011
--6.5 0.011
--6.4 0.01
--6.3 0.01
--6.2 0.01
--6.1 0.009
--6 0.009
--5.9 0.008
--5.8 0.008
--5.7 0.008
--5.6 0.007
--5.5 0.007
--5.4 0.007
--5.3 0.007
--5.2 0.006
--5.1 0.006
--5 0.006
--4.9 0.006
--4.8 0.006
--4.7 0.007
--4.6 0.007
--4.5 0.007
--4.4 0.007
--4.3 0.008
--4.2 0.008
--4.1 0.008
--4 0.009
--3.9 0.009
--3.8 0.01
--3.7 0.01
--3.6 0.01
--3.5 0.011
--3.4 0.011
--3.3 0.012
--3.2 0.013
--3.1 0.013
--3 0.014
--2.9 0.015
--2.8 0.016
--2.7 0.017
--2.6 0.018
--2.5 0.019
--2.4 0.02
--2.3 0.022
--2.2 0.023
--2.1 0.025
--2 0.027
--1.9 0.029
--1.8 0.031
--1.7 0.034
--1.6 0.037
--1.5 0.04
--1.4 0.044
--1.3 0.048
--1.2 0.053
--1.1 0.058
--1 0.064
--0.9 0.071
--0.8 0.077
--0.7 0.085
--0.6 0.092
--0.5 0.099
--0.4 0.106
--0.3 0.111
--0.2 0.115
--0.1 0.117
-0 0.117
-0.1 0.117
-0.2 0.115
-0.3 0.111
-0.4 0.106
-0.5 0.099
-0.6 0.092
-0.7 0.085
-0.8 0.077
-0.9 0.071
-1 0.064
-1.1 0.058
-1.2 0.053
-1.3 0.048
-1.4 0.044
-1.5 0.04
-1.6 0.037
-1.7 0.034
-1.8 0.031
-1.9 0.029
-2 0.027
-2.1 0.025
-2.2 0.023
-2.3 0.022
-2.4 0.02
-2.5 0.019
-2.6 0.018
-2.7 0.017
-2.8 0.016
-2.9 0.015
-3 0.014
-3.1 0.013
-3.2 0.013
-3.3 0.012
-3.4 0.011
-3.5 0.011
-3.6 0.01
-3.7 0.01
-3.8 0.01
-3.9 0.009
-4 0.009
-4.1 0.008
-4.2 0.008
-4.3 0.008
-4.4 0.007
-4.5 0.007
-4.6 0.007
-4.7 0.007
-4.8 0.006
-4.9 0.006
-5 0.006
-5.1 0.006
-5.2 0.006
-5.3 0.007
-5.4 0.007
-5.5 0.007
-5.6 0.007
-5.7 0.008
-5.8 0.008
-5.9 0.008
-6 0.009
-6.1 0.009
-6.2 0.01
-6.3 0.01
-6.4 0.01
-6.5 0.011
-6.6 0.011
-6.7 0.012
-6.8 0.013
-6.9 0.013
-7 0.014
-7.1 0.015
-7.2 0.016
-7.3 0.017
-7.4 0.018
-7.5 0.019
-7.6 0.02
-7.7 0.022
-7.8 0.023
-7.9 0.025
-8 0.027
-8.1 0.029
-8.2 0.031
-8.3 0.034
-8.4 0.037
-8.5 0.04
-8.6 0.044
-8.7 0.048
-8.8 0.053
-8.9 0.058
-9 0.064
-9.1 0.071
-9.2 0.077
-9.3 0.085
-9.4 0.092
-9.5 0.099
-9.6 0.106
-9.7 0.111
-9.8 0.115
-9.9 0.117
-10 0.117
-10.1 0.117
-10.2 0.115
-10.3 0.111
-10.4 0.106
-10.5 0.099
-10.6 0.092
-10.7 0.085
-10.8 0.077
-10.9 0.071
-11 0.064
-11.1 0.058
-11.2 0.053
-11.3 0.048
-11.4 0.044
-11.5 0.04
-11.6 0.037
-11.7 0.034
-11.8 0.031
-11.9 0.029
-12 0.027
-12.1 0.025
-12.2 0.023
-12.3 0.022
-12.4 0.02
-12.5 0.019
-12.6 0.018
-12.7 0.017
-12.8 0.016
-12.9 0.015
-13 0.014
-13.1 0.013
-13.2 0.013
-13.3 0.012
-13.4 0.011
-13.5 0.011
-13.6 0.01
-13.7 0.01
-13.8 0.01
-13.9 0.009
-14 0.009
-14.1 0.008
-14.2 0.008
-14.3 0.008
-14.4 0.007
-14.5 0.007
-14.6 0.007
-14.7 0.007
-14.8 0.006
-14.9 0.006
-15 0.006
-15.1 0.006
-15.2 0.006
-15.3 0.007
-15.4 0.007
-15.5 0.007
-15.6 0.007
-15.7 0.008
-15.8 0.008
-15.9 0.008
-16 0.009
-16.1 0.009
-16.2 0.01
-16.3 0.01
-16.4 0.01
-16.5 0.011
-16.6 0.011
-16.7 0.012
-16.8 0.013
-16.9 0.013
-17 0.014
-17.1 0.015
-17.2 0.016
-17.3 0.017
-17.4 0.018
-17.5 0.019
-17.6 0.02
-17.7 0.022
-17.8 0.023
-17.9 0.025
-18 0.027
-18.1 0.029
-18.2 0.031
-18.3 0.034
-18.4 0.037
-18.5 0.04
-18.6 0.044
-18.7 0.048
-18.8 0.053
-18.9 0.058
-19 0.064
-19.1 0.071
-19.2 0.077
-19.3 0.085
-19.4 0.092
-19.5 0.099
-19.6 0.106
-19.7 0.111
-19.8 0.115
-19.9 0.117
-20 0.117
diff --git a/docs/examples/testsweep/snapshot.json b/docs/examples/testsweep/snapshot.json
deleted file mode 100644
index 93ef979f99f..00000000000
--- a/docs/examples/testsweep/snapshot.json
+++ /dev/null
@@ -1,216 +0,0 @@
-{
- "__class__": "qcodes.data.data_set.DataSet",
- "arrays": {
- "gates_chan0_set": {
- "__class__": "qcodes.data.data_array.DataArray",
- "action_indices": [],
- "array_id": "gates_chan0_set",
- "instrument": "toymodel.MockGates",
- "instrument_name": "gates",
- "is_setpoint": true,
- "label": "Gate Channel 0 (mV)",
- "name": "chan0",
- "shape": [
- 401
- ],
- "units": ""
- },
- "meter_amplitude": {
- "__class__": "qcodes.data.data_array.DataArray",
- "action_indices": [
- 0
- ],
- "array_id": "meter_amplitude",
- "instrument": "toymodel.MockMeter",
- "instrument_name": "meter",
- "is_setpoint": false,
- "label": "Current (nA)",
- "name": "amplitude",
- "shape": [
- 401
- ],
- "units": ""
- }
- },
- "formatter": "qcodes.data.gnuplot_format.GNUPlotFormat",
- "io": "",
- "location": "testsweep",
- "loop": {
- "__class__": "qcodes.loops.ActiveLoop",
- "actions": [
- {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockMeter",
- "instrument_name": "meter",
- "label": "Current (nA)",
- "name": "amplitude",
- "ts": "2016-06-15 22:18:12",
- "units": "",
- "value": 0.117
- }
- ],
- "background": true,
- "delay": 0.003,
- "sweep_values": {
- "parameter": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockGates",
- "instrument_name": "gates",
- "label": "Gate Channel 0 (mV)",
- "name": "chan0",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": 0.0
- },
- "values": [
- {
- "first": -20.0,
- "last": 20.0,
- "num": 401,
- "type": "linear"
- }
- ]
- },
- "then_actions": [],
- "ts_end": "2016-06-15 22:18:19",
- "ts_start": "2016-06-15 22:18:16",
- "use_data_manager": true,
- "use_threads": true
- },
- "station": {
- "components": {},
- "default_measurement": [
- {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockMeter",
- "instrument_name": "meter",
- "label": "Current (nA)",
- "name": "amplitude",
- "ts": "2016-06-15 22:18:12",
- "units": "",
- "value": 0.117
- }
- ],
- "instruments": {
- "gates": {
- "__class__": "toymodel.MockGates",
- "functions": {
- "reset": {}
- },
- "name": "gates",
- "parameters": {
- "IDN": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockGates",
- "instrument_name": "gates",
- "label": "IDN",
- "name": "IDN",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": {
- "firmware": null,
- "model": null,
- "serial": null,
- "vendor": null
- }
- },
- "chan0": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockGates",
- "instrument_name": "gates",
- "label": "Gate Channel 0 (mV)",
- "name": "chan0",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": 0.0
- },
- "chan1": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockGates",
- "instrument_name": "gates",
- "label": "Gate Channel 1 (mV)",
- "name": "chan1",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": 0.0
- },
- "chan2": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockGates",
- "instrument_name": "gates",
- "label": "Gate Channel 2 (mV)",
- "name": "chan2",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": 0.0
- }
- }
- },
- "meter": {
- "__class__": "toymodel.MockMeter",
- "functions": {},
- "name": "meter",
- "parameters": {
- "IDN": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockMeter",
- "instrument_name": "meter",
- "label": "IDN",
- "name": "IDN",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": {
- "firmware": null,
- "model": null,
- "serial": null,
- "vendor": null
- }
- },
- "amplitude": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockMeter",
- "instrument_name": "meter",
- "label": "Current (nA)",
- "name": "amplitude",
- "ts": "2016-06-15 22:18:12",
- "units": "",
- "value": 0.117
- }
- }
- },
- "source": {
- "__class__": "toymodel.MockSource",
- "functions": {},
- "name": "source",
- "parameters": {
- "IDN": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockSource",
- "instrument_name": "source",
- "label": "IDN",
- "name": "IDN",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": {
- "firmware": null,
- "model": null,
- "serial": null,
- "vendor": null
- }
- },
- "amplitude": {
- "__class__": "qcodes.instrument.parameter.StandardParameter",
- "instrument": "toymodel.MockSource",
- "instrument_name": "source",
- "label": "Source Amplitude (μV)",
- "name": "amplitude",
- "ts": "2016-06-15 22:18:10",
- "units": "",
- "value": 0.1
- }
- }
- }
- },
- "parameters": {}
- }
-}
\ No newline at end of file
diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py
index c6a6dd90525..48b55cdff56 100644
--- a/qcodes/instrument_drivers/AlazarTech/ATS.py
+++ b/qcodes/instrument_drivers/AlazarTech/ATS.py
@@ -1,6 +1,7 @@
import ctypes
import logging
import numpy as np
+import time
import os
from qcodes.instrument.base import Instrument
@@ -10,14 +11,14 @@
# TODO(damazter) (C) logging
# these items are important for generalizing this code to multiple alazar cards
-# TODO(damazter) (W) remove 8 bits per sample requirement
# TODO(damazter) (W) some alazar cards have a different number of channels :(
-# this driver only works with 2-channel cards
# TODO(damazter) (S) tests to do:
# acquisition that would overflow the board if measurement is not stopped
# quickly enough. can this be solved by not reposting the buffers?
+# TODO (natalie) make logging vs print vs nothing decisions
+
class AlazarTech_ATS(Instrument):
"""
@@ -193,6 +194,7 @@ def find_boards(cls, dll_path=None):
boards.append(cls.get_board_info(dll, system_id, board_id))
return boards
+ # TODO(nataliejpg) this needs fixing..., dll can't be a string
@classmethod
def get_board_info(cls, dll, system_id, board_id):
"""
@@ -213,7 +215,6 @@ def get_board_info(cls, dll, system_id, board_id):
- max_samples
- bits_per_sample
"""
-
# make a temporary instrument for this board, to make it easier
# to get its info
board = cls('temp', system_id=system_id, board_id=board_id,
@@ -232,7 +233,15 @@ def get_board_info(cls, dll, system_id, board_id):
def __init__(self, name, system_id=1, board_id=1, dll_path=None, **kwargs):
super().__init__(name, **kwargs)
- self._ATS_dll = ctypes.cdll.LoadLibrary(dll_path or self.dll_path)
+ self._ATS_dll = None
+
+ if os.name == 'nt':
+ self._ATS_dll = ctypes.cdll.LoadLibrary(dll_path or self.dll_path)
+ else:
+ raise Exception("Unsupported OS")
+
+ # TODO (W) make the board id more general such that more than one card
+ # per system configurations are supported
self._handle = self._ATS_dll.AlazarGetBoardBySystemID(system_id,
board_id)
@@ -266,6 +275,8 @@ def get_idn(self):
board_kind = self._board_names[
self._ATS_dll.AlazarGetBoardKind(self._handle)]
+ max_s, bps = self._get_channel_info(self._handle)
+
major = np.array([0], dtype=np.uint8)
minor = np.array([0], dtype=np.uint8)
revision = np.array([0], dtype=np.uint8)
@@ -273,7 +284,7 @@ def get_idn(self):
self._handle,
major.ctypes.data,
minor.ctypes.data)
- cpld_ver = str(major[0])+"."+str(minor[0])
+ cpld_ver = str(major[0]) + "." + str(minor[0])
self._call_dll('AlazarGetDriverVersion',
major.ctypes.data,
@@ -308,14 +319,15 @@ def get_idn(self):
# about the encoding of the link speed
self._call_dll('AlazarQueryCapability',
self._handle, 0x10000030, 0, value.ctypes.data)
- pcie_link_speed = str(value[0]*2.5/10)+"GB/s"
+ pcie_link_speed = str(value[0] * 2.5 / 10) + "GB/s"
self._call_dll('AlazarQueryCapability',
self._handle, 0x10000031, 0, value.ctypes.data)
pcie_link_width = str(value[0])
-
return {'firmware': None,
'model': board_kind,
+ 'max_samples': max_s,
+ 'bits_per_sample': bps,
'serial': serial,
'vendor': 'AlazarTech',
'CPLD_version': cpld_ver,
@@ -335,7 +347,8 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None,
trigger_engine2=None, trigger_source2=None,
trigger_slope2=None, trigger_level2=None,
external_trigger_coupling=None, external_trigger_range=None,
- trigger_delay=None, timeout_ticks=None):
+ trigger_delay=None, timeout_ticks=None, aux_io_mode=None,
+ aux_io_param=None):
"""
configure the ATS board and set the corresponding parameters to the
appropriate values.
@@ -396,6 +409,8 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None,
external_trigger_range)
self._set_if_present('trigger_delay', trigger_delay)
self._set_if_present('timeout_ticks', timeout_ticks)
+ self._set_if_present('aux_io_mode', aux_io_mode)
+ self._set_if_present('aux_io_param', aux_io_param)
# endregion
self._call_dll('AlazarSetCaptureClock',
@@ -408,9 +423,10 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None,
self.parameters['coupling' + str(i)],
self.parameters['channel_range' + str(i)],
self.parameters['impedance' + str(i)])
- self._call_dll('AlazarSetBWLimit',
- self._handle, i,
- self.parameters['bwlimit' + str(i)])
+ if bwlimit is not None:
+ self._call_dll('AlazarSetBWLimit',
+ self._handle, i,
+ self.parameters['bwlimit' + str(i)])
self._call_dll('AlazarSetTriggerOperation',
self._handle, self.trigger_operation,
@@ -429,7 +445,9 @@ def config(self, clock_source=None, sample_rate=None, clock_edge=None,
self._call_dll('AlazarSetTriggerTimeOut',
self._handle, self.timeout_ticks)
- # TODO(damazter) (W) config AUXIO
+ self._call_dll('AlazarConfigureAuxIO',
+ self._handle, self.aux_io_mode,
+ self.aux_io_param)
def _get_channel_info(self, handle):
bps = np.array([0], dtype=np.uint8) # bps bits per sample
@@ -501,11 +519,6 @@ def acquire(self, mode=None, samples_per_record=None,
# Abort any previous measurement
self._call_dll('AlazarAbortAsyncRead', self._handle)
- # get channel info
- max_s, bps = self._get_channel_info(self._handle)
- if bps != 8:
- raise Exception('Only 8 bits per sample supported at this moment')
-
# Set record size for NPT mode
if mode == 'NPT':
pretriggersize = 0 # pretriggersize is 0 for NPT always
@@ -546,7 +559,7 @@ def acquire(self, mode=None, samples_per_record=None,
if (samples_per_record % buffers_per_acquisition != 0):
logging.warning('buffers_per_acquisition is not a divisor of '
'samples per record which it should be in '
- 'TS mode, rounding down in samples per buffer '
+ 'Ts mode, rounding down in samples per buffer '
'calculation')
samples_per_buffer = int(samples_per_record /
buffers_per_acquisition)
@@ -574,14 +587,36 @@ def acquire(self, mode=None, samples_per_record=None,
self.interleave_samples._set_updated()
self.get_processed_data._set_updated()
+ # bytes per sample
+ max_s, bps = self._get_channel_info(self._handle)
+ bytes_per_sample = (bps + 7) // 8
+
+ # bytes per record
+ bytes_per_record = bytes_per_sample * samples_per_record
+
+ # channels
+ if self.channel_selection._get_byte() == 3:
+ number_of_channels = 2
+ else:
+ number_of_channels = 1
+
+ # bytes per buffer
+ bytes_per_buffer = (bytes_per_record *
+ records_per_buffer * number_of_channels)
+
# create buffers for acquisition
+ # TODO(nataliejpg) should this be > 1 (as intuitive) or > 8 as in alazar sample code?
+ sample_type = ctypes.c_uint8
+ if bytes_per_sample > 1:
+ sample_type = ctypes.c_uint16
+
self.clear_buffers()
# make sure that allocated_buffers <= buffers_per_acquisition
if (self.allocated_buffers._get_byte() >
self.buffers_per_acquisition._get_byte()):
- print("'allocated_buffers' should be smaller than or equal to"
- "'buffers_per_acquisition'. Defaulting 'allocated_buffers' to"
- "" + str(self.buffers_per_acquisition._get_byte()))
+ logging.warn("'allocated_buffers' should be <= "
+ "'buffers_per_acquisition'. Defaulting 'allocated_buffers'"
+ " to " + str(self.buffers_per_acquisition._get_byte()))
self.allocated_buffers._set(
self.buffers_per_acquisition._get_byte())
@@ -589,33 +624,40 @@ def acquire(self, mode=None, samples_per_record=None,
for k in range(allocated_buffers):
try:
- self.buffer_list.append(Buffer(bps, samples_per_buffer,
- number_of_channels))
+ self.buffer_list.append(Buffer(sample_type, bytes_per_buffer))
except:
self.clear_buffers()
raise
# post buffers to Alazar
+ # print("made buffer list length " + str(len(self.buffer_list)))
for buf in self.buffer_list:
+ self._ATS_dll.AlazarPostAsyncBuffer.argtypes = [ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32]
self._call_dll('AlazarPostAsyncBuffer',
self._handle, buf.addr, buf.size_bytes)
self.allocated_buffers._set_updated()
# -----start capture here-----
acquisition_controller.pre_start_capture()
+ start = time.clock() # Keep track of when acquisition started
# call the startcapture method
self._call_dll('AlazarStartCapture', self._handle)
+ logging.info("Capturing %d buffers." % buffers_per_acquisition)
acquisition_controller.pre_acquire()
+
# buffer handling from acquisition
buffers_completed = 0
+ bytes_transferred = 0
buffer_timeout = self.buffer_timeout._get_byte()
self.buffer_timeout._set_updated()
buffer_recycling = (self.buffers_per_acquisition._get_byte() >
self.allocated_buffers._get_byte())
- while buffers_completed < self.buffers_per_acquisition._get_byte():
+ while (buffers_completed < self.buffers_per_acquisition._get_byte()):
+ # Wait for the buffer at the head of the list of available
+ # buffers to be filled by the board.
buf = self.buffer_list[buffers_completed % allocated_buffers]
self._call_dll('AlazarWaitAsyncBufferComplete',
@@ -628,12 +670,12 @@ def acquire(self, mode=None, samples_per_record=None,
# if buffers must be recycled, extract data and repost them
# otherwise continue to next buffer
-
if buffer_recycling:
acquisition_controller.handle_buffer(buf.buffer)
self._call_dll('AlazarPostAsyncBuffer',
self._handle, buf.addr, buf.size_bytes)
buffers_completed += 1
+ bytes_transferred += buf.size_bytes
# stop measurement here
self._call_dll('AlazarAbortAsyncRead', self._handle)
@@ -651,6 +693,24 @@ def acquire(self, mode=None, samples_per_record=None,
for p in self.parameters.values():
p.get()
+ # Compute the total transfer time, and display performance information.
+ transfer_time_sec = time.clock() - start
+ # print("Capture completed in %f sec" % transfer_time_sec)
+ buffers_per_sec = 0
+ bytes_per_sec = 0
+ records_per_sec = 0
+ if transfer_time_sec > 0:
+ buffers_per_sec = buffers_completed / transfer_time_sec
+ bytes_per_sec = bytes_transferred / transfer_time_sec
+ records_per_sec = (records_per_buffer *
+ buffers_completed / transfer_time_sec)
+ logging.info("Captured %d buffers (%f buffers per sec)" %
+ (buffers_completed, buffers_per_sec))
+ logging.info("Captured %d records (%f records per sec)" %
+ (records_per_buffer * buffers_completed, records_per_sec))
+ logging.info("Transferred %d bytes (%f bytes per sec)" %
+ (bytes_transferred, bytes_per_sec))
+
# return result
return acquisition_controller.post_acquire()
@@ -678,7 +738,7 @@ def _call_dll(self, func_name, *args):
args_out = []
update_params = []
for arg in args:
- if isinstance(arg,AlazarParameter):
+ if isinstance(arg, AlazarParameter):
args_out.append(arg._get_byte())
update_params.append(arg)
else:
@@ -686,10 +746,14 @@ def _call_dll(self, func_name, *args):
# run the function
func = getattr(self._ATS_dll, func_name)
- return_code = func(*args_out)
+ try:
+ return_code = func(*args_out)
+ except Exception as e:
+ logging.error(e)
+ raise
# check for errors
- if (return_code != self._success) and (return_code !=518):
+ if (return_code != self._success) and (return_code != 518):
# TODO(damazter) (C) log error
argrepr = repr(args_out)
@@ -718,6 +782,7 @@ def clear_buffers(self):
"""
for b in self.buffer_list:
b.free_mem()
+ logging.info("buffers cleared")
self.buffer_list = []
def signal_to_volt(self, channel, signal):
@@ -861,44 +926,56 @@ def _set_updated(self):
class Buffer:
- """
- This class represents a single buffer used for the data acquisition
+ """Buffer suitable for DMA transfers.
- Args:
- bits_per_sample: the number of bits needed to store a sample
- samples_per_buffer: the number of samples needed per buffer(per channel)
- number_of_channels: the number of channels that will be stored in the
- buffer
- """
- def __init__(self, bits_per_sample, samples_per_buffer,
- number_of_channels):
- if bits_per_sample != 8:
- raise Exception("Buffer: only 8 bit per sample supported")
- if os.name != 'nt':
- raise Exception("Buffer: only Windows supported at this moment")
- self._allocated = True
+ AlazarTech digitizers use direct memory access (DMA) to transfer
+ data from digitizers to the computer's main memory. This class
+ abstracts a memory buffer on the host, and ensures that all the
+ requirements for DMA transfers are met.
- # try to allocate memory
- mem_commit = 0x1000
- page_readwrite = 0x4
+ Buffer export a 'buffer' member, which is a NumPy array view
+ of the underlying memory buffer
- self.size_bytes = samples_per_buffer * number_of_channels
+ Args:
+ c_sample_type (ctypes type): The datatype of the buffer to create.
+ size_bytes (int): The size of the buffer to allocate, in bytes.
+ """
+ def __init__(self, c_sample_type, size_bytes):
+ self.size_bytes = size_bytes
+
+ npSampleType = {
+ ctypes.c_uint8: np.uint8,
+ ctypes.c_uint16: np.uint16,
+ ctypes.c_uint32: np.uint32,
+ ctypes.c_int32: np.int32,
+ ctypes.c_float: np.float32
+ }.get(c_sample_type, 0)
+
+ bytes_per_sample = {
+ ctypes.c_uint8: 1,
+ ctypes.c_uint16: 2,
+ ctypes.c_uint32: 4,
+ ctypes.c_int32: 4,
+ ctypes.c_float: 4
+ }.get(c_sample_type, 0)
- # for documentation please see:
- # https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx
- ctypes.windll.kernel32.VirtualAlloc.argtypes = [
- ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long]
- ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
- self.addr = ctypes.windll.kernel32.VirtualAlloc(
- 0, ctypes.c_long(self.size_bytes), mem_commit, page_readwrite)
- if self.addr is None:
+ self._allocated = True
+ self.addr = None
+ if os.name == 'nt':
+ MEM_COMMIT = 0x1000
+ PAGE_READWRITE = 0x4
+ ctypes.windll.kernel32.VirtualAlloc.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long]
+ ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
+ self.addr = ctypes.windll.kernel32.VirtualAlloc(
+ 0, ctypes.c_long(size_bytes), MEM_COMMIT, PAGE_READWRITE)
+ else:
self._allocated = False
- e = ctypes.windll.kernel32.GetLastError()
- raise Exception("Memory allocation error: " + str(e))
+ raise Exception("Unsupported OS")
- ctypes_array = (ctypes.c_uint8 *
- self.size_bytes).from_address(self.addr)
- self.buffer = np.frombuffer(ctypes_array, dtype=np.uint8)
+ ctypes_array = (c_sample_type *
+ (size_bytes // bytes_per_sample)).from_address(self.addr)
+ self.buffer = np.frombuffer(ctypes_array, dtype=npSampleType)
+ self.ctypes_buffer = ctypes_array
pointer, read_only_flag = self.buffer.__array_interface__['data']
def free_mem(self):
@@ -906,16 +983,16 @@ def free_mem(self):
uncommit memory allocated with this buffer object
:return: None
"""
- mem_release = 0x8000
-
- # for documentation please see:
- # https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx
- ctypes.windll.kernel32.VirtualFree.argtypes = [
- ctypes.c_void_p, ctypes.c_long, ctypes.c_long]
- ctypes.windll.kernel32.VirtualFree.restype = ctypes.c_int
- ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.addr), 0,
- mem_release)
+
self._allocated = False
+ if os.name == 'nt':
+ MEM_RELEASE = 0x8000
+ ctypes.windll.kernel32.VirtualFree.argtypes = [ctypes.c_void_p, ctypes.c_long, ctypes.c_long]
+ ctypes.windll.kernel32.VirtualFree.restype = ctypes.c_int
+ ctypes.windll.kernel32.VirtualFree(ctypes.c_void_p(self.addr), 0, MEM_RELEASE);
+ else:
+ self._allocated = True
+ raise Exception("Unsupported OS")
def __del__(self):
"""
diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9360.py b/qcodes/instrument_drivers/AlazarTech/ATS9360.py
new file mode 100644
index 00000000000..3c33374d50c
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/ATS9360.py
@@ -0,0 +1,266 @@
+from .ATS import AlazarTech_ATS, AlazarParameter
+from qcodes.utils import validators
+
+
+class AlazarTech_ATS9360(AlazarTech_ATS):
+ """
+ This class is the driver for the ATS9360 board
+ it inherits from the ATS base class
+
+ TODO(nataliejpg):
+ - add clock source options and sample rate options
+ (probelem being that byte_to_value_dict of
+ sample_rate relies on value of clock_source)
+ """
+
+ # samples divisor is listed in the manual as being 32 but this gave
+ # incorrect data when tested for divisors less than 128
+ samples_divisor = 128
+
+ def __init__(self, name, **kwargs):
+ dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll'
+ super().__init__(name, dll_path=dll_path, **kwargs)
+
+ # add parameters
+
+ # ----- Parameters for the configuration of the board -----
+ self.add_parameter(name='clock_source',
+ parameter_class=AlazarParameter,
+ label='Clock Source',
+ unit=None,
+ value='EXTERNAL_CLOCK_10MHz_REF',
+ byte_to_value_dict={7: 'EXTERNAL_CLOCK_10MHz_REF'})
+ self.add_parameter(name='sample_rate',
+ parameter_class=AlazarParameter,
+ label='Sample Rate',
+ unit='S/s',
+ value=500000000)
+ self.add_parameter(name='clock_edge',
+ parameter_class=AlazarParameter,
+ label='Clock Edge',
+ unit=None,
+ value='CLOCK_EDGE_RISING',
+ byte_to_value_dict={0: 'CLOCK_EDGE_RISING',
+ 1: 'CLOCK_EDGE_FALLING'})
+ self.add_parameter(name='decimation',
+ parameter_class=AlazarParameter,
+ label='Decimation',
+ unit=None,
+ value=1,
+ vals=validators.Ints(0, 100000))
+
+ for i in ['1', '2']:
+ self.add_parameter(name='coupling' + i,
+ parameter_class=AlazarParameter,
+ label='Coupling channel ' + i,
+ unit=None,
+ value='DC',
+ byte_to_value_dict={1: 'AC', 2: 'DC'})
+ self.add_parameter(name='channel_range' + i,
+ parameter_class=AlazarParameter,
+ label='Range channel ' + i,
+ unit='V',
+ value=0.4,
+ byte_to_value_dict={7: 0.4})
+ self.add_parameter(name='impedance' + i,
+ parameter_class=AlazarParameter,
+ label='Impedance channel ' + i,
+ unit='Ohm',
+ value=50,
+ byte_to_value_dict={2: 50})
+
+ self.add_parameter(name='trigger_operation',
+ parameter_class=AlazarParameter,
+ label='Trigger Operation',
+ unit=None,
+ value='TRIG_ENGINE_OP_J',
+ byte_to_value_dict={
+ 0: 'TRIG_ENGINE_OP_J',
+ 1: 'TRIG_ENGINE_OP_K',
+ 2: 'TRIG_ENGINE_OP_J_OR_K',
+ 3: 'TRIG_ENGINE_OP_J_AND_K',
+ 4: 'TRIG_ENGINE_OP_J_XOR_K',
+ 5: 'TRIG_ENGINE_OP_J_AND_NOT_K',
+ 6: 'TRIG_ENGINE_OP_NOT_J_AND_K'})
+ for i in ['1', '2']:
+ self.add_parameter(name='trigger_engine' + i,
+ parameter_class=AlazarParameter,
+ label='Trigger Engine ' + i,
+ unit=None,
+ value='TRIG_ENGINE_' + ('J' if i == 0 else 'K'),
+ byte_to_value_dict={0: 'TRIG_ENGINE_J',
+ 1: 'TRIG_ENGINE_K'})
+ self.add_parameter(name='trigger_source' + i,
+ parameter_class=AlazarParameter,
+ label='Trigger Source ' + i,
+ unit=None,
+ value='EXTERNAL',
+ byte_to_value_dict={0: 'CHANNEL_A',
+ 1: 'CHANNEL_B',
+ 2: 'EXTERNAL',
+ 3: 'DISABLE'})
+ self.add_parameter(name='trigger_slope' + i,
+ parameter_class=AlazarParameter,
+ label='Trigger Slope ' + i,
+ unit=None,
+ value='TRIG_SLOPE_POSITIVE',
+ byte_to_value_dict={1: 'TRIG_SLOPE_POSITIVE',
+ 2: 'TRIG_SLOPE_NEGATIVE'})
+ self.add_parameter(name='trigger_level' + i,
+ parameter_class=AlazarParameter,
+ label='Trigger Level ' + i,
+ unit=None,
+ value=140,
+ vals=validators.Ints(0, 255))
+
+ self.add_parameter(name='external_trigger_coupling',
+ parameter_class=AlazarParameter,
+ label='External Trigger Coupling',
+ unit=None,
+ value='DC',
+ byte_to_value_dict={1: 'AC', 2: 'DC'})
+ self.add_parameter(name='external_trigger_range',
+ parameter_class=AlazarParameter,
+ label='External Trigger Range',
+ unit=None,
+ value='ETR_2V5',
+ byte_to_value_dict={0: 'ETR_5V', 1: 'ETR_1V',
+ 2: 'ETR_TTL', 3: 'ETR_2V5'})
+ self.add_parameter(name='trigger_delay',
+ parameter_class=AlazarParameter,
+ label='Trigger Delay',
+ unit='Sample clock cycles',
+ value=0,
+ vals=validators.Ints(min_value=0))
+
+ # NOTE: The board will wait for a for this amount of time for a
+ # trigger event. If a trigger event does not arrive, then the
+ # board will automatically trigger. Set the trigger timeout value
+ # to 0 to force the board to wait forever for a trigger event.
+ #
+ # IMPORTANT: The trigger timeout value should be set to zero after
+ # appropriate trigger parameters have been determined, otherwise
+ # the board may trigger if the timeout interval expires before a
+ # hardware trigger event arrives.
+ self.add_parameter(name='timeout_ticks',
+ parameter_class=AlazarParameter,
+ label='Timeout Ticks',
+ unit='10 us',
+ value=0,
+ vals=validators.Ints(min_value=0))
+
+ self.add_parameter(name='aux_io_mode',
+ parameter_class=AlazarParameter,
+ label='AUX I/O Mode',
+ unit=None,
+ value='AUX_IN_AUXILIARY',
+ byte_to_value_dict={0: 'AUX_OUT_TRIGGER',
+ 1: 'AUX_IN_TRIGGER_ENABLE',
+ 13: 'AUX_IN_AUXILIARY'})
+
+ self.add_parameter(name='aux_io_param',
+ parameter_class=AlazarParameter,
+ unit=None,
+ value='NONE',
+ byte_to_value_dict={0: 'NONE',
+ 1: 'TRIG_SLOPE_POSITIVE',
+ 2: 'TRIG_SLOPE_NEGATIVE'})
+
+ # ----- Parameters for the acquire function -----
+ self.add_parameter(name='mode',
+ parameter_class=AlazarParameter,
+ label='Acquisiton mode',
+ unit=None,
+ value='NPT',
+ byte_to_value_dict={0x200: 'NPT', 0x400: 'TS'})
+ self.add_parameter(name='samples_per_record',
+ parameter_class=AlazarParameter,
+ label='Samples per Record',
+ unit=None,
+ value=1024,
+ vals=validators.Multiples(
+ divisor=self.samples_divisor, min_value=256))
+ self.add_parameter(name='records_per_buffer',
+ parameter_class=AlazarParameter,
+ label='Records per Buffer',
+ unit=None,
+ value=10,
+ vals=validators.Ints(min_value=0))
+ self.add_parameter(name='buffers_per_acquisition',
+ parameter_class=AlazarParameter,
+ label='Buffers per Acquisition',
+ unit=None,
+ value=10,
+ vals=validators.Ints(min_value=0))
+ self.add_parameter(name='channel_selection',
+ parameter_class=AlazarParameter,
+ label='Channel Selection',
+ unit=None,
+ value='AB',
+ byte_to_value_dict={1: 'A', 2: 'B', 3: 'AB'})
+ self.add_parameter(name='transfer_offset',
+ parameter_class=AlazarParameter,
+ label='Transer Offset',
+ unit='Samples',
+ value=0,
+ vals=validators.Ints(min_value=0))
+ self.add_parameter(name='external_startcapture',
+ parameter_class=AlazarParameter,
+ label='External Startcapture',
+ unit=None,
+ value='ENABLED',
+ byte_to_value_dict={0x0: 'DISABLED',
+ 0x1: 'ENABLED'})
+ self.add_parameter(name='enable_record_headers',
+ parameter_class=AlazarParameter,
+ label='Enable Record Headers',
+ unit=None,
+ value='DISABLED',
+ byte_to_value_dict={0x0: 'DISABLED',
+ 0x8: 'ENABLED'})
+ self.add_parameter(name='alloc_buffers',
+ parameter_class=AlazarParameter,
+ label='Alloc Buffers',
+ unit=None,
+ value='DISABLED',
+ byte_to_value_dict={0x0: 'DISABLED',
+ 0x20: 'ENABLED'})
+ self.add_parameter(name='fifo_only_streaming',
+ parameter_class=AlazarParameter,
+ label='Fifo Only Streaming',
+ unit=None,
+ value='DISABLED',
+ byte_to_value_dict={0x0: 'DISABLED',
+ 0x800: 'ENABLED'})
+ self.add_parameter(name='interleave_samples',
+ parameter_class=AlazarParameter,
+ label='Interleave Samples',
+ unit=None,
+ value='DISABLED',
+ byte_to_value_dict={0x0: 'DISABLED',
+ 0x1000: 'ENABLED'})
+ self.add_parameter(name='get_processed_data',
+ parameter_class=AlazarParameter,
+ label='Get Processed Data',
+ unit=None,
+ value='DISABLED',
+ byte_to_value_dict={0x0: 'DISABLED',
+ 0x2000: 'ENABLED'})
+ self.add_parameter(name='allocated_buffers',
+ parameter_class=AlazarParameter,
+ label='Allocated Buffers',
+ unit=None,
+ value=4,
+ vals=validators.Ints(min_value=0))
+
+ self.add_parameter(name='buffer_timeout',
+ parameter_class=AlazarParameter,
+ label='Buffer Timeout',
+ unit='ms',
+ value=1000,
+ vals=validators.Ints(min_value=0))
+
+ model = self.get_idn()['model']
+ if model != 'ATS9360':
+ raise Exception("The Alazar board kind is not 'ATS9360',"
+ " found '" + str(model) + "' instead.")
diff --git a/qcodes/instrument_drivers/AlazarTech/ATS9870.py b/qcodes/instrument_drivers/AlazarTech/ATS9870.py
index eebda198549..817a6f6d35c 100644
--- a/qcodes/instrument_drivers/AlazarTech/ATS9870.py
+++ b/qcodes/instrument_drivers/AlazarTech/ATS9870.py
@@ -150,6 +150,23 @@ def __init__(self, name, **kwargs):
unit='10 us',
value=0,
vals=validators.Ints(min_value=0))
+ self.add_parameter(name='aux_io_mode',
+ parameter_class=AlazarParameter,
+ label='AUX I/O Mode',
+ unit=None,
+ value='AUX_IN_AUXILIARY',
+ byte_to_value_dict={0: 'AUX_OUT_TRIGGER',
+ 1: 'AUX_IN_TRIGGER_ENABLE',
+ 13: 'AUX_IN_AUXILIARY'})
+
+ self.add_parameter(name='aux_io_param',
+ parameter_class=AlazarParameter,
+ unit=None,
+ value='NONE',
+ byte_to_value_dict={0: 'NONE',
+ 1: 'TRIG_SLOPE_POSITIVE',
+ 2: 'TRIG_SLOPE_NEGATIVE'})
+
# ----- Parameters for the acquire function -----
self.add_parameter(name='mode',
diff --git a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py
index a90269a8503..06865c5dee1 100644
--- a/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py
+++ b/qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py
@@ -27,8 +27,10 @@ def __init__(self, name, alazar_name, demodulation_frequency, **kwargs):
self.demodulation_frequency = demodulation_frequency
self.acquisitionkwargs = {}
self.samples_per_record = None
+ self.bits_per_sample = None
self.records_per_buffer = None
self.buffers_per_acquisition = None
+ self.allocated_buffers = None
# TODO(damazter) (S) this is not very general:
self.number_of_channels = 2
self.cos_list = None
diff --git a/qcodes/instrument_drivers/AlazarTech/acq_helpers.py b/qcodes/instrument_drivers/AlazarTech/acq_helpers.py
new file mode 100644
index 00000000000..785145d3887
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/acq_helpers.py
@@ -0,0 +1,74 @@
+import numpy as np
+from scipy import signal
+
+
+def filter_win(rec, cutoff, sample_rate, numtaps, axis=-1):
+ """
+ low pass filter, returns filtered signal using FIR window
+ filter
+
+ inputs:
+ record to filter
+ cutoff frequency
+ sampling rate
+ number of frequency comppnents to use in the filer
+ axis of record to apply filter along
+ """
+ nyq_rate = sample_rate / 2.
+ fir_coef = signal.firwin(numtaps, cutoff / nyq_rate)
+ filtered_rec = signal.lfilter(fir_coef, 1.0, rec, axis=axis)
+ return filtered_rec
+
+
+def filter_ls(rec, cutoff, sample_rate, numtaps, axis=-1):
+ """
+ low pass filter, returns filtered signal using FIR
+ least squared filter
+
+ inputs:
+ record to filter
+ cutoff frequency
+ sampling rate
+ number of frequency comppnents to use in the filer
+ axis of record to apply filter along
+ """
+ raise NotImplementedError
+
+
+def sample_to_volt_u12(raw_samples, bps):
+ """
+ Applies volts conversion for 12 bit sample data stored
+ in 2 bytes
+ return:
+ samples_magnitude_array
+ samples_phase_array
+ """
+
+ # right_shift 16-bit sample by 4 to get 12 bit sample
+ shifted_samples = np.right_shift(raw_samples, 4)
+
+ # Alazar calibration
+ code_zero = (1 << (bps - 1)) - 0.5
+ code_range = (1 << (bps - 1)) - 0.5
+
+ # TODO(nataliejpg) make this not hard coded
+ input_range_volts = 1
+ # Convert to volts
+ volt_samples = np.float64(input_range_volts *
+ (shifted_samples - code_zero) / code_range)
+
+ return volt_samples
+
+
+def roundup(num, to_nearest):
+ """
+ Rounds up the 'num' to the nearest multiple of 'to_nearest', all int
+
+ inputs:
+ num to be rounded up
+ to_nearest value to be rounded to int multiple of
+ return:
+ rounded up value
+ """
+ remainder = num % to_nearest
+ return int(num if remainder == 0 else num + to_nearest - remainder)
diff --git a/qcodes/instrument_drivers/AlazarTech/acquisition_tools.py b/qcodes/instrument_drivers/AlazarTech/acquisition_tools.py
new file mode 100644
index 00000000000..657f1f3be9f
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/acquisition_tools.py
@@ -0,0 +1,49 @@
+import numpy as np
+from scipy import signal
+
+
+def sample_to_volt_u12(raw_samples, input_range_volts, bps):
+ # right_shift 16-bit sample by 4 to get 12 bit sample
+ shifted_samples = np.right_shift(raw_samples, 4)
+
+ # Alazar calibration
+ code_zero = (1 << (bps - 1)) - 0.5
+ code_range = (1 << (bps - 1)) - 0.5
+
+ # Convert to volts
+ volt_samples = (input_range_volts *
+ (shifted_samples - code_zero) / code_range)
+
+ return volt_samples
+
+
+def filter_win(rec, cutoff, sample_rate, numtaps):
+ nyq_rate = sample_rate / 2.
+ fir_coef = signal.firwin(numtaps, cutoff / nyq_rate)
+ filtered_rec = signal.lfilter(fir_coef, 1.0, rec)
+ return filtered_rec
+
+
+def filter_ham(rec, cutoff, sample_rate, numtaps):
+ raise NotImplementedError
+ # sample_rate = self.sample_rate
+ # nyq_rate = sample_rate / 2.
+ # fir_coef = signal.firwin(numtaps,
+ # cutoff / nyq_rate,
+ # window="hamming")
+ # filtered_rec = 2 * signal.lfilter(fir_coef, 1.0, rec)
+ # return filtered_rec
+
+
+def filter_ls(rec, cutoff, sample_rate, numtaps):
+ raise NotImplementedError
+ # sample_rate = self.sample_rate
+ # nyq_rate = sample_rate / 2.
+ # bands = [0, cutoff / nyq_rate, cutoff / nyq_rate, 1]
+ # desired = [1, 1, 0, 0]
+ # fir_coef = signal.firls(numtaps,
+ # bands,
+ # desired,
+ # nyq=nyq_rate)
+ # filtered_rec = 2 * signal.lfilter(fir_coef, 1.0, rec)
+ # return filtered_rec
diff --git a/qcodes/instrument_drivers/AlazarTech/ave_controller.py b/qcodes/instrument_drivers/AlazarTech/ave_controller.py
new file mode 100644
index 00000000000..48d593e1db7
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/ave_controller.py
@@ -0,0 +1,556 @@
+import logging
+from .ATS import AcquisitionController
+import numpy as np
+from qcodes import Parameter
+import qcodes.instrument_drivers.AlazarTech.acq_helpers as helpers
+
+
+class AcqVariablesParam(Parameter):
+ """
+ Parameter of an AcquisitionController which has a _check_and_update_instr
+ function used for validation and to update instrument attributes and a
+ _get_default function which it uses to set the AcqVariablesParam to an
+ instrument caluclated default.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ check_and_update_fn: instrument function to be used for value
+ validation and updating instrument values
+ default_fn (optional): instrument function to be used to calculate
+ a default value to set parameter to
+ initial_value (optional): initial value for parameter
+ """
+
+ def __init__(self, name, instrument, check_and_update_fn,
+ default_fn=None, initial_value=None):
+ super().__init__(name)
+ self._instrument = instrument
+ self._save_val(initial_value)
+ setattr(self, '_check_and_update_instr', check_and_update_fn)
+ if default_fn is not None:
+ setattr(self, '_get_default', default_fn)
+
+ def set(self, value):
+ """
+ Function which checks value using validation function and then sets
+ the Parameter value to this value.
+
+ Args:
+ value: value to set the parameter to
+ """
+ self._check_and_update_instr(value, param_name=self.name)
+ self._save_val(value)
+
+ def get(self):
+ return self._latest()['value']
+
+ def to_default(self):
+ """
+ Function which executes the default_fn specified to calculate the
+ default value based on instrument values and then calls the set
+ function with this value
+ """
+ try:
+ default = self._get_default()
+ except AttributeError as e:
+ raise AttributeError('no default function for {} Parameter '
+ '{}'.format(self.name, e))
+ self.set(default)
+
+ def check(self):
+ """
+ Function which checks the current Parameter value using the specified
+ check_and_update_fn which can also serve to update instrument values.
+
+ Return:
+ True (if no errors raised when check_and_update_fn executed)
+ """
+ val = self._latest()['value']
+ self._check_and_update_instr(val, param_name=self.name)
+ return True
+
+
+class AveragedAcqParam(Parameter):
+ """
+ Software controlled parameter class for Alazar acquisition. To be used with
+ HD_Averaging_Controller (tested with ATS9360 board) for return of
+ averaged magnitude and phase data from the Alazar.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ demod_length: numer of demodulation frequencies the acq controller has
+ NB this is currently set in acq controller init but that's really
+ not nice and should be changed when possible
+
+ TODO(nataliejpg) setpoints (including names and units)
+ TODO(nataliejpg) setpoint units
+ """
+
+ def __init__(self, name, instrument, demod_length):
+ super().__init__(name)
+ self._instrument = instrument
+ self.acquisition_kwargs = {}
+ self.names = ('magnitude', 'phase')
+ if demod_length > 1:
+ self.shapes = ((demod_length, ), (demod_length, ))
+ else:
+ self.shapes = ((), ())
+
+ def update_demod_setpoints(self, demod_freqs):
+ """
+ Function to update the demodulation frequency setpoints to be called
+ when a demod_freq Parameter of the acq controller is updated
+
+ Args:
+ demod_freqs: numpy array of demodulation frequencies to use as
+ setpoints if length > 1
+ """
+ demod_length = self._instrument._demod_length
+ if demod_length > 1:
+ pass
+ # self.setpoints = ((demod_freqs, ), (demod_freqs, ))
+ else:
+ pass
+
+ def get(self):
+ """
+ Gets the magnitude and phase signal by calling acquire
+ on the alazar (which in turn calls the processing functions of the
+ aqcuisition controller before returning the processed data
+ demodulated at specified frequencies and averaged over samples,
+ records and buffers)
+
+ Returns:
+ mag: numpy array of magnitude, shape (demod_length, )
+ phase: numpy array of magnitude, shape (demod_length, )
+ """
+ mag, phase = self._instrument._get_alazar().acquire(
+ acquisition_controller=self._instrument,
+ **self.acquisition_kwargs)
+ return mag, phase
+
+
+class HD_Averaging_Controller(AcquisitionController):
+ """
+ This is the Acquisition Controller class which works with the ATS9360,
+ averaging over samples (limited by int_time and int_delay values),
+ records and buffers and demodulating with software reference signal(s).
+
+ Args:
+ name: name for this acquisition_conroller as an instrument
+ alazar_name: name of the alazar instrument such that this
+ controller can communicate with the Alazar
+ demod_length (default 1): number of demodulation frequencies
+ filter (default 'win'): filter to be used to filter out double freq
+ component ('win' - window, 'ls' - least squared, 'ave' - averaging)
+ numtaps (default 101): number of freq components used in filter
+ chan_b (default False): whether there is also a second channel of data
+ to be processed and returned
+ **kwargs: kwargs are forwarded to the Instrument base class
+
+ TODO(nataliejpg) test filter options
+ TODO(nataliejpg) finish implementation of channel b option
+ TODO(nataliejpg) what should be private?
+ TODO(nataliejpg) where should filter_dict live?
+ TODO(nataliejpg) demod_freq should be changeable number: maybe channels
+ """
+
+ filter_dict = {'win': 0, 'ls': 1, 'ave': 2}
+
+ def __init__(self, name, alazar_name, demod_length=1, filter='win',
+ numtaps=101, chan_b=False, **kwargs):
+ self.filter_settings = {'filter': self.filter_dict[filter],
+ 'numtaps': numtaps}
+ self.chan_b = chan_b
+ self._demod_length = demod_length
+ self.number_of_channels = 2
+ self.samples_per_record = None
+ self.sample_rate = None
+ super().__init__(name, alazar_name, **kwargs)
+
+ self.add_parameter(name='acquisition',
+ demod_length=demod_length,
+ parameter_class=AveragedAcqParam)
+ for i in range(demod_length):
+ self.add_parameter(name='demod_freq_{}'.format(i),
+ check_and_update_fn=self._update_demod_freq,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_time',
+ check_and_update_fn=self._update_int_time,
+ default_fn=self._int_time_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_delay',
+ check_and_update_fn=self._update_int_delay,
+ default_fn=self._int_delay_default,
+ parameter_class=AcqVariablesParam)
+
+ self.samples_divisor = self._get_alazar().samples_divisor
+
+ def _update_demod_freq(instr, value, param_name=None):
+ """
+ Function to validate and update acquisiton parameter when
+ a demod_freq_ Parameter is changed
+
+ Args:
+ value to update demodulation frequency to
+
+ Kwargs:
+ param_name: used to update demod_freq list used for updating
+ septionts of acquisition parameter
+
+ Checks:
+ 1e6 <= value <= 500e6
+ number of oscilation measured using current int_tiume param value
+ at this demod frequency value
+ oversampling rate for this demodulation frequency
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ setpoints of acquisiton parameter
+ """
+ if (value is None) or not (1e6 <= value <= 500e6):
+ raise ValueError('demod_freqs must be 1e6 <= value <= 500e6')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ min_oscilations_measured = instr.int_time() * value
+ oversampling = instr.sample_rate / (2 * value)
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ demod_freqs = instr.get_demod_freqs()
+ current_demod_index = ([int(s) for s in param_name.split()
+ if s.isdigit()][0])
+ demod_freqs[current_demod_index] = value
+ instr.acquisition.update_demod_setpoints(demod_freqs)
+
+ def _update_int_time(instr, value, **kwargs):
+ """
+ Function to validate value for int_time before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of oscilation measured in this time
+ oversampling rate
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_time must be 0 <= value <= 1')
+
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ if instr.get_max_demod_freq() is not None:
+ min_oscilations_measured = value * instr.get_max_demod_freq()
+ oversampling = instr.sample_rate / (2 * instr.get_max_demod_freq())
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ if instr.int_delay() is None:
+ instr.int_delay.to_default()
+
+ # update acquision kwargs and acq controller value
+ total_time = value + instr.int_delay()
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _update_int_delay(instr, value, **kwargs):
+ """
+ Function to validate value for int_delay before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of samples discarded >= numtaps
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ setpoints of acquisiton param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_delay must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samples_delay_min = (instr.filter_settings['numtaps'] - 1)
+ int_delay_min = samples_delay_min / instr.sample_rate
+ if value < int_delay_min:
+ logging.warning(
+ 'delay is less than recommended for filter choice: '
+ '(expect delay >= {})'.format(int_delay_min))
+
+ # update acquision kwargs and acq controller value
+ total_time = value + (instr.int_time() or 0)
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _int_delay_default(instr):
+ """
+ Function to generate default int_delay value
+
+ Returns:
+ minimum int_delay recommended for (numtaps - 1)
+ samples to be discarded as recommended for filter
+ """
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samp_delay = instr.filter_settings['numtaps'] - 1
+ return samp_delay / instr.sample_rate
+
+ def _int_time_default(instr):
+ """
+ Function to generate defult int_time value
+
+ Returns:
+ max total time for integration based on samples_per_record,
+ sample_rate and int_delay
+ """
+ if instr.samples_per_record is (0 or None):
+ raise ValueError('Cannot set int_time to max if acq controller'
+ ' has 0 or None samples_per_record, choose a '
+ 'value for int_time and samples_per_record will '
+ 'be set accordingly')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ total_time = ((instr.samples_per_record / instr.sample_rate) -
+ (instr.int_delay() or 0))
+ return total_time
+
+ def get_demod_freqs(self):
+ """
+ Function to get all the demod_freq parameter values in a list, v hacky
+
+ Returns:
+ freqs: numpy array of demodulation frequencies
+ """
+ freqs = list(filter(None, [getattr(self, 'demod_freq_{}'.format(c))()
+ for c in range(self._demod_length)]))
+ return np.array(freqs)
+
+ def get_max_demod_freq(self):
+ """
+ Returns:
+ the largest demodulation frequency
+
+ nb: really hacky and we should have channels in qcodes but we don't
+ (at time of writing)
+ """
+ freqs = self.get_demod_freqs()
+ if len(freqs) > 0:
+ return max(freqs)
+ else:
+ return None
+
+ def update_filter_settings(self, filter, numtaps):
+ """
+ Updates the settings of the filter for filtering out
+ double frwuency component for demodulation.
+
+ Args:
+ filter (str): filter type ('win' or 'ls')
+ numtaps (int): numtaps for filter
+ """
+ self.filter_settings.update({'filter': self.filter_dict[filter],
+ 'numtaps': numtaps})
+
+ def update_acquisition_kwargs(self, **kwargs):
+ """
+ Updates the kwargs to be used when
+ alazar_driver.acquisition() is called via a get call of the
+ acquisition AveragedAcqParam. Should be used by the user for
+ updating averaging settings since the 'samples_per_record'
+ kwarg is updated via the int_time and int_delay parameters
+
+ Kwargs (ints):
+ records_per_buffer
+ buffers_per_acquisition
+ allocated_buffers
+ """
+ if 'samples_per_record' in kwargs:
+ raise ValueError('With HD_Averaging_Controller '
+ 'samples_per_record cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting int_time and int_delay')
+ self.acquisition.acquisition_kwargs.update(**kwargs)
+
+ def pre_start_capture(self):
+ """
+ Called before capture start to update Acquisition Controller with
+ alazar acquisition params and set up software wave for demodulation.
+ """
+ alazar = self._get_alazar()
+ if self.samples_per_record != alazar.samples_per_record.get():
+ raise Exception('acq controller samples per record does not match'
+ ' instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.sample_rate != alazar.get_sample_rate():
+ raise Exception('acq controller sample rate does not match '
+ 'instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+
+ demod_freqs = self.get_demod_freqs()
+ if len(demod_freqs) == 0:
+ raise Exception('no demod_freqs set')
+
+ self.records_per_buffer = alazar.records_per_buffer.get()
+ self.buffers_per_acquisition = alazar.buffers_per_acquisition.get()
+ self.board_info = alazar.get_idn()
+ self.buffer = np.zeros(self.samples_per_record *
+ self.records_per_buffer *
+ self.number_of_channels)
+
+ integer_list = np.arange(self.samples_per_record)
+ angle_mat = 2 * np.pi * \
+ np.outer(demod_freqs, integer_list) / self.sample_rate
+ self.cos_mat = np.cos(angle_mat)
+ self.sin_mat = np.sin(angle_mat)
+
+ def pre_acquire(self):
+ pass
+
+ def handle_buffer(self, data):
+ """
+ Adds data from alazar to buffer (effectively averaging)
+ """
+ self.buffer += data
+
+ def post_acquire(self):
+ """
+ Processes the data according to ATS9360 settings, splitting into
+ records and averaging over them, then applying demodulation fit
+ nb: currently only channel A
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, samples_used)
+ phase (numpy array): shape = (demod_length, samples_used)
+ """
+
+ # for ATS9360 samples are arranged in the buffer as follows:
+ # S00A, S00B, S01A, S01B...S10A, S10B, S11A, S11B...
+ # where SXYZ is record X, sample Y, channel Z.
+
+ # break buffer up into records and averages over them
+ reshaped_buf = self.buffer.reshape(self.records_per_buffer,
+ self.samples_per_record,
+ self.number_of_channels)
+ recordA = np.uint16(np.mean(reshaped_buf[:, :, 0], axis=0) /
+ self.buffers_per_acquisition)
+
+ # TODO(nataliejpg): test above version works on alazar and
+ # compare performance
+
+ # records_per_acquisition = (self.buffers_per_acquisition *
+ # self.records_per_buffer)
+ # recA = np.zeros(self.samples_per_record)
+ # for i in range(self.records_per_buffer):
+ # i0 = (i * self.samples_per_record * self.number_of_channels)
+ # i1 = (i0 + self.samples_per_record * self.number_of_channels)
+ # recA += self.buffer[i0:i1:self.number_of_channels]
+ # recordA = np.uint16(recA / records_per_acquisition)
+
+ # do demodulation
+ magA, phaseA = self._fit(recordA)
+
+ # same for chan b
+ if self.chan_b:
+ raise NotImplementedError('chan b code not complete')
+
+ return magA, phaseA
+
+ def _fit(self, rec):
+ """
+ Applies volts conversion, demodulation fit, low bandpass filter
+ and integration limits to samples array
+
+ Args:
+ rec (numpy array): record from alazar to be multiplied
+ with the software signal, filtered and limited
+ to integration limits shape = (samples_taken, )
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, )
+ phase (numpy array): shape = (demod_length, )
+ """
+ # convert rec to volts
+ bps = self.board_info['bits_per_sample']
+ if bps == 12:
+ volt_rec = helpers.sample_to_volt_u12(rec, bps)
+ else:
+ logging.warning('sample to volt conversion does not exist for'
+ ' bps != 12, centered raw samples returned')
+ volt_rec = rec - np.mean(rec)
+
+ # volt_rec to matrix and multiply with demodulation signal matrices
+ volt_rec_mat = np.outer(np.ones(self._demod_length), volt_rec)
+ re_mat = np.multiply(volt_rec_mat, self.cos_mat)
+ im_mat = np.multiply(volt_rec_mat, self.sin_mat)
+
+ # filter out higher freq component
+ cutoff = self.get_max_demod_freq() / 10
+ if self.filter_settings['filter'] == 0:
+ re_filtered = helpers.filter_win(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_win(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 1:
+ re_filtered = helpers.filter_ls(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_ls(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 2:
+ re_filtered = re_mat
+ im_filtered = im_mat
+
+ # apply integration limits
+ beginning = int(self.int_delay() * self.sample_rate)
+ end = beginning + int(self.int_time() * self.sample_rate)
+
+ re_limited = re_filtered[:, beginning:end]
+ im_limited = im_filtered[:, beginning:end]
+
+ # convert to magnitude and phase
+ complex_mat = re_limited + im_limited * 1j
+ magnitude = np.mean(abs(complex_mat), axis=-1)
+ phase = np.mean(np.angle(complex_mat, deg=True), axis=-1)
+
+ return magnitude, phase
diff --git a/qcodes/instrument_drivers/AlazarTech/basic_controller.py b/qcodes/instrument_drivers/AlazarTech/basic_controller.py
new file mode 100644
index 00000000000..176749e5784
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/basic_controller.py
@@ -0,0 +1,159 @@
+import logging
+from .ATS import AcquisitionController
+import numpy as np
+import qcodes.instrument_drivers.AlazarTech.acq_helpers as helpers
+from qcodes import Parameter
+
+
+class SampleSweep(Parameter):
+ """
+ Hardware controlled parameter class for Alazar acquisition. To be used with
+ Acquisition Controller (tested with ATS9360 board)
+
+ Alazar Instrument 'acquire' returns a buffer of data each time a buffer is
+ filled (channels * samples * records) which is processed by the
+ post_acquire function of the Acquisition Controller and finally the
+ processed result is returned when the SampleSweep parameter is called.
+
+ :args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ """
+
+ def __init__(self, name, instrument):
+ super().__init__(name)
+ self._instrument = instrument
+ self.acquisition_kwargs = {}
+ self.names = ('A', 'B')
+
+ def get(self):
+ """
+ Gets the samples for channels A and B by calling acquire
+ on the alazar (which in turn calls the processing functions of the
+ aqcuisition controller before returning the reshaped data averaged
+ over records and buffers)
+
+ returns:
+ recordA: numpy array of channel A acquisition
+ recordB: numpy array of channel B acquisition
+ """
+ recordA, recordB = self._instrument._get_alazar().acquire(
+ acquisition_controller=self._instrument,
+ **self.acquisition_kwargs)
+ return recordA, recordB
+
+
+class Basic_Acquisition_Controller(AcquisitionController):
+ """
+ This class represents an acquisition controller. It is designed to be used
+ primarily to check the function of the Alazar driver and returns the
+ samples on channel A and channel B, averaging over recoirds and buffers
+
+ args:
+ name: name for this acquisition_conroller as an instrument
+ alazar_name: the name of the alazar instrument such that this controller
+ can communicate with the Alazar
+ **kwargs: kwargs are forwarded to the Instrument base class
+ """
+
+ def __init__(self, name, alazar_name, **kwargs):
+ self.number_of_channels = 2
+ # make a call to the parent class and by extension,
+ # create the parameter structure of this class
+ super().__init__(name, alazar_name, **kwargs)
+
+ self.add_parameter(name='acquisition',
+ parameter_class=SampleSweep)
+
+ def update_acquisition_kwargs(self, **kwargs):
+ """
+ This method must be used to update the kwargs used for the acquisition
+ with the alazar_driver.acquire
+ :param kwargs:
+ :return:
+ """
+ self.samples_per_record = kwargs['samples_per_record']
+ self.acquisition.shapes = (
+ (self.samples_per_record,), (self.samples_per_record,))
+ self.acquisition.acquisition_kwargs.update(**kwargs)
+
+ def pre_start_capture(self):
+ """
+ See AcquisitionController
+ :return:
+ """
+ alazar = self._get_alazar()
+ if self.samples_per_record != alazar.samples_per_record.get():
+ raise Exception('Instrument samples_per_record settings does '
+ 'not match acq controller value, most likely '
+ 'need to call update_acquisition_settings')
+ self.records_per_buffer = alazar.records_per_buffer.get()
+ self.buffers_per_acquisition = alazar.buffers_per_acquisition.get()
+ self.board_info = alazar.get_idn()
+ self.buffer = np.zeros(self.samples_per_record *
+ self.records_per_buffer *
+ self.number_of_channels)
+
+ def pre_acquire(self):
+ """
+ See AcquisitionController
+ :return:
+ """
+ pass
+
+ def handle_buffer(self, data):
+ """
+ Function which is called during the Alazar acquire each time a buffer
+ is completed. In this acquistion controller these buffers are just
+ added together (ie averaged)
+ :return:
+ """
+ self.buffer += data
+
+ def post_acquire(self):
+ """
+ Function which is called at the end of the Alazar acquire function to
+ signal completion and trigger data processing. This acquisition
+ controller has averaged over the buffers acquired so has one buffer of
+ data which is splits into records and channels, averages over records
+ and returns the samples for each channel.
+
+ return:
+ recordA: numpy array of channel A acquisition
+ recordB: numpy array of channel B acquisition
+ """
+
+ # for ATS9360 samples are arranged in the buffer as follows:
+ # S00A, S00B, S01A, S01B...S10A, S10B, S11A, S11B...
+ # where SXYZ is record X, sample Y, channel Z.
+
+ # break buffer up into records, averages over them and returns samples
+ records_per_acquisition = (self.buffers_per_acquisition *
+ self.records_per_buffer)
+
+ recA = np.zeros(self.samples_per_record)
+ for i in range(self.records_per_buffer):
+ i0 = (i * self.samples_per_record * self.number_of_channels)
+ i1 = (i0 + self.samples_per_record * self.number_of_channels)
+ recA += self.buffer[i0:i1:self.number_of_channels]
+ recordA = np.uint16(recA / records_per_acquisition)
+
+ recB = np.zeros(self.samples_per_record)
+ for i in range(self.records_per_buffer):
+ i0 = (i * self.samples_per_record * self.number_of_channels + 1)
+ i1 = (i0 + self.samples_per_record * self.number_of_channels)
+ recB += self.buffer[i0:i1:self.number_of_channels]
+ recordB = np.uint16(recB / records_per_acquisition)
+
+ # converts to volts if bits per sample is 12 (as ATS9360)
+ bps = self.board_info['bits_per_sample']
+ if bps == 12:
+ volt_rec_A = helpers.sample_to_volt_u12(recordA, bps)
+ volt_rec_B = helpers.sample_to_volt_u12(recordB, bps)
+ else:
+ logging.warning('sample to volt conversion does not exist for bps '
+ '!= 12, raw samples centered on 0 and returned')
+ volt_rec_A = recordA - np.mean(recordA)
+ volt_rec_B = recordB - np.mean(recordB)
+
+ return volt_rec_A, volt_rec_B
diff --git a/qcodes/instrument_drivers/AlazarTech/buf_rec_controller.py b/qcodes/instrument_drivers/AlazarTech/buf_rec_controller.py
new file mode 100644
index 00000000000..6f8f75ee6f0
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/buf_rec_controller.py
@@ -0,0 +1,688 @@
+import logging
+from .ATS import AcquisitionController
+import numpy as np
+from qcodes import Parameter
+import qcodes.instrument_drivers.AlazarTech.acq_helpers as helpers
+
+
+class AcqVariablesParam(Parameter):
+ """
+ Parameter of an AcquisitionController which has a _check_and_update_instr
+ function used for validation and to update instrument attributes and a
+ _get_default function which it uses to set the AcqVariablesParam to an
+ instrument caluclated default.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ check_and_update_fn: instrument function to be used for value
+ validation and updating instrument values
+ default_fn (optional): instrument function to be used to calculate
+ a default value to set parameter to
+ initial_value (optional): initial value for parameter
+ """
+
+ def __init__(self, name, instrument, check_and_update_fn,
+ default_fn=None, initial_value=None):
+ super().__init__(name)
+ self._instrument = instrument
+ self._save_val(initial_value)
+ setattr(self, '_check_and_update_instr', check_and_update_fn)
+ if default_fn is not None:
+ setattr(self, '_get_default', default_fn)
+
+ def set(self, value):
+ """
+ Function which checks value using validation function and then sets
+ the Parameter value to this value.
+
+ Args:
+ value: value to set the parameter to
+ """
+ self._check_and_update_instr(value, param_name=self.name)
+ self._save_val(value)
+
+ def get(self):
+ return self._latest()['value']
+
+ def to_default(self):
+ """
+ Function which executes the default_fn specified to calculate the
+ default value based on instrument values and then calls the set
+ function with this value
+ """
+ try:
+ default = self._get_default()
+ except AttributeError as e:
+ raise AttributeError('no default function for {} Parameter '
+ '{}'.format(self.name, e))
+ self.set(default)
+
+ def check(self):
+ """
+ Function which checks the current Parameter value using the specified
+ check_and_update_fn which can also serve to update instrument values.
+
+ Return:
+ True (if no errors raised when check_and_update_fn executed)
+ """
+ val = self._latest()['value']
+ self._check_and_update_instr(val, param_name=self.name)
+ return True
+
+
+class BuffersRecordsAcqParam(Parameter):
+ """
+ Software controlled parameter class for Alazar acquisition. To be used with
+ HD_Records_Controller (tested with ATS9360 board) for return of
+ averaged magnitude and phase data from the Alazar.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+
+ TODO(nataliejpg) setpoints (including names and units)
+ """
+
+ def __init__(self, name, instrument):
+ super().__init__(name)
+ self._instrument = instrument
+ self.acquisition_kwargs = {}
+ self.names = ('magnitude', 'phase')
+
+ def update_buf_sweep(self, buf_npts, buf_start=None, buf_stop=None):
+ """
+ Function which updates the shape of the parameter (and it's setpoints
+ when this is fixed)
+
+ Args:
+ buf_npts: number of buffers returned
+ buf_start (optional): start value of buffers returned
+ buf_stop (optional): stop value of records returned
+ """
+ demod_length = self._instrument._demod_length
+ # self._buf_list = tuple(np.linspace(buf_start,
+ # buf_stop, num=buf_npts))
+ self._buf_npts = buf_npts
+ if demod_length > 1:
+ # demod_freqs = self._instrument.get_demod_freqs()
+ # self.setpoints = ((demod_freqs, self._buf_list, self._rec_list),
+ # (demod_freqs, self._buf_list, self._rec_list))
+ self.shapes = ((demod_length, self._buf_npts, self._rec_npts),
+ (demod_length, self._buf_npts, self._rec_npts))
+ else:
+ self.shapes = ((self._buf_npts, self._rec_npts),
+ (self._buf_npts, self._rec_npts))
+ # self.setpoints = ((self._buf_list, self._rec_list),
+ # (self._buf_list, self._rec_list))
+
+ def update_rec_sweep(self, rec_npts, rec_start=None, rec_stop=None):
+ """
+ Function which updates the shape of the parameter (and it's setpoints
+ when this is fixed)
+
+ Args:
+ rec_npts: number of records returned after processing
+ rec_start (optional): start value of records returned
+ rec_stop (optional): stop value of records returned
+ """
+ demod_length = self._instrument._demod_length
+ # self._rec_list = tuple(np.linspace(rec_start,
+ # rec_stop, num=rec_npts))
+ self._rec_npts = rec_npts
+ if demod_length > 1:
+ # demod_freqs = self._instrument.get_demod_freqs()
+ # self.setpoints = ((demod_freqs, self._buf_list, self._rec_list),
+ # (demod_freqs, self._buf_list, self._rec_list))
+ self.shapes = ((demod_length, self._buf_npts, self._rec_npts),
+ (demod_length, self._buf_npts, self._rec_npts))
+ else:
+ self.shapes = ((self._buf_npts, self._rec_npts),
+ (self._buf_npts, self._rec_npts))
+ # self.setpoints = ((self._buf_list, self._rec_list),
+ # (self._buf_list, self._rec_list))
+
+ def update_demod_setpoints(self, demod_freqs):
+ """
+ Function to update the demodulation frequency setpoints to be called
+ when a demod_freq Parameter of the acq controller is updated
+
+ Args:
+ demod_freqs: numpy array of demodulation frequencies to use as
+ setpoints if length > 1
+ """
+ demod_length = self._instrument._demod_length
+ if demod_length > 1:
+ pass
+ # self.setpoints = ((demod_freqs, self._buf_list, self._rec_list),
+ # (demod_freqs, self._buf_list, self._rec_list))
+ else:
+ pass
+
+ def get(self):
+ """
+ Gets the magnitude and phase signal by calling acquire
+ on the alazar (which in turn calls the processing functions of the
+ aqcuisition controller before returning the processed data
+ demodulated at specified frequencies and averaged over samples
+ and buffers)
+
+ Returns:
+ mag: numpy array of magnitude, shape (demod_length, records)
+ phase: numpy array of magnitude, shape (demod_length, records)
+ """
+ mag, phase = self._instrument._get_alazar().acquire(
+ acquisition_controller=self._instrument,
+ **self.acquisition_kwargs)
+ return mag, phase
+
+
+class HD_BuffersRecords_Controller(AcquisitionController):
+ """
+ This is the Acquisition Controller class which works with the ATS9360,
+ averaging over samples (limited by int_time and int_delay values) and
+ buffers and demodulating with software reference signal(s).
+
+ Args:
+ name: name for this acquisition_conroller as an instrument
+ alazar_name: name of the alazar instrument such that this
+ controller can communicate with the Alazar
+ demod_length (default 1): number of demodulation frequencies
+ filter (default 'win'): filter to be used to filter out double freq
+ component ('win' - window, 'ls' - least squared, 'ave' - averaging)
+ numtaps (default 101): number of freq components used in filter
+ chan_b (default False): whether there is also a second channel of data
+ to be processed and returned
+ **kwargs: kwargs are forwarded to the Instrument base class
+
+ TODO(nataliejpg) test filter options
+ TODO(nataliejpg) finish implementation of channel b option
+ TODO(nataliejpg) what should be private?
+ TODO(nataliejpg) where should filter_dict live?
+ TODO(nataliejpg) demod_freq should be changeable number: maybe channels
+ TODO(nataliejpg) make record param 'start' and 'stop' meaningful
+ TODO(nataliejpg) make buffers param 'start' and 'stop' meaningful
+ """
+
+ filter_dict = {'win': 0, 'ls': 1, 'ave': 2}
+
+ def __init__(self, name, alazar_name, demod_length=1, filter='win',
+ numtaps=101, chan_b=False, **kwargs):
+ self.filter_settings = {'filter': self.filter_dict[filter],
+ 'numtaps': numtaps}
+ self.chan_b = chan_b
+ self._demod_length = demod_length
+ self.number_of_channels = 2
+ self.samples_per_record = None
+ self.sample_rate = None
+ super().__init__(name, alazar_name, **kwargs)
+
+ self.add_parameter(name='acquisition',
+ parameter_class=BuffersRecordsAcqParam)
+ for i in range(demod_length):
+ self.add_parameter(name='demod_freq_{}'.format(i),
+ check_and_update_fn=self._update_demod_freq,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_time',
+ check_and_update_fn=self._update_int_time,
+ default_fn=self._int_time_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_delay',
+ check_and_update_fn=self._update_int_delay,
+ default_fn=self._int_delay_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='record_num',
+ check_and_update_fn=self._update_rec_num,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='buffer_num',
+ check_and_update_fn=self._update_buf_num,
+ parameter_class=AcqVariablesParam)
+
+ self.samples_divisor = self._get_alazar().samples_divisor
+
+ def _update_demod_freq(instr, value, param_name=None):
+ """
+ Function to validate and update acquisiton parameter when
+ a demod_freq_ Parameter is changed
+
+ Args:
+ value to update demodulation frequency to
+
+ Kwargs:
+ param_name: used to update demod_freq list used for updating
+ septionts of acquisition parameter
+
+ Checks:
+ 1e6 <= value <= 500e6
+ number of oscilation measured using current int_tiume param value
+ at this demod frequency value
+ oversampling rate for this demodulation frequency
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ setpoints of acquisiton parameter
+ """
+ if (value is None) or not (1e6 <= value <= 500e6):
+ raise ValueError('demod_freqs must be 1e6 <= value <= 500e6')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ min_oscilations_measured = instr.int_time() * value
+ oversampling = instr.sample_rate / (2 * value)
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ demod_freqs = instr.get_demod_freqs()
+ current_demod_index = ([int(s) for s in param_name.split()
+ if s.isdigit()][0])
+ demod_freqs[current_demod_index] = value
+ instr.acquisition.update_demod_setpoints(demod_freqs)
+
+ def _update_record_num(instr, value, **kwargs):
+ """
+ Function to update the record number, and instr attributes. Main
+ reason to record_num as a parameter is so we can more easily push the
+ record number setting up to other instruments which will control this.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 1 <= value <= 1000
+
+ Sets:
+ acquisition_kwarg['records_per_buffer'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (1 <= value <= 1000):
+ raise ValueError('int_time must be 1 <= value <= 1000')
+
+ # update acquisition parameter shapes
+ instr.acquisition.update_sweep(value)
+
+ # update acquision kwargs
+ instr.acquisition.acquisition_kwargs.update(
+ records_per_buffer=value)
+
+ def _update_buffer_num(instr, value, **kwargs):
+ """
+ Function to update the buffer number, and instr attributes. By now
+ I'm just making a parameter because it follows the patter of having a
+ parameter for everything we want to preserve and not average over.
+ At some point this should maybe be done more smartly with having
+ "number of averages" and the driver working out how to allocate
+ records and buffers accordingly depending on what is being averaged
+ over. If you have ideas let me know. nataliejpg
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 1 <= value <= 100000
+
+ Sets:
+ acquisition_kwarg['buffers_per_acquisition'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (1 <= value <= 100000):
+ raise ValueError('int_time must be 1 <= value <= 1000')
+
+ # update acquisition parameter shapes
+ instr.acquisition.update_buf_sweep(value)
+
+ # update acquision kwargs
+ instr.acquisition.acquisition_kwargs.update(
+ buffers_per_acquisition=value)
+
+ def _update_int_time(instr, value, **kwargs):
+ """
+ Function to validate value for int_time before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of oscilation measured in this time
+ oversampling rate
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_time must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ if instr.get_max_demod_freq() is not None:
+ oscilations_measured = value * instr.get_max_demod_freq()
+ oversampling = instr.sample_rate / (2 * instr.get_max_demod_freq())
+ if oscilations_measured < 10:
+ logging.warning('{} oscilations measured, recommend at '
+ 'least 10: decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ if instr.int_delay() is None:
+ instr.int_delay.to_default()
+
+ # update acquision kwargs and acq controller value
+ total_time = value + instr.int_delay()
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _update_int_delay(instr, value, **kwargs):
+ """
+ Function to validate value for int_delay before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of samples discarded >= numtaps
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_delay must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samples_delay_min = (instr.filter_settings['numtaps'] - 1)
+ int_delay_min = samples_delay_min / instr.sample_rate
+ if value < int_delay_min:
+ logging.warning(
+ 'delay is less than recommended for filter choice: '
+ '(expect delay >= {})'.format(int_delay_min))
+
+ # update acquision kwargs and acq controller value
+ total_time = value + (instr.int_time() or 0)
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _int_delay_default(instr):
+ """
+ Function to generate default int_delay value
+
+ Returns:
+ minimum int_delay recommended for (numtaps - 1)
+ samples to be discarded as recommended for filter
+ """
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samp_delay = instr.filter_settings['numtaps'] - 1
+ return samp_delay / instr.sample_rate
+
+ def _int_time_default(instr):
+ """
+ Function to generate defult int_time value
+
+ Returns:
+ max total time for integration based on samples_per_record,
+ sample_rate and int_delay
+ """
+ if instr.samples_per_record is (0 or None):
+ raise ValueError('Cannot set int_time to max if acq controller'
+ ' has 0 or None samples_per_record, choose a '
+ 'value for int_time and samples_per_record will '
+ 'be set accordingly')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ total_time = ((instr.samples_per_record / instr.sample_rate) -
+ (instr.int_delay() or 0))
+ return total_time
+
+ def get_demod_freqs(self):
+ """
+ Function to get all the demod_freq parameter values in a list, v hacky
+
+ Returns:
+ freqs: numpy array of demodulation frequencies
+ """
+ freqs = list(filter(None, [getattr(self, 'demod_freq_{}'.format(c))()
+ for c in range(self._demod_length)]))
+ return np.array(freqs)
+
+ def get_max_demod_freq(self):
+ """
+ Returns:
+ the largest demodulation frequency
+
+ nb: really hacky and we should have channels in qcodes but we don't
+ (at time of writing)
+ """
+ freqs = self.get_demod_freqs()
+ if len(freqs) > 0:
+ return max(freqs)
+ else:
+ return None
+
+ def update_filter_settings(self, filter, numtaps):
+ """
+ Updates the settings of the filter for filtering out
+ double frwuency component for demodulation.
+
+ Args:
+ filter (str): filter type ('win' or 'ls')
+ numtaps (int): numtaps for filter
+ """
+ self.filter_settings.update({'filter': self.filter_dict[filter],
+ 'numtaps': numtaps})
+
+ def update_acquisition_kwargs(self, **kwargs):
+ """
+ Updates the kwargs to be used when
+ alazar_driver.acquisition() is called via a get call of the
+ acquisition BuffersRecordsAcqParam. Should be used by the user for
+ updating allocated_buffers kwarg since samples_per_record,
+ records_per_buffer and buffers_per_acquisition are updated via the
+ int_time, int_delay, record_num and buffer_num parameters
+
+ Kwargs (ints):
+ allocated_buffers
+ """
+ if 'samples_per_record' in kwargs:
+ raise ValueError('With HD_BuffersRecords_Controller '
+ 'samples_per_record cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting int_time and int_delay')
+ if 'records_per_buffer' in kwargs:
+ raise ValueError('With HD_BuffersRecords_Controller '
+ 'records_per_buffer cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting record_num')
+ if 'records_per_buffer' in kwargs:
+ raise ValueError('With HD_BuffersRecords_Controller '
+ 'records_per_buffer cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting buffer_num')
+ self.acquisition.acquisition_kwargs.update(**kwargs)
+
+ def pre_start_capture(self):
+ """
+ Called before capture start to update Acquisition Controller with
+ alazar acquisition params and set up software wave for demodulation.
+ """
+ alazar = self._get_alazar()
+ if self.samples_per_record != alazar.samples_per_record.get():
+ raise Exception('acq controller samples per record does not match'
+ ' instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.sample_rate != alazar.get_sample_rate():
+ raise Exception('acq controller sample rate does not match '
+ 'instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.record_num() != alazar.records_per_buffer.get():
+ raise Exception('acq controller record_num does not match '
+ 'instrument value, most likely need '
+ 'to call set and check record_num')
+ if self.buffer_num() != alazar.buffers_per_acquisition.get():
+ raise Exception('acq controller buffer_num does not match '
+ 'instrument value, most likely need '
+ 'to call set and check buffer_num')
+
+ demod_freqs = self.get_demod_freqs()
+ if len(demod_freqs) == 0:
+ raise Exception('no demod_freqs set')
+
+ self.board_info = alazar.get_idn()
+ self.buffer_count = 0
+ self.samples_per_buffer = (self.samples_per_record *
+ self.record_num() *
+ self.buffer_num() *
+ self.number_of_channels)
+ self.buffer = np.zeros(self.samples_per_record *
+ self.buffer_num() *
+ self.record_num() *
+ self.number_of_channels)
+
+ mat_shape = (self._demod_length, self.buffer_num(),
+ self.record_num(), self.samples_per_record)
+ integer_list = np.arange(self.samples_per_record)
+ integer_mat = (np.outer(np.ones(self.buffer_num()),
+ np.outer(np.ones(self.record_num()),
+ integer_list)))
+ angle_mat = 2 * np.pi * \
+ np.outer(demod_freqs, integer_mat).reshape(
+ mat_shape) / self.sample_rate
+ self.cos_mat = np.cos(angle_mat)
+ self.sin_mat = np.sin(angle_mat)
+
+ def pre_acquire(self):
+ pass
+
+ def handle_buffer(self, data):
+ """
+ Adds data from alazar to buffer (effectively averaging)
+ """
+ i0 = self.buffer_count * self.samples_per_buffer
+ i1 = i0 + self.samples_per_buffer
+ self.buffer[i0:i1] = data
+ self.buf_count += 1
+
+ def post_acquire(self):
+ """
+ Processes the data according to ATS9360 settings, splitting into
+ records and then applying demodulation fit
+ nb: currently only channel A
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, records_per_buffer)
+ phase (numpy array): shape = (demod_length, records_per_buffer
+ """
+ # for ATS9360 samples are arranged in the buffer as follows:
+ # S00A, S00B, S01A, S01B...S10A, S10B, S11A, S11B...
+ # where SXYZ is record X, sample Y, channel Z.
+
+ # break buffer up into records and shapes to be (records, samples)
+ reshaped_buf = np.uint16(self.buffer.reshape(self.buffer_num(),
+ self.record_num(),
+ self.samples_per_buffer,
+ self.number_of_channels))
+
+ recA = reshaped_buf[:, :, :, 0]
+
+ magA, phaseA = self._fit(recA)
+
+ # same for chan b
+ if self.chan_b:
+ # recB = reshaped_buf[:, :, :, 1]
+ # magB, phaseB = self, _fit(recB)
+ raise NotImplementedError('chan b code not complete')
+
+ self.buf_count = 0
+
+ return magA, phaseA
+
+ def _fit(self, rec):
+ """
+ Applies volts conversion, demodulation fit, low bandpass filter
+ and integration limits to samples array
+
+ Args:
+ rec (numpy array): record from alazar to be multiplied
+ with the software signal, filtered and limited
+ to integration limits shape = (samples_taken, )
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, records_per_buffer)
+ phase (numpy array): shape = (demod_length, records_per_buffer)
+ """
+ # convert rec to volts
+ bps = self.board_info['bits_per_sample']
+ if bps == 12:
+ volt_rec = helpers.sample_to_volt_u12(rec, bps)
+ else:
+ logging.warning('sample to volt conversion does not exist for'
+ ' bps != 12, centered raw samples returned')
+ # TODO(nataliejpg): think about this recentering makes sense here
+ volt_rec = rec - np.mean(rec)
+
+ # volt_rec to matrix and multiply with demodulation signal matrices
+ mat_shape = (self._demod_length, self.buffer_num(), self.record_num(),
+ self.samples_per_record)
+ volt_rec_mat = np.outer(
+ np.ones(self._demod_length), volt_rec).reshape(mat_shape)
+ re_mat = np.multiply(volt_rec_mat, self.cos_mat)
+ im_mat = np.multiply(volt_rec_mat, self.sin_mat)
+
+ # filter out higher freq component
+ cutoff = self.get_max_demod_freq() / 10
+ if self.filter_settings['filter'] == 0:
+ re_filtered = helpers.filter_win(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_win(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 1:
+ re_filtered = helpers.filter_ls(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_ls(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 2:
+ re_filtered = re_mat
+ im_filtered = im_mat
+
+ # apply integration limits
+ beginning = int(self.int_delay() * self.sample_rate)
+ end = beginning + int(self.int_time() * self.sample_rate)
+
+ re_limited = re_filtered[:, :, beginning:end]
+ im_limited = im_filtered[:, :, beginning:end]
+
+ # convert to magnitude and phase
+ complex_mat = re_limited + im_limited * 1j
+ magnitude = np.mean(abs(complex_mat), axis=-1)
+ phase = np.mean(np.angle(complex_mat, deg=True), axis=-1)
+
+ return magnitude, phase
diff --git a/qcodes/instrument_drivers/AlazarTech/rec_controller.py b/qcodes/instrument_drivers/AlazarTech/rec_controller.py
new file mode 100644
index 00000000000..6053f71c066
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/rec_controller.py
@@ -0,0 +1,613 @@
+import logging
+from .ATS import AcquisitionController
+import numpy as np
+from qcodes import Parameter
+import qcodes.instrument_drivers.AlazarTech.acq_helpers as helpers
+
+
+class AcqVariablesParam(Parameter):
+ """
+ Parameter of an AcquisitionController which has a _check_and_update_instr
+ function used for validation and to update instrument attributes and a
+ _get_default function which it uses to set the AcqVariablesParam to an
+ instrument caluclated default.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ check_and_update_fn: instrument function to be used for value
+ validation and updating instrument values
+ default_fn (optional): instrument function to be used to calculate
+ a default value to set parameter to
+ initial_value (optional): initial value for parameter
+ """
+
+ def __init__(self, name, instrument, check_and_update_fn,
+ default_fn=None, initial_value=None):
+ super().__init__(name)
+ self._instrument = instrument
+ self._save_val(initial_value)
+ setattr(self, '_check_and_update_instr', check_and_update_fn)
+ if default_fn is not None:
+ setattr(self, '_get_default', default_fn)
+
+ def set(self, value):
+ """
+ Function which checks value using validation function and then sets
+ the Parameter value to this value.
+
+ Args:
+ value: value to set the parameter to
+ """
+ self._check_and_update_instr(value, param_name=self.name)
+ self._save_val(value)
+
+ def get(self):
+ return self._latest()['value']
+
+ def to_default(self):
+ """
+ Function which executes the default_fn specified to calculate the
+ default value based on instrument values and then calls the set
+ function with this value
+ """
+ try:
+ default = self._get_default()
+ except AttributeError as e:
+ raise AttributeError('no default function for {} Parameter '
+ '{}'.format(self.name, e))
+ self.set(default)
+
+ def check(self):
+ """
+ Function which checks the current Parameter value using the specified
+ check_and_update_fn which can also serve to update instrument values.
+
+ Return:
+ True (if no errors raised when check_and_update_fn executed)
+ """
+ val = self._latest()['value']
+ self._check_and_update_instr(val, param_name=self.name)
+ return True
+
+
+class RecordsAcqParam(Parameter):
+ """
+ Software controlled parameter class for Alazar acquisition. To be used with
+ HD_Records_Controller (tested with ATS9360 board) for return of
+ averaged magnitude and phase data from the Alazar.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+
+ TODO(nataliejpg) setpoints (including names and units)
+ """
+
+ def __init__(self, name, instrument):
+ super().__init__(name)
+ self._instrument = instrument
+ self.acquisition_kwargs = {}
+ self.names = ('magnitude', 'phase')
+
+ def update_sweep(self, npts, start=None, stop=None):
+ """
+ Function which updates the shape of the parameter (and it's setpoints
+ when this is fixed)
+
+ Args:
+ npts: number of records returned
+ start (optional): start value of records returned (if relevant)
+ stop (optional): stop value of records returned (if relevant)
+ """
+ demod_length = self._instrument._demod_length
+ # self.rec_list = tuple(np.linspace(start, stop, num=npts))
+ if demod_length > 1:
+ # demod_freqs = self._instrument.get_demod_freqs()
+ # self.setpoints = ((demod_freqs, self._rec_list),
+ # (demod_freqs, self._rec_list))
+ self.shapes = ((demod_length, npts), (demod_length, npts))
+ else:
+ self.shapes = ((npts,), (npts,))
+ # self.setpoints = ((self._rec_list,), (self._rec_list,))
+
+ def update_demod_setpoints(self, demod_freqs):
+ """
+ Function to update the demodulation frequency setpoints to be called
+ when a demod_freq Parameter of the acq controller is updated
+
+ Args:
+ demod_freqs: numpy array of demodulation frequencies to use as
+ setpoints if length > 1
+ """
+ demod_length = self._instrument._demod_length
+ if demod_length > 1:
+ pass
+ # self.setpoints = ((demod_freqs, self._rec_list),
+ # (demod_freqs, self._rec_list))
+ else:
+ pass
+
+ def get(self):
+ """
+ Gets the magnitude and phase signal by calling acquire
+ on the alazar (which in turn calls the processing functions of the
+ aqcuisition controller before returning the processed data
+ demodulated at specified frequencies and averaged over samples
+ and buffers)
+
+ Returns:
+ mag: numpy array of magnitude, shape (demod_length, records)
+ phase: numpy array of magnitude, shape (demod_length, records)
+ """
+ mag, phase = self._instrument._get_alazar().acquire(
+ acquisition_controller=self._instrument,
+ **self.acquisition_kwargs)
+ return mag, phase
+
+
+class HD_Records_Controller(AcquisitionController):
+ """
+ This is the Acquisition Controller class which works with the ATS9360,
+ averaging over samples (limited by int_time and int_delay values) and
+ buffers and demodulating with software reference signal(s).
+
+ Args:
+ name: name for this acquisition_conroller as an instrument
+ alazar_name: name of the alazar instrument such that this
+ controller can communicate with the Alazar
+ demod_length (default 1): number of demodulation frequencies
+ filter (default 'win'): filter to be used to filter out double freq
+ component ('win' - window, 'ls' - least squared, 'ave' - averaging)
+ numtaps (default 101): number of freq components used in filter
+ chan_b (default False): whether there is also a second channel of data
+ to be processed and returned
+ **kwargs: kwargs are forwarded to the Instrument base class
+
+ TODO(nataliejpg) test filter options
+ TODO(nataliejpg) finish implementation of channel b option
+ TODO(nataliejpg) what should be private?
+ TODO(nataliejpg) where should filter_dict live?
+ TODO(nataliejpg) demod_freq should be changeable number: maybe channels
+ TODO(nataliejpg) make record param 'start' and 'stop' meaningful
+ """
+
+ filter_dict = {'win': 0, 'ls': 1, 'ave': 2}
+
+ def __init__(self, name, alazar_name, demod_length=1, filter='win',
+ numtaps=101, chan_b=False, **kwargs):
+ self.filter_settings = {'filter': self.filter_dict[filter],
+ 'numtaps': numtaps}
+ self.chan_b = chan_b
+ self._demod_length = demod_length
+ self.number_of_channels = 2
+ self.samples_per_record = None
+ self.sample_rate = None
+ super().__init__(name, alazar_name, **kwargs)
+
+ self.add_parameter(name='acquisition',
+ parameter_class=RecordsAcqParam)
+ for i in range(demod_length):
+ self.add_parameter(name='demod_freq_{}'.format(i),
+ check_and_update_fn=self._update_demod_freq,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_time',
+ check_and_update_fn=self._update_int_time,
+ default_fn=self._int_time_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_delay',
+ check_and_update_fn=self._update_int_delay,
+ default_fn=self._int_delay_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='record_num',
+ check_and_update_fn=self._update_rec_num,
+ parameter_class=AcqVariablesParam)
+
+ self.samples_divisor = self._get_alazar().samples_divisor
+
+ def _update_demod_freq(instr, value, param_name=None):
+ """
+ Function to validate and update acquisiton parameter when
+ a demod_freq_ Parameter is changed
+
+ Args:
+ value to update demodulation frequency to
+
+ Kwargs:
+ param_name: used to update demod_freq list used for updating
+ septionts of acquisition parameter
+
+ Checks:
+ 1e6 <= value <= 500e6
+ number of oscilation measured using current int_tiume param value
+ at this demod frequency value
+ oversampling rate for this demodulation frequency
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ setpoints of acquisiton parameter
+ """
+ if (value is None) or not (1e6 <= value <= 500e6):
+ raise ValueError('demod_freqs must be 1e6 <= value <= 500e6')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ min_oscilations_measured = instr.int_time() * value
+ oversampling = instr.sample_rate / (2 * value)
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ demod_freqs = instr.get_demod_freqs()
+ current_demod_index = ([int(s) for s in param_name.split()
+ if s.isdigit()][0])
+ demod_freqs[current_demod_index] = value
+ instr.acquisition.update_demod_setpoints(demod_freqs)
+
+ def _update_record_num(instr, value, **kwargs):
+ """
+ Function to update the record number, and instr attributes. Main
+ reason to record_num as a parameter is so we can more easily push the
+ record number setting up to other instruments which will control this.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 1 <= value <= 1000
+
+ Sets:
+ acquisition_kwarg['records_per_buffer'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (1 <= value <= 1000):
+ raise ValueError('int_time must be 1 <= value <= 1000')
+
+ # update acquisition parameter shapes
+ instr.acquisition.update_sweep(value)
+
+ # update acquision kwargs
+ instr.acquisition.acquisition_kwargs.update(
+ records_per_buffer=value)
+
+ def _update_int_time(instr, value, **kwargs):
+ """
+ Function to validate value for int_time before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of oscilation measured in this time
+ oversampling rate
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_time must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ if instr.get_max_demod_freq() is not None:
+ oscilations_measured = value * instr.get_max_demod_freq()
+ oversampling = instr.sample_rate / (2 * instr.get_max_demod_freq())
+ if oscilations_measured < 10:
+ logging.warning('{} oscilations measured, recommend at '
+ 'least 10: decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ if instr.int_delay() is None:
+ instr.int_delay.to_default()
+
+ # update acquision kwargs and acq controller value
+ total_time = value + instr.int_delay()
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _update_int_delay(instr, value, **kwargs):
+ """
+ Function to validate value for int_delay before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of samples discarded >= numtaps
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_delay must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samples_delay_min = (instr.filter_settings['numtaps'] - 1)
+ int_delay_min = samples_delay_min / instr.sample_rate
+ if value < int_delay_min:
+ logging.warning(
+ 'delay is less than recommended for filter choice: '
+ '(expect delay >= {})'.format(int_delay_min))
+
+ # update acquision kwargs and acq controller value
+ total_time = value + (instr.int_time() or 0)
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _int_delay_default(instr):
+ """
+ Function to generate default int_delay value
+
+ Returns:
+ minimum int_delay recommended for (numtaps - 1)
+ samples to be discarded as recommended for filter
+ """
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samp_delay = instr.filter_settings['numtaps'] - 1
+ return samp_delay / instr.sample_rate
+
+ def _int_time_default(instr):
+ """
+ Function to generate defult int_time value
+
+ Returns:
+ max total time for integration based on samples_per_record,
+ sample_rate and int_delay
+ """
+ if instr.samples_per_record is (0 or None):
+ raise ValueError('Cannot set int_time to max if acq controller'
+ ' has 0 or None samples_per_record, choose a '
+ 'value for int_time and samples_per_record will '
+ 'be set accordingly')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ total_time = ((instr.samples_per_record / instr.sample_rate) -
+ (instr.int_delay() or 0))
+ return total_time
+
+ def get_demod_freqs(self):
+ """
+ Function to get all the demod_freq parameter values in a list, v hacky
+
+ Returns:
+ freqs: numpy array of demodulation frequencies
+ """
+ freqs = list(filter(None, [getattr(self, 'demod_freq_{}'.format(c))()
+ for c in range(self._demod_length)]))
+ return np.array(freqs)
+
+ def get_max_demod_freq(self):
+ """
+ Returns:
+ the largest demodulation frequency
+
+ nb: really hacky and we should have channels in qcodes but we don't
+ (at time of writing)
+ """
+ freqs = self.get_demod_freqs()
+ if len(freqs) > 0:
+ return max(freqs)
+ else:
+ return None
+
+ def update_filter_settings(self, filter, numtaps):
+ """
+ Updates the settings of the filter for filtering out
+ double frwuency component for demodulation.
+
+ Args:
+ filter (str): filter type ('win' or 'ls')
+ numtaps (int): numtaps for filter
+ """
+ self.filter_settings.update({'filter': self.filter_dict[filter],
+ 'numtaps': numtaps})
+
+ def update_acquisition_kwargs(self, **kwargs):
+ """
+ Updates the kwargs to be used when
+ alazar_driver.acquisition() is called via a get call of the
+ acquisition RecordsAcqParam. Should be used by the user for
+ updating averaging settings since the 'samples_per_record'
+ and 'records_per_buffer' kwargs are updated via the int_time,
+ int_delay and record_num parameters
+
+ Kwargs (ints):
+ buffers_per_acquisition
+ allocated_buffers
+ """
+ if 'samples_per_record' in kwargs:
+ raise ValueError('With HD_Records_Controller '
+ 'samples_per_record cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting int_time and int_delay')
+ if 'records_per_buffer' in kwargs:
+ raise ValueError('With HD_Records_Controller '
+ 'records_per_buffer cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting record_num')
+ self.acquisition.acquisition_kwargs.update(**kwargs)
+
+ def pre_start_capture(self):
+ """
+ Called before capture start to update Acquisition Controller with
+ alazar acquisition params and set up software wave for demodulation.
+ """
+ alazar = self._get_alazar()
+ if self.samples_per_record != alazar.samples_per_record.get():
+ raise Exception('acq controller samples per record does not match'
+ ' instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.sample_rate != alazar.get_sample_rate():
+ raise Exception('acq controller sample rate does not match '
+ 'instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.record_num() != alazar.records_per_buffer.get():
+ raise Exception('acq controller record_num does not match '
+ 'instrument value, most likely need '
+ 'to call set and check record_num')
+
+ demod_freqs = self.get_demod_freqs()
+ if len(demod_freqs) == 0:
+ raise Exception('no demod_freqs set')
+
+ self.buffers_per_acquisition = alazar.buffers_per_acquisition.get()
+ self.board_info = alazar.get_idn()
+ self.buffer = np.zeros(self.samples_per_record *
+ self.record_num() *
+ self.number_of_channels)
+
+ mat_shape = (self._demod_length, self.record_num(),
+ self.samples_per_record)
+ integer_list = np.arange(self.samples_per_record)
+ integer_mat = np.outer(np.ones(self.record_num()), integer_list)
+ angle_mat = 2 * np.pi * \
+ np.outer(demod_freqs, integer_mat).reshape(
+ mat_shape) / self.sample_rate
+ self.cos_mat = np.cos(angle_mat)
+ self.sin_mat = np.sin(angle_mat)
+
+ def pre_acquire(self):
+ pass
+
+ def handle_buffer(self, data):
+ """
+ Adds data from alazar to buffer (effectively averaging)
+ """
+ self.buffer += data
+
+ def post_acquire(self):
+ """
+ Processes the data according to ATS9360 settings, splitting into
+ records and then applying demodulation fit
+ nb: currently only channel A
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, records_per_buffer)
+ phase (numpy array): shape = (demod_length, records_per_buffer
+ """
+ # for ATS9360 samples are arranged in the buffer as follows:
+ # S00A, S00B, S01A, S01B...S10A, S10B, S11A, S11B...
+ # where SXYZ is record X, sample Y, channel Z.
+
+ # break buffer up into records and shapes to be (records, samples)
+ reshaped_buf = self.buffer.reshape(self.records_per_buffer,
+ self.samples_per_record,
+ self.number_of_channels)
+ recordsA = np.uint16(reshaped_buf[:, :, 0] /
+ self.buffers_per_acquisition)
+
+ # TODO(nataliejpg): test above version works on alazar and
+ # compare performance
+ # recordsA = np.empty((self.record_num(), self.samples_per_record),
+ # dtype=np.uint16)
+ # for i in range(self.record_num()):
+ # i0 = (i * self.samples_per_record * self.number_of_channels)
+ # i1 = (i0 + self.samples_per_record * self.number_of_channels)
+ # recordsA[i, :] = np.uint16(
+ # self.buffer[i0:i1:self.number_of_channels] /
+ # self.buffers_per_acquisition)
+
+ # do demodulation
+ magA, phaseA = self._fit(recordsA)
+
+ # same for chan b
+ if self.chan_b:
+ # recordsB = np.uint16(reshaped_buf[:, :, 1] /
+ # self.buffers_per_acquisition)
+ raise NotImplementedError('chan b code not complete')
+
+ return magA, phaseA
+
+ def _fit(self, rec):
+ """
+ Applies volts conversion, demodulation fit, low bandpass filter
+ and integration limits to samples array
+
+ Args:
+ rec (numpy array): record from alazar to be multiplied
+ with the software signal, filtered and limited
+ to integration limits shape = (samples_taken, )
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, records_per_buffer)
+ phase (numpy array): shape = (demod_length, records_per_buffer)
+ """
+ # convert rec to volts
+ bps = self.board_info['bits_per_sample']
+ if bps == 12:
+ volt_rec = helpers.sample_to_volt_u12(rec, bps)
+ else:
+ logging.warning('sample to volt conversion does not exist for'
+ ' bps != 12, centered raw samples returned')
+ # TODO(nataliejpg): think about this recentering makes sense here
+ volt_rec = rec - np.mean(rec)
+
+ # volt_rec to matrix and multiply with demodulation signal matrices
+ mat_shape = (self._demod_length, self.record_num(),
+ self.samples_per_record)
+ volt_rec_mat = np.outer(
+ np.ones(self._demod_length), volt_rec).reshape(mat_shape)
+ re_mat = np.multiply(volt_rec_mat, self.cos_mat)
+ im_mat = np.multiply(volt_rec_mat, self.sin_mat)
+
+ # filter out higher freq component
+ cutoff = self.get_max_demod_freq() / 10
+ if self.filter_settings['filter'] == 0:
+ re_filtered = helpers.filter_win(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_win(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 1:
+ re_filtered = helpers.filter_ls(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_ls(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 2:
+ re_filtered = re_mat
+ im_filtered = im_mat
+
+ # apply integration limits
+ beginning = int(self.int_delay() * self.sample_rate)
+ end = beginning + int(self.int_time() * self.sample_rate)
+
+ re_limited = re_filtered[:, :, beginning:end]
+ im_limited = im_filtered[:, :, beginning:end]
+
+ # convert to magnitude and phase
+ complex_mat = re_limited + im_limited * 1j
+ magnitude = np.mean(abs(complex_mat), axis=-1)
+ phase = np.mean(np.angle(complex_mat, deg=True), axis=-1)
+
+ return magnitude, phase
diff --git a/qcodes/instrument_drivers/AlazarTech/rec_samp_controller.py b/qcodes/instrument_drivers/AlazarTech/rec_samp_controller.py
new file mode 100644
index 00000000000..4987fd32b59
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/rec_samp_controller.py
@@ -0,0 +1,661 @@
+import logging
+from .ATS import AcquisitionController
+import numpy as np
+from qcodes import Parameter
+import qcodes.instrument_drivers.AlazarTech.acq_helpers as helpers
+
+
+class AcqVariablesParam(Parameter):
+ """
+ Parameter of an AcquisitionController which has a _check_and_update_instr
+ function used for validation and to update instrument attributes and a
+ _get_default function which it uses to set the AcqVariablesParam to an
+ instrument caluclated default.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ check_and_update_fn: instrument function to be used for value
+ validation and updating instrument values
+ default_fn (optional): instrument function to be used to calculate
+ a default value to set parameter to
+ initial_value (optional): initial value for parameter
+ """
+
+ def __init__(self, name, instrument, check_and_update_fn,
+ default_fn=None, initial_value=None):
+ super().__init__(name)
+ self._instrument = instrument
+ self._save_val(initial_value)
+ setattr(self, '_check_and_update_instr', check_and_update_fn)
+ if default_fn is not None:
+ setattr(self, '_get_default', default_fn)
+
+ def set(self, value):
+ """
+ Function which checks value using validation function and then sets
+ the Parameter value to this value.
+
+ Args:
+ value: value to set the parameter to
+ """
+ self._check_and_update_instr(value, param_name=self.name)
+ self._save_val(value)
+
+ def get(self):
+ return self._latest()['value']
+
+ def to_default(self):
+ """
+ Function which executes the default_fn specified to calculate the
+ default value based on instrument values and then calls the set
+ function with this value
+ """
+ try:
+ default = self._get_default()
+ except AttributeError as e:
+ raise AttributeError('no default function for {} Parameter '
+ '{}'.format(self.name, e))
+ self.set(default)
+
+ def check(self):
+ """
+ Function which checks the current Parameter value using the specified
+ check_and_update_fn which can also serve to update instrument values.
+
+ Return:
+ True (if no errors raised when check_and_update_fn executed)
+ """
+ val = self._latest()['value']
+ self._check_and_update_instr(val, param_name=self.name)
+ return True
+
+
+class RecordsSamplesAcqParam(Parameter):
+ """
+ TODO
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ demod_length: numer of demodulation frequencies the acq controller has
+ NB this is currently set in acq controller init but that's really
+ not nice and should be changed when possible
+
+ TODO(nataliejpg) setpoints (including names and units)
+ TODO(nataliejpg) convert records setpoint into actual frequency
+ """
+
+ def __init__(self, name, instrument):
+ super().__init__(name)
+ self._instrument = instrument
+ self.acquisition_kwargs = {}
+ self.names = ('magnitude', 'phase')
+
+ def update_time_sweep(self, time_npts, time_start, time_stop):
+ """
+ Function which updates the shape of the parameter (and it's setpoints
+ when this is fixed)
+
+ Args:
+ time_npts: number of samples returned after processing
+ time_start: start time of samples returned after processing
+ time_stop: stop time of samples returned after processing
+ """
+ demod_length = self._instrument._demod_length
+ # self._time_list = tuple(np.linspace(time_start,
+ # time_stop, num=time_npts))
+ self._time_npts = time_npts
+ if demod_length > 1:
+ # demod_freqs = self._instrument.get_demod_freqs()
+ # self.setpoints = ((demod_freqs, self._rec_list, self._time_list),
+ # (demod_freqs, self._rec_list, self._time_list))
+ self.shapes = ((demod_length, self._rec_npts, self._time_npts),
+ (demod_length, self._rec_npts, self._time_npts))
+ else:
+ self.shapes = ((self._rec_npts, self._time_npts),
+ (self._rec_npts, self._time_npts))
+ # self.setpoints = ((self._rec_list, self._time_list),
+ # (self._rec_list, self._time_list))
+
+ def update_rec_sweep(self, rec_npts, rec_start=None, rec_stop=None):
+ """
+ Function which updates the shape of the parameter (and it's setpoints
+ when this is fixed)
+
+ Args:
+ rec_npts: number of records returned
+ rec_start (optional): start value of records returned
+ rec_stop (optional): stop value of records returned
+ """
+ demod_length = self._instrument._demod_length
+ # self._rec_list = tuple(np.linspace(rec_start,
+ # rec_stop, num=rec_npts))
+ self._rec_npts = rec_npts
+ if demod_length > 1:
+ # demod_freqs = self._instrument.get_demod_freqs()
+ # self.setpoints = ((demod_freqs, self._rec_list, self._time_list),
+ # (demod_freqs, self._rec_list, self._time_list))
+ self.shapes = ((demod_length, self._rec_npts, self._time_npts),
+ (demod_length, self._rec_npts, self._time_npts))
+ else:
+ self.shapes = ((self._rec_npts, self._time_npts),
+ (self._rec_npts, self._time_npts))
+ # self.setpoints = ((self._rec_list, self._time_list),
+ # (self._rec_list, self._time_list))
+
+ def update_demod_setpoints(self, demod_freqs):
+ """
+ Function to update the demodulation frequency setpoints to be called
+ when a demod_freq Parameter of the acq controller is updated
+
+ Args:
+ demod_freqs: numpy array of demodulation frequencies to use as
+ setpoints if length > 1
+ """
+ demod_length = self._instrument._demod_length
+ if demod_length > 1:
+ pass
+ # self.setpoints = ((demod_freqs, self._rec_list, self._time_list),
+ # (demod_freqs, self._rec_list, self._time_list))
+ else:
+ pass
+
+ def get(self):
+ """
+ Gets the magnitude and phase signal by calling acquire
+ on the alazar (which in turn calls the processing functions of the
+ aqcuisition controller before returning the processed data
+ demodulated at specified frequencies and averaged over buffers)
+
+ Returns:
+ mag: numpy array of magnitude, shape (demod_length, records)
+ phase: numpy array of magnitude, shape (demod_length, records)
+ """
+ mag, phase = self._instrument._get_alazar().acquire(
+ acquisition_controller=self._instrument,
+ **self.acquisition_kwargs)
+ return mag, phase
+
+
+class HD_RecordsSamples_Controller(AcquisitionController):
+ """
+ This is the Acquisition Controller class which works with the ATS9360,
+ averaging over buffers and demodulating with software reference signal(s).
+
+ Args:
+ name: name for this acquisition_conroller as an instrument
+ alazar_name: name of the alazar instrument such that this
+ controller can communicate with the Alazar
+ demod_length (default 1): number of demodulation frequencies
+ filter (default 'win'): filter to be used to filter out double freq
+ component ('win' - window, 'ls' - least squared, 'ave' - averaging)
+ numtaps (default 101): number of freq components used in filter
+ chan_b (default False): whether there is also a second channel of data
+ to be processed and returned
+ **kwargs: kwargs are forwarded to the Instrument base class
+
+ TODO(nataliejpg) test filter options
+ TODO(nataliejpg) finish implementation of channel b option
+ TODO(nataliejpg) what should be private?
+ TODO(nataliejpg) where should filter_dict live?
+ TODO(nataliejpg) demod_freq should be changeable number: maybe channels
+ TODO(nataliejpg) make record param 'start' and 'stop' meaningful
+ """
+
+ filter_dict = {'win': 0, 'ls': 1, 'ave': 2}
+
+ def __init__(self, name, alazar_name, demod_length=1, filter='win',
+ numtaps=101, chan_b=False, **kwargs):
+ self.filter_settings = {'filter': self.filter_dict[filter],
+ 'numtaps': numtaps}
+ self.chan_b = chan_b
+ self._demod_length = demod_length
+ self.number_of_channels = 2
+ self.samples_per_record = None
+ self.sample_rate = None
+ super().__init__(name, alazar_name, **kwargs)
+
+ self.add_parameter(name='acquisition',
+ parameter_class=RecordsSamplesAcqParam)
+ for i in range(demod_length):
+ self.add_parameter(name='demod_freq_{}'.format(i),
+ check_and_update_fn=self._update_demod_freq,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_time',
+ check_and_update_fn=self._update_int_time,
+ default_fn=self._int_time_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_delay',
+ check_and_update_fn=self._update_int_delay,
+ default_fn=self._int_delay_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='record_num',
+ check_and_update_fn=self._update_rec_num,
+ parameter_class=AcqVariablesParam)
+
+ self.samples_divisor = self._get_alazar().samples_divisor
+
+ def _update_demod_freq(instr, value, param_name=None):
+ """
+ Function to validate and update acquisiton parameter when
+ a demod_freq_ Parameter is changed
+
+ Args:
+ value to update demodulation frequency to
+
+ Kwargs:
+ param_name: used to update demod_freq list used for updating
+ septionts of acquisition parameter
+
+ Checks:
+ 1e6 <= value <= 500e6
+ number of oscilation measured using current int_tiume param value
+ at this demod frequency value
+ oversampling rate for this demodulation frequency
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ setpoints of acquisiton parameter
+ """
+ if (value is None) or not (1e6 <= value <= 500e6):
+ raise ValueError('demod_freqs must be 1e6 <= value <= 500e6')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ min_oscilations_measured = instr.int_time() * value
+ oversampling = instr.sample_rate / (2 * value)
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ demod_freqs = instr.get_demod_freqs()
+ current_demod_index = ([int(s) for s in param_name.split()
+ if s.isdigit()][0])
+ demod_freqs[current_demod_index] = value
+ instr.acquisition.update_demod_setpoints(demod_freqs)
+
+ def _update_record_num(instr, value, **kwargs):
+ """
+ Function to update the record number, and instr attributes. Main
+ reason to record_num as a parameter is so we can more easily push the
+ record number setting up to other instruments which will control this.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 1 <= value <= 1000
+
+ Sets:
+ acquisition_kwarg['records_per_buffer'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (1 <= value <= 1000):
+ raise ValueError('int_time must be 1 <= value <= 1000')
+
+ # update acquisition parameter shapes
+ instr.acquisition.update_rec_sweep(value)
+
+ # update acquision kwargs
+ instr.acquisition.acquisition_kwargs.update(
+ records_per_buffer=value)
+
+ def _update_int_time(instr, value, **kwargs):
+ """
+ Function to validate value for int_time before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of oscilation measured in this time
+ oversampling rate
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_time must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ if instr.get_max_demod_freq() is not None:
+ oscilations_measured = value * instr.get_max_demod_freq()
+ oversampling = instr.sample_rate / (2 * instr.get_max_demod_freq())
+ if oscilations_measured < 10:
+ logging.warning('{} oscilations measured, recommend at '
+ 'least 10: decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ if instr.int_delay() is None:
+ instr.int_delay.to_default()
+
+ # update acquisition parameter shapes
+ start = instr.int_delay()
+ stop = start + value
+ npts = int(value * instr.sample_rate)
+ instr.acquisition.update_time_sweep(start, stop, npts)
+
+ # update acquision kwargs and acq controller value
+ total_time = value + instr.int_delay()
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _update_int_delay(instr, value, **kwargs):
+ """
+ Function to validate value for int_delay before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of samples discarded >= numtaps
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_delay must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samples_delay_min = (instr.filter_settings['numtaps'] - 1)
+ int_delay_min = samples_delay_min / instr.sample_rate
+ if value < int_delay_min:
+ logging.warning(
+ 'delay is less than recommended for filter choice: '
+ '(expect delay >= {})'.format(int_delay_min))
+
+ # update acquisition parameter shapes
+ start = value
+ stop = start + (instr.int_time() or 0)
+ npts = int((instr.int_time() or 0) * instr.sample_rate)
+ instr.acquisition.update_time_sweep(start, stop, npts)
+
+ # update acquision kwargs and acq controller value
+ total_time = value + (instr.int_time() or 0)
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _int_delay_default(instr):
+ """
+ Function to generate default int_delay value
+
+ Returns:
+ minimum int_delay recommended for (numtaps - 1)
+ samples to be discarded as recommended for filter
+ """
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samp_delay = instr.filter_settings['numtaps'] - 1
+ return samp_delay / instr.sample_rate
+
+ def _int_time_default(instr):
+ """
+ Function to generate defult int_time value
+
+ Returns:
+ max total time for integration based on samples_per_record,
+ sample_rate and int_delay
+ """
+ if instr.samples_per_record is (0 or None):
+ raise ValueError('Cannot set int_time to max if acq controller'
+ ' has 0 or None samples_per_record, choose a '
+ 'value for int_time and samples_per_record will '
+ 'be set accordingly')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ total_time = ((instr.samples_per_record / instr.sample_rate) -
+ (instr.int_delay() or 0))
+ return total_time
+
+ def get_demod_freqs(self):
+ """
+ Function to get all the demod_freq parameter values in a list, v hacky
+
+ Returns:
+ freqs: numpy array of demodulation frequencies
+ """
+ freqs = list(filter(None, [getattr(self, 'demod_freq_{}'.format(c))()
+ for c in range(self._demod_length)]))
+ return np.array(freqs)
+
+ def get_max_demod_freq(self):
+ """
+ Returns:
+ the largest demodulation frequency
+
+ nb: really hacky and we should have channels in qcodes but we don't
+ (at time of writing)
+ """
+ freqs = self.get_demod_freqs()
+ if len(freqs) > 0:
+ return max(freqs)
+ else:
+ return None
+
+ def update_filter_settings(self, filter, numtaps):
+ """
+ Updates the settings of the filter for filtering out
+ double frwuency component for demodulation.
+
+ Args:
+ filter (str): filter type ('win' or 'ls')
+ numtaps (int): numtaps for filter
+ """
+ self.filter_settings.update({'filter': self.filter_dict[filter],
+ 'numtaps': numtaps})
+
+ def update_acquisition_kwargs(self, **kwargs):
+ """
+ Updates the kwargs to be used when
+ alazar_driver.acquisition() is called via a get call of the
+ acquisition RecordsSamplesAcqParam. Should be used by the user for
+ updating averaging settings since the 'samples_per_record'
+ and 'records_per_buffer' kwargs are updated via the int_time,
+ int_delay and record_num parameters
+
+ Kwargs (ints):
+ buffers_per_acquisition
+ allocated_buffers
+ """
+ if 'samples_per_record' in kwargs:
+ raise ValueError('With HD_RecordsSamples_Controller '
+ 'samples_per_record cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting int_time and int_delay')
+ if 'records_per_buffer' in kwargs:
+ raise ValueError('With HD_RecordsSamples_Controller '
+ 'records_per_buffer cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ ' be set by setting record_num')
+ self.acquisition.acquisition_kwargs.update(**kwargs)
+
+ def pre_start_capture(self):
+ """
+ Called before capture start to update Acquisition Controller with
+ alazar acquisition params and set up software wave for demodulation.
+ """
+ alazar = self._get_alazar()
+ if self.samples_per_record != alazar.samples_per_record.get():
+ raise Exception('acq controller samples per record does not match'
+ ' instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.sample_rate != alazar.get_sample_rate():
+ raise Exception('acq controller sample rate does not match '
+ 'instrument value, most likely need '
+ 'to set and check int_time and int_delay')
+ if self.record_num() != alazar.records_per_buffer.get():
+ raise Exception('acq controller records per buffer does not match '
+ 'instrument value, most likely need '
+ 'to call update_acquisition_kwargs with'
+ 'records_per_buffer as a param')
+
+ demod_freqs = self.get_demod_freqs()
+ if len(demod_freqs) == 0:
+ raise Exception('no demod_freqs set')
+
+ self.buffers_per_acquisition = alazar.buffers_per_acquisition.get()
+ self.board_info = alazar.get_idn()
+ self.buffer = np.zeros(self.samples_per_record *
+ self.record_num() *
+ self.number_of_channels)
+
+ mat_shape = (self._demod_length, self.record_num(),
+ self.samples_per_record)
+ integer_list = np.arange(self.samples_per_record)
+ integer_mat = np.outer(np.ones(self.record_num()), integer_list)
+ angle_mat = 2 * np.pi * \
+ np.outer(demod_freqs, integer_mat).reshape(
+ mat_shape) / self.sample_rate
+ self.cos_mat = np.cos(angle_mat)
+ self.sin_mat = np.sin(angle_mat)
+
+ def pre_acquire(self):
+ pass
+
+ def handle_buffer(self, data):
+ """
+ Adds data from alazar to buffer (effectively averaging)
+ """
+ self.buffer += data
+
+ def post_acquire(self):
+ """
+ Processes the data according to ATS9360 settings, splitting into
+ records and then applying demodulation fit
+ nb: currently only channel A
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, records_per_buffer)
+ phase (numpy array): shape = (demod_length, records_per_buffer
+ """
+ # for ATS9360 samples are arranged in the buffer as follows:
+ # S00A, S00B, S01A, S01B...S10A, S10B, S11A, S11B...
+ # where SXYZ is record X, sample Y, channel Z.
+
+ # break buffer up into records and shapes to be (records, samples)
+ reshaped_buf = self.buffer.reshape(self.records_per_buffer,
+ self.samples_per_record,
+ self.number_of_channels)
+ recordsA = np.uint16(reshaped_buf[:, :, 0] /
+ self.buffers_per_acquisition)
+
+ # TODO(nataliejpg): test above version works on alazar and
+ # compare performance
+ # recordsA = np.empty((self.record_num(), self.samples_per_record),
+ # dtype=np.uint16)
+ # for i in range(self.record_num()):
+ # i0 = (i * self.samples_per_record * self.number_of_channels)
+ # i1 = (i0 + self.samples_per_record * self.number_of_channels)
+ # recordsA[i, :] = np.uint16(
+ # self.buffer[i0:i1:self.number_of_channels] /
+ # self.buffers_per_acquisitin)
+
+ # do demodulation
+ # recordsB = np.uint16(reshaped_buf[:, :, 1] /
+ # self.buffers_per_acquisition)
+ magA, phaseA = self._fit(recordsA)
+
+ # same for chan b
+ if self.chan_b:
+ raise NotImplementedError('chan b code not complete')
+
+ return magA, phaseA
+
+ def _fit(self, rec):
+ """
+ Applies volts conversion, demodulation fit, low bandpass filter
+ and integration limits to samples array
+
+ Args:
+ rec (numpy array): record from alazar to be multiplied
+ with the software signal, filtered and limited
+ to integration limits shape = (samples_taken, )
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, records_per_buffer)
+ phase (numpy array): shape = (demod_length, records_per_buffer)
+ """
+ # convert rec to volts
+ bps = self.board_info['bits_per_sample']
+ if bps == 12:
+ volt_rec = helpers.sample_to_volt_u12(rec, bps)
+ else:
+ logging.warning('sample to volt conversion does not exist for'
+ ' bps != 12, centered raw samples returned')
+ # TODO(nataliejpg): think about this recentering makes sense here
+ volt_rec = rec - np.mean(rec)
+
+ # volt_rec to matrix and multiply with demodulation signal matrices
+ mat_shape = (self._demod_length, self.record_num,
+ self.samples_per_record)
+ volt_rec_mat = np.outer(
+ np.ones(self._demod_length), volt_rec).reshape(mat_shape)
+ re_mat = np.multiply(volt_rec_mat, self.cos_mat)
+ im_mat = np.multiply(volt_rec_mat, self.sin_mat)
+
+ # filter out higher freq component
+ cutoff = self.get_max_demod_freq() / 10
+ if self.filter_settings['filter'] == 0:
+ re_filtered = helpers.filter_win(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_win(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 1:
+ re_filtered = helpers.filter_ls(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_ls(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 2:
+ re_filtered = re_mat
+ im_filtered = im_mat
+
+ # apply integration limits
+ beginning = int(self.int_delay() * self.sample_rate)
+ end = beginning + int(self.int_time() * self.sample_rate)
+
+ re_limited = re_filtered[:, :, beginning:end]
+ im_limited = im_filtered[:, :, beginning:end]
+
+ # convert to magnitude and phase
+ complex_mat = re_limited + im_limited * 1j
+ magnitude = abs(complex_mat)
+ phase = np.angle(complex_mat, deg=True)
+
+ return magnitude, phase
diff --git a/qcodes/instrument_drivers/AlazarTech/samp_controller.py b/qcodes/instrument_drivers/AlazarTech/samp_controller.py
new file mode 100644
index 00000000000..995250d9fc8
--- /dev/null
+++ b/qcodes/instrument_drivers/AlazarTech/samp_controller.py
@@ -0,0 +1,584 @@
+import logging
+from .ATS import AcquisitionController
+import numpy as np
+from qcodes import Parameter
+import qcodes.instrument_drivers.AlazarTech.acq_helpers as helpers
+
+
+class AcqVariablesParam(Parameter):
+ """
+ Parameter of an AcquisitionController which has a _check_and_update_instr
+ function used for validation and to update instrument attributes and a
+ _get_default function which it uses to set the AcqVariablesParam to an
+ instrument caluclated default.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+ check_and_update_fn: instrument function to be used for value
+ validation and updating instrument values
+ default_fn (optional): instrument function to be used to calculate
+ a default value to set parameter to
+ initial_value (optional): initial value for parameter
+ """
+
+ def __init__(self, name, instrument, check_and_update_fn,
+ default_fn=None, initial_value=None):
+ super().__init__(name)
+ self._instrument = instrument
+ self._save_val(initial_value)
+ setattr(self, '_check_and_update_instr', check_and_update_fn)
+ if default_fn is not None:
+ setattr(self, '_get_default', default_fn)
+
+ def set(self, value):
+ """
+ Function which checks value using validation function and then sets
+ the Parameter value to this value.
+
+ Args:
+ value: value to set the parameter to
+ """
+ self._check_and_update_instr(value, param_name=self.name)
+ self._save_val(value)
+
+ def get(self):
+ return self._latest()['value']
+
+ def to_default(self):
+ """
+ Function which executes the default_fn specified to calculate the
+ default value based on instrument values and then calls the set
+ function with this value
+ """
+ try:
+ default = self._get_default()
+ except AttributeError as e:
+ raise AttributeError('no default function for {} Parameter '
+ '{}'.format(self.name, e))
+ self.set(default)
+
+ def check(self):
+ """
+ Function which checks the current Parameter value using the specified
+ check_and_update_fn which can also serve to update instrument values.
+
+ Return:
+ True (if no errors raised when check_and_update_fn executed)
+ """
+ val = self._latest()['value']
+ self._check_and_update_instr(val, param_name=self.name)
+ return True
+
+
+class SamplesAcqParam(Parameter):
+ """
+ Hardware controlled parameter class for Alazar acquisition. To be used with
+ HD_Samples_Controller (tested with ATS9360 board) for return of an array of
+ sample data from the Alazar, averaged over records and buffers.
+
+ Args:
+ name: name for this parameter
+ instrument: acquisition controller instrument this parameter belongs to
+
+ TODO(nataliejpg) setpoints (including names and units)
+ """
+
+ def __init__(self, name, instrument):
+ super().__init__(name)
+ self._instrument = instrument
+ self.acquisition_kwargs = {}
+ self.names = ('magnitude', 'phase')
+
+ def update_sweep(self, start, stop, npts):
+ """
+ Function which updates the shape of the parameter (and it's setpoints
+ when this is fixed)
+
+ Args:
+ start: start time of samples returned after processing
+ stop: stop time of samples returned after processing
+ npts: number of samples returned after processing
+ """
+ demod_length = self._instrument._demod_length
+ # self._time_list = tuple(np.linspace(start, stop, num=npts))
+ if demod_length > 1:
+ # demod_freqs = self._instrument.get_demod_freqs()
+ # self.setpoints = ((demod_freqs, self._time_list),
+ # (demod_freqs, self._time_list))
+ self.shapes = ((demod_length, npts), (demod_length, npts))
+ else:
+ self.shapes = ((npts,), (npts,))
+ # self.setpoints = ((self._time_list,), (self._time_list,))
+
+ def update_demod_setpoints(self, demod_freqs):
+ """
+ Function to update the demodulation frequency setpoints to be called
+ when a demod_freq Parameter of the acq controller is updated
+
+ Args:
+ demod_freqs: numpy array of demodulation frequencies to use as
+ setpoints if length > 1
+ """
+ demod_length = self._instrument._demod_length
+ if demod_length > 1:
+ pass
+ # self.setpoints = ((demod_freqs, self._time_list),
+ # (demod_freqs, self._time_list))
+ else:
+ pass
+
+ def get(self):
+ """
+ Gets the magnitude and phase signal by calling acquire
+ on the alazar (which in turn calls the processing functions of the
+ aqcuisition controller before returning the processed data
+ demodulated at specified frequencies and averaged over records
+ and buffers)
+
+ Returns:
+ mag: numpy array of magnitude, shape (demod_length, samples)
+ phase: numpy array of magnitude, shape (demod_length, samples)
+ """
+ mag, phase = self._instrument._get_alazar().acquire(
+ acquisition_controller=self._instrument,
+ **self.acquisition_kwargs)
+ return mag, phase
+
+
+class HD_Samples_Controller(AcquisitionController):
+ """
+ This is the Acquisition Controller class which works with the ATS9360,
+ averaging over records and buffers and demodulating with software
+ reference signal(s), returning samples limited by int_time and int_delay
+ values.
+
+ Args:
+ name: name for this acquisition_conroller as an instrument
+ alazar_name: name of the alazar instrument such that this
+ controller can communicate with the Alazar
+ demod_length (default 1): number of demodulation frequencies
+ filter (default 'win'): filter to be used to filter out double
+ freq component ('win' - window, 'ls' - least squared)
+ numtaps (default 101): number of freq components used in the filter
+ chan_b (default False): whether there is also a second channel of data
+ to be processed and returned
+ **kwargs: kwargs are forwarded to the Instrument base class
+
+ TODO(nataliejpg) test filter options
+ TODO(nataliejpg) finish implementation of channel b option
+ TODO(nataliejpg) what should be private?
+ TODO(nataliejpg) where should filter_dict live?
+ TODO(nataliejpg) demod_freq number should be changeable number: channels?
+ """
+ filter_dict = {'win': 0, 'ls': 1}
+
+ def __init__(self, name, alazar_name, demod_length=1, filter='win',
+ numtaps=101, chan_b=False, **kwargs):
+ self.filter_settings = {'filter': self.filter_dict[filter],
+ 'numtaps': numtaps}
+ self.chan_b = chan_b
+ self._demod_length = demod_length
+ self.number_of_channels = 2
+ self.samples_per_record = None
+ self.sample_rate = None
+ super().__init__(name, alazar_name, **kwargs)
+
+ self.add_parameter(name='acquisition',
+ parameter_class=SamplesAcqParam)
+ for i in range(demod_length):
+ self.add_parameter(name='demod_freq_{}'.format(i),
+ check_and_update_fn=self._update_demod_freq,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_time',
+ check_and_update_fn=self._update_int_time,
+ default_fn=self._int_time_default,
+ parameter_class=AcqVariablesParam)
+ self.add_parameter(name='int_delay',
+ check_and_update_fn=self._update_int_delay,
+ default_fn=self._int_delay_default,
+ parameter_class=AcqVariablesParam)
+ self.samples_divisor = self._get_alazar().samples_divisor
+
+ def _update_demod_freq(instr, value, param_name=None):
+ """
+ Function to validate and update acquisiton parameter when
+ a demod_freq_ Parameter is changed
+
+ Args:
+ value to update demodulation frequency to
+
+ Kwargs:
+ param_name: used to update demod_freq list used for updating
+ septionts of acquisition parameter
+
+ Checks:
+ 1e6 <= value <= 500e6
+ number of oscilation measured using current int_tiume param value
+ at this demod frequency value
+ oversampling rate for this demodulation frequency
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ setpoints of acquisiton parameter
+ """
+ if (value is None) or not (1e6 <= value <= 500e6):
+ raise ValueError('demod_freqs must be 1e6 <= value <= 500e6')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ min_oscilations_measured = instr.int_time() * value
+ oversampling = instr.sample_rate / (2 * value)
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ demod_freqs = instr.get_demod_freqs()
+ current_demod_index = ([int(s) for s in param_name.split()
+ if s.isdigit()][0])
+ demod_freqs[current_demod_index] = value
+ instr.acquisition.update_demod_setpoints(demod_freqs)
+
+ def _update_int_time(instr, value, **kwargs):
+ """
+ Function to validate value for int_time before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of oscilation measured in this time
+ oversampling rate
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_time must be 0 <= value <= 1')
+
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ if instr.get_max_demod_freq() is not None:
+ min_oscilations_measured = value * instr.get_max_demod_freq()
+ oversampling = instr.sample_rate / (2 * instr.get_max_demod_freq())
+ if min_oscilations_measured < 10:
+ logging.warning('{} oscilations measured for largest '
+ 'demod freq, recommend at least 10: '
+ 'decrease sampling rate, take '
+ 'more samples or increase demodulation '
+ 'freq'.format(min_oscilations_measured))
+ elif oversampling < 1:
+ logging.warning('oversampling rate is {}, recommend > 1: '
+ 'increase sampling rate or decrease '
+ 'demodulation frequency'.format(oversampling))
+ if instr.int_delay() is None:
+ instr.int_delay.to_default()
+
+ # update acquisition parameter shapes
+ start = instr.int_delay()
+ stop = start + value
+ npts = int(value * instr.sample_rate)
+ instr.acquisition.update_sweep(start, stop, npts)
+
+ # update acquision kwargs and acq controller value
+ total_time = value + instr.int_delay()
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _update_int_delay(instr, value, **kwargs):
+ """
+ Function to validate value for int_delay before setting parameter
+ value and update instr attributes.
+
+ Args:
+ value to be validated and used for instrument attribute update
+
+ Checks:
+ 0 <= value <= 0.1 seconds
+ number of samples discarded >= numtaps
+
+ Sets:
+ sample_rate attr of acq controller to be that of alazar
+ samples_per_record of acq controller
+ acquisition_kwarg['samples_per_record'] of acquisition param
+ setpoints of acquisiton param
+ shape of acquisition param
+ """
+ if (value is None) or not (0 <= value <= 0.1):
+ raise ValueError('int_delay must be 0 <= value <= 1')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samples_delay_min = (instr.filter_settings['numtaps'] - 1)
+ int_delay_min = samples_delay_min / instr.sample_rate
+ if value < int_delay_min:
+ logging.warning(
+ 'delay is less than recommended for filter choice: '
+ '(expect delay >= {})'.format(int_delay_min))
+
+ # update acquisition parameter shapes
+ start = value
+ stop = start + (instr.int_time() or 0)
+ npts = int((instr.int_time() or 0) * instr.sample_rate)
+ instr.acquisition.update_sweep(start, stop, npts)
+
+ # update acquision kwargs and acq controller value
+ total_time = value + (instr.int_time() or 0)
+ samples_needed = total_time * instr.sample_rate
+ instr.samples_per_record = helpers.roundup(
+ samples_needed, instr.samples_divisor)
+ instr.acquisition.acquisition_kwargs.update(
+ samples_per_record=instr.samples_per_record)
+
+ def _int_delay_default(instr):
+ """
+ Function to generate default int_delay value
+
+ Returns:
+ minimum int_delay recommended for (numtaps - 1)
+ samples to be discarded as recommended for filter
+ """
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ samp_delay = instr.filter_settings['numtaps'] - 1
+ return samp_delay / instr.sample_rate
+
+ def _int_time_default(instr):
+ """
+ Function to generate defult int_time value
+
+ Returns:
+ max total time for integration based on samples_per_record,
+ sample_rate and int_delay
+ """
+ if instr.samples_per_record is (0 or None):
+ raise ValueError('Cannot set int_time to max if acq controller'
+ ' has 0 or None samples_per_record, choose a '
+ 'value for int_time and samples_per_record '
+ 'will be set accordingly')
+ alazar = instr._get_alazar()
+ instr.sample_rate = alazar.get_sample_rate()
+ total_time = ((instr.samples_per_record / instr.sample_rate) -
+ (instr.int_delay() or 0))
+ return total_time
+
+ def get_demod_freqs(self):
+ """
+ Function to get all the demod_freq parameter values in a list, v hacky
+
+ Returns:
+ freqs: numpy array of demodulation frequencies
+ """
+ freqs = list(filter(None, [getattr(self, 'demod_freq_{}'.format(c))()
+ for c in range(self._demod_length)]))
+ return np.array(freqs)
+
+ def get_max_demod_freq(self):
+ """
+ Returns:
+ the largest demodulation frequency
+
+ nb: really hacky and we should have channels in qcodes but we don't
+ (at time of writing)
+ """
+ freqs = self.get_demod_freqs()
+ if len(freqs) > 0:
+ return max(freqs)
+ else:
+ return None
+
+ def update_filter_settings(self, filter, numtaps):
+ """
+ Updates the settings of the filter for filtering out
+ double frwuency component for demodulation.
+
+ Args:
+ filter (str): filter type ('win' or 'ls')
+ numtaps (int): numtaps for filter
+ """
+ self.filter_settings.update({'filter': self.filter_dict[filter],
+ 'numtaps': numtaps})
+
+ def update_acquisition_kwargs(self, **kwargs):
+ """
+ Updates the kwargs to be used when
+ alazar_driver.acquisition() is called via a get call of the
+ acquisition SamplesAcqParam. Should be used by the user for updating
+ averaging settings since the 'samples_per_record' kwarg is updated
+ via the int_time and int_delay parameters
+
+ Kwargs (ints):
+ records_per_buffer
+ buffers_per_acquisition
+ allocated_buffers
+ """
+ if 'samples_per_record' in kwargs:
+ raise ValueError('With HD_Samples_Controller '
+ 'samples_per_record cannot be set manually '
+ 'via update_acquisition_kwargs and should instead'
+ 'be set by setting int_time int_delay and alazar '
+ 'sample_rate')
+ self.acquisition.acquisition_kwargs.update(**kwargs)
+
+ def pre_start_capture(self):
+ """
+ Called before capture start to update Acquisition Controller with
+ alazar acquisition params and set up software wave for demodulation.
+ """
+ alazar = self._get_alazar()
+ if self.samples_per_record != alazar.samples_per_record.get():
+ raise Exception('acq controller samples per record does not match'
+ ' instrument value, most likely need '
+ 'to call update_acquisition_settings')
+ if self.sample_rate != alazar.get_sample_rate():
+ raise Exception('acq controller sample rate does not match '
+ 'instrument value, most likely need '
+ 'to call update_acquisition_settings')
+
+ demod_freqs = self.get_demod_freqs()
+ if len(demod_freqs) == 0:
+ raise Exception('no demod_freqs set')
+
+ self.records_per_buffer = alazar.records_per_buffer.get()
+ self.buffers_per_acquisition = alazar.buffers_per_acquisition.get()
+ self.board_info = alazar.get_idn()
+ self.buffer = np.zeros(self.samples_per_record *
+ self.records_per_buffer *
+ self.number_of_channels)
+
+ integer_list = np.arange(self.samples_per_record)
+ angle_mat = 2 * np.pi * \
+ np.outer(demod_freqs, integer_list) / self.sample_rate
+ self.cos_mat = np.cos(angle_mat)
+ self.sin_mat = np.sin(angle_mat)
+
+ def pre_acquire(self):
+ pass
+
+ def handle_buffer(self, data):
+ """
+ Adds data from alazar to buffer (effectively averaging)
+ """
+ self.buffer += data
+
+ def post_acquire(self):
+ """
+ Processes the data according to ATS9360 settings, splitting into
+ records and averaging over them, then applying demodulation fit
+ nb: currently only channel A
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, samples_used)
+ phase (numpy array): shape = (demod_length, samples_used)
+ """
+
+ # for ATS9360 samples are arranged in the buffer as follows:
+ # S00A, S00B, S01A, S01B...S10A, S10B, S11A, S11B...
+ # where SXYZ is record X, sample Y, channel Z.
+
+ # break buffer up into records and averages over them
+ reshaped_buf = self.buffer.reshape(self.records_per_buffer,
+ self.samples_per_record,
+ self.number_of_channels)
+ recordA = np.uint16(np.mean(reshaped_buf[:, :, 0], axis=0) /
+ self.buffers_per_acquisition)
+
+ # TODO(nataliejpg): test above version works on alazar and
+ # compare performance
+
+ # records_per_acquisition = (self.buffers_per_acquisition *
+ # self.records_per_buffer)
+ # recA = np.zeros(self.samples_per_record)
+ # for i in range(self.records_per_buffer):
+ # i0 = (i * self.samples_per_record * self.number_of_channels)
+ # i1 = (i0 + self.samples_per_record * self.number_of_channels)
+ # recA += self.buffer[i0:i1:self.number_of_channels]
+ # recordA = np.uint16(recA / records_per_acquisition)
+
+ # do demodulation
+ magA, phaseA = self._fit(recordA)
+
+ # same for chan b
+ if self.chan_b:
+ # recordB = np.uint16(np.mean(reshaped_buf[:, :, 1], axis=0) /
+ # self.buffers_per_acquisition)
+ raise NotImplementedError('chan b code not complete')
+
+ return magA, phaseA
+
+ def _fit(self, rec):
+ """
+ Applies volts conversion, demodulation fit, low bandpass filter
+ and integration limits to samples array
+
+ Args:
+ rec (numpy array): record from alazar to be multiplied with the
+ software signal, filtered and limited to
+ integration limits
+ shape = (samples_taken, )
+
+ Returns:
+ magnitude (numpy array): shape = (demod_length, samples_used)
+ phase (numpy array): shape = (demod_length, samples_used)
+ """
+ # convert rec to volts
+ bps = self.board_info['bits_per_sample']
+ if bps == 12:
+ volt_rec = helpers.sample_to_volt_u12(rec, bps)
+ else:
+ logging.warning('sample to volt conversion does not exist for'
+ ' bps != 12, centered raw samples returned')
+ volt_rec = rec - np.mean(rec)
+
+ # volt_rec to matrix and multiply with demodulation signal matrices
+ volt_rec_mat = np.outer(np.ones(self._demod_length), volt_rec)
+ re_mat = np.multiply(volt_rec_mat, self.cos_mat)
+ im_mat = np.multiply(volt_rec_mat, self.sin_mat)
+
+ # filter out higher freq component
+ cutoff = self.get_max_demod_freq() / 20
+ if self.filter_settings['filter'] == 0:
+ re_filtered = helpers.filter_win(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_win(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ elif self.filter_settings['filter'] == 1:
+ re_filtered = helpers.filter_ls(re_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+ im_filtered = helpers.filter_ls(im_mat, cutoff,
+ self.sample_rate,
+ self.filter_settings['numtaps'],
+ axis=-1)
+
+ # apply integration limits
+ beginning = int(self.int_delay() * self.sample_rate)
+ end = beginning + int(self.int_time() * self.sample_rate)
+
+ re_limited = re_filtered[:, beginning:end]
+ im_limited = im_filtered[:, beginning:end]
+
+ # convert to magnitude and phase
+ complex_mat = re_limited + im_limited * 1j
+ magnitude = abs(complex_mat)
+ phase = np.angle(complex_mat, deg=True)
+
+ return magnitude, phase
diff --git a/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py b/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py
index 83eb19ee054..094d5d64738 100644
--- a/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py
+++ b/qcodes/instrument_drivers/rohde_schwarz/SGS100A.py
@@ -36,7 +36,7 @@ def __init__(self, name, address, **kwargs):
get_cmd='SOUR:FREQ' + '?',
set_cmd='SOUR:FREQ' + ' {:.2f}',
get_parser=float,
- vals=vals.Numbers(1e9, 20e9))
+ vals=vals.Numbers(1e6, 20e9))
self.add_parameter(name='phase',
label='Phase',
units='deg',
diff --git a/qcodes/instrument_drivers/rohde_schwarz/SMR40.py b/qcodes/instrument_drivers/rohde_schwarz/SMR40.py
index 3b31aa89e34..d3cc0df98c5 100644
--- a/qcodes/instrument_drivers/rohde_schwarz/SMR40.py
+++ b/qcodes/instrument_drivers/rohde_schwarz/SMR40.py
@@ -13,15 +13,22 @@
class RohdeSchwarz_SMR40(VisaInstrument):
"""This is the qcodes driver for the Rohde & Schwarz SMR40 signal generator
+<<<<<<< HEAD
+ Status: beta-version. TODO:
+=======
Status: beta-version.
.. todo::
+>>>>>>> master
- Add all parameters that are in the manual
- Add test suite
- See if there can be a common driver for RS mw sources from which
different models inherit
+<<<<<<< HEAD
+=======
+>>>>>>> master
This driver does not contain all commands available for the SMR40 but
only the ones most commonly used.
diff --git a/qcodes/utils/helpers.py b/qcodes/utils/helpers.py
index eaca490c741..a3b45545ae3 100644
--- a/qcodes/utils/helpers.py
+++ b/qcodes/utils/helpers.py
@@ -422,3 +422,4 @@ def compare_dictionaries(dict_1, dict_2,
else:
dicts_equal = False
return dicts_equal, dict_differences
+