From 9c8fa02d7028ab7232243898b034a02f20e3bd90 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 17 May 2017 17:12:46 +0200 Subject: [PATCH 01/19] Docs strings --- .../instrument_drivers/rohde_schwarz/ZNB20.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 1131115c5914..5ef6c7cfdcf9 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -12,6 +12,21 @@ class FrequencySweep(MultiParameter): Instrument returns an list of transmission data in the form of a list of complex numbers taken from a frequency sweep. + Args: + name: parameter name + instrument: instrument the parameter belongs to + start: starting frequency of sweep + stop: ending frequency of sweep + npts: numper of points in frequency sweep + + Methods: + set_sweep(start, stop, npts): sets the shapes and + setpoint arrays of the parameter to correspond with the sweep + get(): executes a sweep and returns magnitude and phase arrays + + get_ramping: Queries the value of self.ramp_state and + self.ramp_time. Returns a string. + TODO: - ability to choose for abs or db in magnitude return """ @@ -24,7 +39,7 @@ def __init__(self, name, instrument, start, stop, npts): self.setpoint_names = (('frequency',), ('frequency',)) def set_sweep(self, start, stop, npts): - # needed to update config of the software parameter on sweep chage + # needed to update config of the software parameter on sweep change # freq setpoints tuple as needs to be hashable for look up f = tuple(np.linspace(int(start), int(stop), num=npts)) self.setpoints = ((f,), (f,)) From aeef4541f54bc3a69d5d5e757e18620772eb2508 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 17 May 2017 17:13:09 +0200 Subject: [PATCH 02/19] Fix: add option to set span and center --- .../instrument_drivers/rohde_schwarz/ZNB20.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 5ef6c7cfdcf9..65f9a3b611a7 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -116,6 +116,16 @@ def __init__(self, name, address, **kwargs): set_cmd=self._set_stop, get_parser=int) + self.add_parameter(name='center', + get_cmd = 'SENS:FREQ:CENT?', + set_cmd = self._set_center, + get_parser = int) + + self.add_parameter(name='span', + get_cmd = 'SENS:FREQ:SPAN?', + set_cmd=self._set_span, + get_parser = int) + self.add_parameter(name='npts', get_cmd='SENS:SWE:POIN?', set_cmd=self._set_npts, @@ -156,6 +166,14 @@ def _set_npts(self, val): # update setpoints for FrequencySweep param self.trace.set_sweep(self.start(), self.stop(), val) + def _set_span(self, val): + self.write('SENS:FREQ:SPAN {:.4f}'.format(val)) + self.trace.set_sweep(self.start(), self.stop(), self.npts()) + + def _set_center(self, val): + self.write('SENS:FREQ:CENT {:.4f}'.format(val)) + self.trace.set_sweep(self.start(), self.stop(), self.npts()) + def initialise(self): self.write('*RST') self.write('SENS1:SWE:TYPE LIN') From 331c19669893ccac7f91e5106f3d9e2a9c01b3cf Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 17 May 2017 17:22:44 +0200 Subject: [PATCH 03/19] Int -> float --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 65f9a3b611a7..2b7831ad9676 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -109,22 +109,22 @@ def __init__(self, name, address, **kwargs): self.add_parameter(name='start', get_cmd='SENS:FREQ:START?', set_cmd=self._set_start, - get_parser=int) + get_parser=float) self.add_parameter(name='stop', get_cmd='SENS:FREQ:STOP?', set_cmd=self._set_stop, - get_parser=int) + get_parser=float) self.add_parameter(name='center', get_cmd = 'SENS:FREQ:CENT?', set_cmd = self._set_center, - get_parser = int) + get_parser=float) self.add_parameter(name='span', get_cmd = 'SENS:FREQ:SPAN?', set_cmd=self._set_span, - get_parser = int) + get_parser=float) self.add_parameter(name='npts', get_cmd='SENS:SWE:POIN?', From 84b933710697928270ad49d67c011a1e78633ae4 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 19 May 2017 10:54:43 +0200 Subject: [PATCH 04/19] Update znb notebook --- ...odes example with Rohde Schwarz ZN20.ipynb | 1040 ++++------------- 1 file changed, 206 insertions(+), 834 deletions(-) diff --git a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb index e0e2acad4721..080c7cd5378d 100644 --- a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb +++ b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb @@ -11,379 +11,27 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "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", - " '' +\r\n", - " '' +\r\n", - " '' +\r\n", - " '' +\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" - } - ], + "outputs": [], "source": [ "%matplotlib nbagg\n", "import matplotlib.pyplot as plt\n", "\n", "from imp import reload\n", - "\n", - "import qcodes as qc\n", - "\n", - "qc.set_mp_method('spawn') # force Windows behavior on mac\n", - "\n", - "# this makes a widget in the corner of the window to show and control\n", - "# subprocesses and any output they would print to the terminal\n", - "qc.show_subprocess_widget()" + "import qcodes as qc\n" ] }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 27, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -394,25 +42,28 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Rohde-Schwarz ZNB20-2Port (serial:1311601062101551, firmware:2.10) in 0.04s\n" + "Connected to: Rohde-Schwarz ZNB20-2Port (serial:1311601062101551, firmware:2.10) in 0.11s\n" ] } ], "source": [ - "v1 =vna.ZNB20('VNA', 'TCPIP0::172.20.2.234::inst0::INSTR', server_name=None)" + "# v1 =vna.ZNB20('VNA', 'TCPIP0::172.20.2.234::inst0::INSTR', server_name=None)\n", + "v1 =vna.ZNB20('VNA', 'TCPIP0::192.168.15.100::inst0::INSTR', server_name=None)" ] }, { "cell_type": "code", - "execution_count": 29, - "metadata": {}, + "execution_count": 4, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "station = qc.Station(v1)" @@ -420,417 +71,35 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "([0.9895826882081791,\n", - " 0.9869094348257063,\n", - " 0.9857022207845295,\n", - " 0.9849716811324213,\n", - " 0.9851777067679051,\n", - " 0.9842607626269199,\n", - " 0.9829348381629962,\n", - " 0.9816473088019041,\n", - " 0.9786861283846768,\n", - " 0.977592036189242,\n", - " 0.97576729729163,\n", - " 0.9740934018474197,\n", - " 0.9729518103133459,\n", - " 0.9721370921861145,\n", - " 0.9713039723260913,\n", - " 0.9709207543511132,\n", - " 0.9708230438550919,\n", - " 0.9703666979337292,\n", - " 0.9703414381126192,\n", - " 0.9700908859391326,\n", - " 0.9699112711672869,\n", - " 0.9694166657814337,\n", - " 0.968903093853172,\n", - " 0.9682554312580419,\n", - " 0.9678450187387361,\n", - " 0.9671028614781024,\n", - " 0.9664735489036151,\n", - " 0.965510156267443,\n", - " 0.9649242678857383,\n", - " 0.9649892999018361,\n", - " 0.9644816933427587,\n", - " 0.9641921319025079,\n", - " 0.963669775695679,\n", - " 0.9631865143768873,\n", - " 0.963223910382565,\n", - " 0.963030553862949,\n", - " 0.9624009542078145,\n", - " 0.9622513785770892,\n", - " 0.9620348386109799,\n", - " 0.961453672750619,\n", - " 0.9604823245357286,\n", - " 0.9601940834710165,\n", - " 0.9594606244612337,\n", - " 0.9593216823689693,\n", - " 0.9589108029090968,\n", - " 0.9578873673683236,\n", - " 0.9573589291476022,\n", - " 0.9569588227170734,\n", - " 0.9564502087571111,\n", - " 0.955669859967192,\n", - " 0.9549499221478315,\n", - " 0.9540578765671092,\n", - " 0.9530129876524023,\n", - " 0.9517121031522534,\n", - " 0.9513873939731231,\n", - " 0.9504770541287781,\n", - " 0.9514052798363227,\n", - " 0.9519324122396933,\n", - " 0.9502438823700848,\n", - " 0.943213062343683,\n", - " 0.9371787503752951,\n", - " 0.9361742294777097,\n", - " 0.9394688962970474,\n", - " 0.9445367130494726,\n", - " 0.9472092623822433,\n", - " 0.9479792705463528,\n", - " 0.9480799944513731,\n", - " 0.9473828821678538,\n", - " 0.9455337460737451,\n", - " 0.9457087929324874,\n", - " 0.9462239698094738,\n", - " 0.9461226512723114,\n", - " 0.9455034078803901,\n", - " 0.9443907659225531,\n", - " 0.94365363844252,\n", - " 0.9430770510774368,\n", - " 0.9420973162820626,\n", - " 0.9406199004439628,\n", - " 0.9393153552545652,\n", - " 0.9383821996868444,\n", - " 0.9380895206348119,\n", - " 0.9368862835566656,\n", - " 0.9344415030119433,\n", - " 0.9311402924887935,\n", - " 0.9262748633155682,\n", - " 0.9212472780821491,\n", - " 0.9193006436522684,\n", - " 0.9201060562261194,\n", - " 0.9239782946171617,\n", - " 0.9266855495081732,\n", - " 0.9256206644137215,\n", - " 0.9230752335742844,\n", - " 0.9203336283158239,\n", - " 0.9171825974615793,\n", - " 0.9155916002239227,\n", - " 0.9154638000567723,\n", - " 0.9156386345594286,\n", - " 0.915411675480082,\n", - " 0.914080287388952,\n", - " 0.9107595174729219,\n", - " 0.9038962008036946,\n", - " 0.8927686431493355,\n", - " 0.8758581077844744,\n", - " 0.8534214948797171,\n", - " 0.8260045725743231,\n", - " 0.7947028544404089,\n", - " 0.7599259059113547,\n", - " 0.7225393521464759,\n", - " 0.6823648596301773,\n", - " 0.6393656639277121,\n", - " 0.5931113543704739,\n", - " 0.5441506885467429,\n", - " 0.4935484833551584,\n", - " 0.44340326569642374,\n", - " 0.3952782959903659,\n", - " 0.35100264189785674,\n", - " 0.31151834258445116,\n", - " 0.27700917333421426,\n", - " 0.24721802127630774,\n", - " 0.22213474407679737,\n", - " 0.20066032690466426,\n", - " 0.18234508982200742,\n", - " 0.16670859050017847,\n", - " 0.1530462944576956,\n", - " 0.1413275026823718,\n", - " 0.13058719359036725,\n", - " 0.12087065818962711,\n", - " 0.11172748051132558,\n", - " 0.10290008431824464,\n", - " 0.09465149248317925,\n", - " 0.08666126323379829,\n", - " 0.07946789030378242,\n", - " 0.0725860300638041,\n", - " 0.06631945966880881,\n", - " 0.06068450429465256,\n", - " 0.05523756855252659,\n", - " 0.05048916409687119,\n", - " 0.046112634791750706,\n", - " 0.04252924175208469,\n", - " 0.039214999209167094,\n", - " 0.03632221589554925,\n", - " 0.033960487109423926,\n", - " 0.03160439859699994,\n", - " 0.029940075621481918,\n", - " 0.02796992271519951,\n", - " 0.026643014513012757,\n", - " 0.025244254189062704,\n", - " 0.023820806664581567,\n", - " 0.022447139371216618,\n", - " 0.021050545597438262,\n", - " 0.019874088905746982,\n", - " 0.018645562732940713,\n", - " 0.01727799703196309,\n", - " 0.016002710865995674,\n", - " 0.01503032327152424,\n", - " 0.013987715380044643,\n", - " 0.01310755688557064,\n", - " 0.012115593481965576,\n", - " 0.011412071313340755,\n", - " 0.010654009997301088,\n", - " 0.009989801855445736,\n", - " 0.009477542474530308,\n", - " 0.00895126947691363,\n", - " 0.008475730814023537,\n", - " 0.008023368159711393,\n", - " 0.007653496379647708,\n", - " 0.007230465955946998,\n", - " 0.006854537670863554,\n", - " 0.006594801721280584,\n", - " 0.006223036608081843,\n", - " 0.006032662337093347,\n", - " 0.005710267944673411,\n", - " 0.0054625256725857035,\n", - " 0.005182030628555568,\n", - " 0.004905518766564076,\n", - " 0.0046588769261585745,\n", - " 0.0043293071704507005,\n", - " 0.004052557827013329,\n", - " 0.0038341147896325907,\n", - " 0.0036112055308751634,\n", - " 0.0033927249044489443,\n", - " 0.0031880555712037926,\n", - " 0.0029939316028082855,\n", - " 0.0029020418309596368,\n", - " 0.002771223631302068,\n", - " 0.002645519992786253,\n", - " 0.0025457635648588333,\n", - " 0.002479129374286534,\n", - " 0.002376064201398493,\n", - " 0.0022786035577616643,\n", - " 0.0022308097785247146,\n", - " 0.002109930637083628,\n", - " 0.0020136527194443863,\n", - " 0.001906772783176855,\n", - " 0.0018292625864839147,\n", - " 0.001689509801043019,\n", - " 0.0015958608326242783,\n", - " 0.0015611211728045495,\n", - " 0.0014947999199123089,\n", - " 0.0014254963667496704,\n", - " 0.001330926232424635],\n", - " [-0.4637218035133345,\n", - " -0.6447678115627552,\n", - " -0.8231987038344319,\n", - " -1.005804636348533,\n", - " -1.1882935648852178,\n", - " -1.3691429237764958,\n", - " -1.5501365959864954,\n", - " -1.7318710619900028,\n", - " -1.9112238200978167,\n", - " -2.090251428805007,\n", - " -2.270426256251092,\n", - " -2.4503739923681915,\n", - " -2.6297055657459634,\n", - " -2.8096638874119417,\n", - " -2.989713608670389,\n", - " 3.114134012350575,\n", - " 2.933951309345143,\n", - " 2.7535528475439186,\n", - " 2.573724473324577,\n", - " 2.3921071348300385,\n", - " 2.2111013152935564,\n", - " 2.029675538192421,\n", - " 1.8490448702823405,\n", - " 1.6675329087276884,\n", - " 1.4862310265845533,\n", - " 1.30481106145617,\n", - " 1.1238499741204908,\n", - " 0.9419879730263643,\n", - " 0.7599432241785905,\n", - " 0.578023071372694,\n", - " 0.39572932365602964,\n", - " 0.2134962483220875,\n", - " 0.03221498371449915,\n", - " -0.14953955285881196,\n", - " -0.3327929653419456,\n", - " -0.51564614920525,\n", - " -0.6982052258600608,\n", - " -0.8813233462194436,\n", - " -1.0649083152488747,\n", - " -1.250962462159386,\n", - " -1.43452833522854,\n", - " -1.6179507116440404,\n", - " -1.8019172913015926,\n", - " -1.9852294528292043,\n", - " -2.165698517660056,\n", - " -2.3487423107423595,\n", - " -2.535057992685882,\n", - " -2.7216737022961035,\n", - " -2.911143633789084,\n", - " -3.099483457041719,\n", - " 2.997380309490084,\n", - " 2.8129135867365944,\n", - " 2.6274016434130973,\n", - " 2.4407574694932386,\n", - " 2.2540668201412193,\n", - " 2.0676436180305604,\n", - " 1.8805714687074337,\n", - " 1.6924983298403085,\n", - " 1.506379287093013,\n", - " 1.316522817990967,\n", - " 1.1285859712859345,\n", - " 0.9430229614399827,\n", - " 0.7544675543855067,\n", - " 0.561407170424298,\n", - " 0.37187845683006154,\n", - " 0.18204462982356642,\n", - " -0.009185311839872331,\n", - " -0.20121323075174838,\n", - " -0.395215188944158,\n", - " -0.5892489776971399,\n", - " -0.7840904833928506,\n", - " -0.9788691849876674,\n", - " -1.1742991845436888,\n", - " -1.3694082648677244,\n", - " -1.566090331445052,\n", - " -1.7634382871097927,\n", - " -1.9619593125415025,\n", - " -2.161584877084847,\n", - " -2.362519614981662,\n", - " -2.5640987969249416,\n", - " -2.7649350836896023,\n", - " -2.966673830171186,\n", - " 3.1154444808759694,\n", - " 2.91490203419451,\n", - " 2.712423055065066,\n", - " 2.5071488143700265,\n", - " 2.3030465495064876,\n", - " 2.097088732293975,\n", - " 1.8879208728389256,\n", - " 1.6768425673161458,\n", - " 1.4661728615561327,\n", - " 1.252490772547974,\n", - " 1.0362722080809879,\n", - " 0.8180699652393353,\n", - " 0.5981768941025124,\n", - " 0.37713970887469733,\n", - " 0.15242661132471982,\n", - " -0.07693161148689913,\n", - " -0.31178895916639765,\n", - " -0.5525239192125634,\n", - " -0.7994954845539253,\n", - " -1.051127006802208,\n", - " -1.3066996237302078,\n", - " -1.5641618627388874,\n", - " -1.8230201362843257,\n", - " -2.083562947844965,\n", - " -2.343956440953144,\n", - " -2.6053730278673286,\n", - " -2.8683519178696817,\n", - " -3.132152578823861,\n", - " 2.8872920953776977,\n", - " 2.6256610329712435,\n", - " 2.370652630686787,\n", - " 2.125004799211656,\n", - " 1.8905925632084184,\n", - " 1.6691819655543654,\n", - " 1.4592803138877657,\n", - " 1.2596139542773384,\n", - " 1.0691587884262208,\n", - " 0.8873064258216831,\n", - " 0.707508835586725,\n", - " 0.5328184901807979,\n", - " 0.36144053283622934,\n", - " 0.18987860634411735,\n", - " 0.01709917167703673,\n", - " -0.15873454633721307,\n", - " -0.3352062958570742,\n", - " -0.5149910998180319,\n", - " -0.696433516908304,\n", - " -0.8750539939475772,\n", - " -1.0527366877700064,\n", - " -1.231903705283048,\n", - " -1.404871568357883,\n", - " -1.5713943458855526,\n", - " -1.7353126371336791,\n", - " -1.8964828297641938,\n", - " -2.049993269190271,\n", - " -2.203707853911233,\n", - " -2.3523604545372736,\n", - " -2.4964254305150853,\n", - " -2.6372490611548,\n", - " -2.7763903012229925,\n", - " -2.917266393033113,\n", - " -3.0577780761105644,\n", - " 3.0807529782061907,\n", - " 2.930705937428023,\n", - " 2.775350053502727,\n", - " 2.6200312491092115,\n", - " 2.4593025944789892,\n", - " 2.295699743465874,\n", - " 2.138590317088304,\n", - " 1.982356416900639,\n", - " 1.8202116829819857,\n", - " 1.6720486152538656,\n", - " 1.512464468900243,\n", - " 1.371308781495767,\n", - " 1.2375597191527623,\n", - " 1.0767866005800673,\n", - " 0.9368242043807584,\n", - " 0.7943621153773274,\n", - " 0.6538999347279995,\n", - " 0.5188922036965969,\n", - " 0.38959452139157347,\n", - " 0.24513175512537463,\n", - " 0.11132974138554518,\n", - " -0.04274015501516999,\n", - " -0.16993756552221392,\n", - " -0.3069346539085933,\n", - " -0.44679321649734777,\n", - " -0.5971430038889,\n", - " -0.7485228461463075,\n", - " -0.8899898307589587,\n", - " -1.0387652880075307,\n", - " -1.1891912793457242,\n", - " -1.3600087554236135,\n", - " -1.5001991227564042,\n", - " -1.641892938892661,\n", - " -1.796905939130636,\n", - " -1.9317395407644775,\n", - " -2.0653263071332564,\n", - " -2.2032368918755725,\n", - " -2.344697883843954,\n", - " -2.4644733459138664,\n", - " -2.6101505914591283,\n", - " -2.7193594592940613,\n", - " -2.862680284501814,\n", - " -2.9965949633329236,\n", - " 3.138945021791405,\n", - " 3.0332380708322284,\n", - " 2.874815043594395,\n", - " 2.724193928724211,\n", - " 2.6034833484710624,\n", - " 2.4433131117179867,\n", - " 2.273076475329651,\n", - " 2.142631961520665,\n", - " 1.9975653095579686,\n", - " 1.865871925122896,\n", - " 1.6868536330810981,\n", - " 1.5988409429506418,\n", - " 1.4429123365656216,\n", - " 1.2923650088441336])" + "([0.009646977277334165,\n", + " 0.0021979858842479604,\n", + " 0.011385066678388848,\n", + " 0.0036578559616232834,\n", + " 0.001534106152954764,\n", + " 0.0037237462606044343,\n", + " 0.0003013562395182502,\n", + " 0.005760142857503463,\n", + " 0.005929500614331058,\n", + " 0.0064628871815816695],\n", + " [2.4181310614736207,\n", + " 1.9080227951332198,\n", + " -0.5016603343918788,\n", + " -2.9137114727849935,\n", + " -1.7222804801278566,\n", + " 2.727342904656236,\n", + " 2.834714809822022,\n", + " 1.5005701652238659,\n", + " -1.1597524510801358,\n", + " 2.9650693082434896])" ] }, - "execution_count": 54, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -841,7 +110,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -855,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 8, "metadata": { "scrolled": false }, @@ -864,27 +133,27 @@ "name": "stdout", "output_type": "stream", "text": [ + "Started at 2017-05-19 10:47:47\n", "DataSet:\n", - " mode = DataMode.LOCAL\n", - " location = '2016-07-07/14-59-21'\n", + " location = 'data/2017-05-19/#001_{name}_10-47-47'\n", " | | | \n", " Setpoint | VNA_power_set | power | (14,)\n", - " Measured | frequency | frequency | (14, 201)\n", - " Measured | VNA_magnitude | magnitude | (14, 201)\n", - " Measured | VNA_phase | phase | (14, 201)\n", - "started at 2016-07-07 14:59:22\n" + " Setpoint | frequency_set | frequency | (14, 100)\n", + " Measured | VNA_magnitude | magnitude | (14, 100)\n", + " Measured | VNA_phase | phase | (14, 100)\n", + "Finished at 2017-05-19 10:47:48\n" ] } ], "source": [ - "data1 = qc.Loop(v1.power[-15:-1:1]).each(v1.trace).run(background = False)" + "data1 = qc.Loop(v1.power[-15:-1:1]).each(v1.trace).run()" ] }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 9, "metadata": { - "scrolled": true + "scrolled": false }, "outputs": [ { @@ -893,6 +162,7 @@ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", + "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", @@ -951,6 +221,9 @@ " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", @@ -962,7 +235,6 @@ " 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", @@ -1021,6 +293,15 @@ " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", @@ -1077,8 +358,9 @@ " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", @@ -1211,10 +493,10 @@ "}\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", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", @@ -1293,11 +575,13 @@ " 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", @@ -1346,6 +630,19 @@ " 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", @@ -1355,11 +652,12 @@ " this.canvas_div.focus();\n", " }\n", "\n", - " var x = canvas_pos.x;\n", - " var y = canvas_pos.y;\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", - " step: event.step});\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", @@ -1399,7 +697,8 @@ "\n", " this._key_event_extra(event, name);\n", "\n", - " this.send_message(name, {key: value});\n", + " this.send_message(name, {key: value,\n", + " guiEvent: simpleKeys(event)});\n", " return false;\n", "}\n", "\n", @@ -1416,7 +715,7 @@ "};\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", + "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", @@ -1475,21 +774,29 @@ "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\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.send_message('closing', {});\n", - " fig.ws.close()\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 width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] = '';\n", + " this.cell_info[1]['text/html'] = '';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", @@ -1538,14 +845,20 @@ "\n", " // Add the close button to the window.\n", " var buttongrp = $('
');\n", - " var button = $('');\n", + " var button = $('');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", - " button.mouseover('Close figure', toolbar_mouse_event);\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", @@ -1572,12 +885,9 @@ " // 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", + " // 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", @@ -1626,7 +936,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1638,10 +948,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 55, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -1652,7 +962,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -1661,6 +971,7 @@ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", + "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", @@ -1719,6 +1030,9 @@ " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", @@ -1730,7 +1044,6 @@ " 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", @@ -1789,6 +1102,15 @@ " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", @@ -1845,8 +1167,9 @@ " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", @@ -1979,10 +1302,10 @@ "}\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", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", @@ -2061,11 +1384,13 @@ " 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", @@ -2114,6 +1439,19 @@ " 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", @@ -2123,11 +1461,12 @@ " this.canvas_div.focus();\n", " }\n", "\n", - " var x = canvas_pos.x;\n", - " var y = canvas_pos.y;\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", - " step: event.step});\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", @@ -2167,7 +1506,8 @@ "\n", " this._key_event_extra(event, name);\n", "\n", - " this.send_message(name, {key: value});\n", + " this.send_message(name, {key: value,\n", + " guiEvent: simpleKeys(event)});\n", " return false;\n", "}\n", "\n", @@ -2184,7 +1524,7 @@ "};\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", + "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", @@ -2243,21 +1583,29 @@ "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\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.send_message('closing', {});\n", - " fig.ws.close()\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 width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] = '';\n", + " this.cell_info[1]['text/html'] = '';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", @@ -2306,14 +1654,20 @@ "\n", " // Add the close button to the window.\n", " var buttongrp = $('
');\n", - " var button = $('');\n", + " var button = $('');\n", " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", - " button.mouseover('Close figure', toolbar_mouse_event);\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", @@ -2340,12 +1694,9 @@ " // 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", + " // 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", @@ -2394,7 +1745,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2406,10 +1757,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 53, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -2420,12 +1771,33 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+gAAAJYCAIAAAB+fFtyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAg\nAElEQVR4nOzde1zUZd7/8Q864gSjoEAiaUApeMBGjSxKzVPcWspmobVqrkmlFkbupvcvydbNtb2T\nyqXcWFspb3UpDxuJByxTTL3FikpcMKXMU0seUEGHREXn98fgiPIZQQRmRl/Pxzwezrz5zvW9gJnx\n4+X1vS4Pq9UqAAAAAFxbI2d3AAAAAED1KNwBAAAAN0DhDgAAALgBCncAAADADVC4AwAAAG6Awh0A\nAABwAxTuAAAAgBugcAcAAADcAIU7AAAA4AYo3AEAAAA3QOEOAAAAuAEKdwAAAMANXD+Fe69evZzd\nBQAAANQB6jrV9VO4AwAAANcxCncAAADADVC4AwAAAG6Awh0AAABwAxTuAAAAgBugcAcAAADcgMHZ\nHQAAAABcnYeHRy2eZbVa67APFO4AAACAQ/aSfevWp67qiffcM69ue0LhDgAAACguK9nrvBC/WhTu\nAAAAwCWqluxWq1VkntV6roYtPPTQkFWrVtVtryjcAQAAgArqKPvFqeo1nrO+evXqOu8bhTsAAABQ\nXcleoS4vNr1aFO4AAAC4JkUFGz9cuHLXcQnvM/iJ2N6+l371YO669fnHO/cbbA40VkSWgrSUhVv2\nHQ8Kjx47ISbQBQpSW9V+xZLdxpmFO+u4AwAAoPaKst8ZGpe45LhveLAsSU4cEje/uPKXi7MT4qen\npCRvPFRWkVjypwyKS8koDO8SvGVJ0rCR7xx0Qq8v8vDwsFft99wzzzad3fEyjtYa3+qeC/wDBwAA\nAO6qbMO8JWKenDUnxiDyZPT8QfGpG/c8HhNqG1y3LHt5SmHYoKhDmZ4XnpCf8Va2hM1ekRrpKxOi\nw/uOTnp/47CpvQMbvusOrkC9MqbKAAAAwC0Z7n5+1uzmHW01pbFlSxHxNFRUmAc3vp2cKzPTnz38\nXOYvFcdbvl5e4BMzK9JXRMQQGp0QljT/yz3SsIW7WrJbrf+owVMp3AEAAOCWDG3NUW0r7hcvmp4k\nEtO1rUFEpCw3MTEzbMLfe/sb55Ze8hzvgOYX7ho79gorWba9eHLUZTPj60nNrkB1zHq+fvpVIxTu\nAAAAuHZl614blVrgM33pJNvg+ca3EgskZumIziJlTUXOVCo7A0xe1TaXlZVV+WHfvn2vsX/XWrJX\nYMQdAAAA7ixn7nPTM0vi5qzoH2gQkfIDGYmZJeYJfeXAgQNy7IjIiX27D95ye6C/SKkcOXrC/sQT\nRw5JiJ+xSoPXXqlXVuNFY6pF4Q4AAAC3lb9syqRFBXGzV4wxV0x4KTv2i4jkpkwalnLhoKT4DTIq\nc1NcYDcpXP+dZZzZJCJyYHVGSdiEjlUL97pSeaD92kp2Gwp31zPnwu+4sjUODu6lhZ9pofrj/k4L\nldOLiEgXLWyphT9r4SkHzfbQwse08EUtbKWFaq9ERN0peK8Wqt/CGAfN3qKF6jUmN2nh7Vp4zMG5\nQrVwsxb+qIX3a+F6B+dSe3urFqpz7n7voNk0LTRp4Rc17oD6MnDU7CEt/EkL2ztotoUWHtdCtWPf\naKH6mxUHvS3WQnWCpo8WHnZwriIt7KmF6keH+uoSB6/PPlr4kRaqb+c7HZyrnRbu0EL108DRR8di\nLXxGC9WXgfpbUH8sImLWQvXjV/0W1G92j4NzDdNC9X2nfp6cdNBsHy3cr4XdtXCoFn7i4FwZWqj+\nwEu0MMpBszlaeEIL1Xeu+g5t5uBcv2qhnxaqq2h7auEdDs6lfiROu6Y60vn2rEkan5wt5rhuN+3L\nyfnx7FkJ7Ng1tHNcZuZIg8EgIgZDcerDw04kLp0cFSgiPWNHSXzqq2kRU2NCtqa8uEEksV94fXSs\nVovGVIvCHQAAAG7Jkr0yQ0QkNzV+fEU0fPaKiZG+JpP93ymmpiJGr4qHJvO4OQk/xydPGpIiIjJ8\nZtpAbQemL798uk76Zxto37r1qa1bn6qDNp36rywKdwAAANSaacScTSOqO2bMyk2VH5tjZ6wdUGQp\nF4PR19ekl6NNmtRkccYr+eabf9x5p8c998z75purq7bz8vJsdyIiIi79yjwH/8PdQCjcAQAA0NCM\nvv71N6/d7mpLdht7vZ6Xl1eldnfmiLs6WQsAAACAa2HEHQAAALicNtzOBkwAAACAy7DNcU9Pl6p1\nO6vKAAAAAK7iwkB7HnPcAQAAAFenzJMREbHW+Fb3GHEHAAAAasiZc9wZcQcAAADcACPuAAAAQM2w\nqkyNWPZkfPDhZ7sKWwRHxj7xuDmwAdbsBwAAACrj4tRqWXLjB41OWrI7uEt4YUZq/LDYdQfLnd0n\nAAAA3GiceXGqexTuRf9elSs+szNTJ4+bmJqV2kdK3lue7+xOAQAA4EbDqjLVMYX+ZtbsJyJNIiJi\nuLmNjxQ4uUcAAAC48TDHvVrGwM5RgRX3CzLeXFQikx8Md2qPAAAAgAblioW7Zc/GZV/85OnpKXLm\njCni8ZhI+4WoRTlz45I2RCWkxrRVLk7Nysqy3enbt29DdRYAAAA3DmdenOqKhXvhN2uXLSvw9haR\nUgk2xcZE2nJL/rKhkxYFDZ/5WmyY+kTqdQAAANQnpspcKix2xsrYy8PyA2seH58cFDNz8cTezugU\nAAAAwIh7tYpzXhgxs0SCnunrl5uTc/bs2SaB7c2h/s7uFgAAAG4kVgr36lj2fZMrIlKYNGl8ReQz\natPKcU7sEgAAAG48FO7VMZnHbdpEmQ4AAADnonAHAAAA3ACFOwAAAOAGWFUGAAAAcH1cnAoAAAC4\nAwp3AAAAwA1QuAMAAABugMIdAAAAcAMU7gAAAIAboHAHAAAAXJ+V5SABAAAAN8CIOwAAAOAGKNwB\nAAAAN0Dh7npWa6Gng4MHauEALfybFk7TwpccnKurFh7Wwie18P85aLZUC01a+KAW/qiFRxyc65QW\n5mjhYC3c5aDZT7XwHi1co4X+Wnivg3N9rIXHtbCpFqo/mZEOzrVeC0O1sLUWOvpx9dBC9fvy0cKf\ntPCcg3M9qoXZWthNC59x0Kz6Cldfn+q34KGFBxycK1YLt2nhL1rorYWdHJzr31p4WgvVb0F9I4iI\nWQvV34L6gaa+5NRXkYg8pYV/0cJCLVR/sCLSRgv3a6FFC9XfgqNP9WZaOEcLb9PCllro6M2ovse7\na6H6Ua/+XeOIUQvVl5z6MeXoW7hFC3/Vwp5auNNBs+oncKAWqh0L0UJHv3H1w2eZFsbUuAONHJzr\nCy1UKwG4Kgp3AAAAuC/LnowPPvxsV2GL4MjYJx43B1b8O7GoYOOHC1fuOi7hfQY/Edvb9+LxBWkp\nC7fsOx4UHj12QkygGxWkVmcW7o7+QQgAAADUgCU3ftDopCW7g7uEF2akxg+LXXewXESKst8ZGpe4\n5LhveLAsSU4cEje/uOL4/CmD4lIyCsO7BG9ZkjRs5DsHndr9q3S+xre6R+EOAACA2iv696pc8Zmd\nmTp53MTUrNQ+UvLe8nyRsg3zloh5ctacqRMnz8qcEycFqRv3lIlIfsZb2RI2e0XqxHGTP1kwWQqX\nvL/RjUp3a41vdY/CHQAAALVnCv3NrNkpkbZr4ww3t6m4tMhw9/OzZv+ht20WjLFlSxHxNBhELF8v\nL/CJeSrSV0TEEBqdECZbvtzjlJ7XCoU7AAAA3JMxsHNUZFvb/YKMNxeVyMgHw0UMbc1RkaG2ae3F\ni6YnicR0bVsxmd07oLn92R17hZV8sb24wbtdS1ZrTW/1wI2uBQAAAIDrKsqZG5e0ISohNaZt5UWM\nyta9Niq1wGf60kn2dYECTF7VtrZtW1blh1279q27nl4LVpUBAACAO7PkLxs6aVHQ8JmvxYZVznPm\nPjc9syRuzor+9rVjSuXI0RP2A04cOSQhflWXK3WZSv0yrCoDAAAAt1V+YM3j45ODYmYunti78qhw\n/rIpkxYVxM1eMcZsXwrSGNhNCtd/d2HLhQOrM0rC7u2o7jPgkpjjDgAAADdVnPPCiJklEjSyr19u\nTk5OdnbuniIR2bMmaXxytpjjut20LycnJzs7Z09xuYihZ+woKUx9NS2n2FK0JunFDSLD+oU7+3uo\nOWcuB8lUGQAAANSeZd83uSIihUmTxldEPqM2rRyZvTJDRCQ3Nf5CPHz2iomRvibzuDkJP8cnTxqS\nIiIyfGbaQDfagcmpGzC5z48JAAAArsdkHrdp07iq+Yg5m0Y4eIo5dsbaAUWWcjEYfX1N7lWOUrgD\nAADgRmL09XfZee15eXm2OxEREVW+SOEOAAAAuAZbvW4v3y/FqjIAAACAK4mIiNBqd2euKsOIOwAA\nAFAz1npZLqaGKNwBAACAS9jG2pnjDgAAALguB7PbbZjjDgAAALgG+0A7c9wBAAAA18VykAAAAIAb\nqDzifnntzs6pAAAAgDugcAcAAADcAMtBAgAAAG6AEXcAAADADVC4AwAAAK5EuTJVuDgVAAAAcBm2\n5SDT00VZDZIRdwAAAMBFXBhoz9MG3dk5FQAAAHAl2u5LInK+xre6x4g7AAAAUEOMuAMAAAC4Ikbc\nAQAAgJqxsgETAAAA4AZYVQYAAABwAxTuAAAAgBugcAcAAABchm0PJm3nVOa4u54uWviog4M3aGGR\nFg7RwjQtbOzgXD5aeE4Lf9LClx00q7bwFy2M18LjWtjBwblCa9yBw1qo/moctdBUC5/Vwi+1cJ+D\nc2Vo4XYtHKeF+7WwmYNzbdTCv2vhe1o43EGzX2jhKS0M0MJ2Wljs4Fz/0MLWWnhMCyc7aPYhLVyv\nhY9pYVctVF9y4uDH9YAWrtHCTloY6eBc6kfHHi00amE/B82qHwi3aKGfFqqvjUUOzqX+at7SQvXT\n4BkHzb6uhbu0MFoLf9TCNxyc62ktvFULH9TCb7VQ/TgSkSNaWKCFvlr48s0OmtVeza/U+FxeWujo\n1ZWuhSVaqL7H1VeXiJQ6yKu6UwvVD+r/dtCC+h4P18INWnhGCx39uA45yOFSbFW7C6JwBwAAAC6y\nD7RrO6cy4g4AAAC4Aea4AwAAAG6Awh0AAABwfVYKdwAAAMANOHOOeyMnnhsAAABADTHiDgAAANQQ\nU2UAAAAAN8BykAAAAIAr0RZx5+JUAAAAuLOigo0fLly567iE9xn8RGxv+0a/Rblr3vvnysJfW0QO\nfWJM/7CLT7AUpKUs3LLveFB49NgJMYEuVpDadk5NT5eqdbtzp8pwcSoAAABqryj7naFxiUuO+4YH\ny5LkxCFx84ttec7cofEzM38NCg8qTJ0eF5+WW/EES/6UQXEpGYXhXYK3LEkaNvKdg87rvCoiIiIi\nImLoUPWL1hrf6p67Fe7FBRnLlmWsyy1zdkcAAAAgUrZh3hIxT86aM3Xi5FmZc+KkIHXjnjKRog+n\nL5KohLVzpk6cmjonzpyb8nauRUQkP+OtbAmbvSJ14rjJnyyYLIVL3t/oaqW7iEhERIRt6P1SFO41\nZVn2clxScnLS7K0U7gAAAC7AcPfzs2b/obdttouxZUsR8TQYxLJ3c4nE/W6gUUREzLFjfKRg6+5i\nEcvXywt8Yp6K9BURMYRGJ4TJli/3OK37V43CvWYOrns7OdcnKkzEu6mLTYUCAAC4MRnamqMiQ23T\n2osXTU8Siena1mDZl1coQd2CTReOah5S6TneAc0v3DV27BVW8sX24obr8LWxnq/prR64TwFsyUmc\nnhmVuOApy5vZ853dGQAAAFyibN1ro1ILfKYvnRQoYik/fckXjc2DRc5ceBRg8qq2uYSEXlf4anLy\nplp39Nqwqkz1yte8PqnAZ/iKgaGH5x9xdmcAAABwiZy5z03PLImbs6J/oEFEjK2CRQqLysrFZBAR\nKTuUI9LPdmipHDl6wv7EE0cOSYifsUqDzivNr4zC/RJlORkf51nEU0TOnDGF94+Jalucmzpzg0xe\nMMFX5D+On5mVlWW707dv3wbpKgAAACR/2ZRJiwriZq8YY65YCtLgf5tZ5NMtB/rHhIpI2f78QpHW\nzY0ihsBuUrj+O8s4s0lE5MDqjJKwCR2rFu6uisL9EuV7Ny9ftk+8RaS01PzM/TFy4B/xiyRoVIeb\nfjlwQA4cEZEju/ccDA8NvOx3TL0OAADQwPasSRqfnC3muG437cvJ+fHsWQns2DXUN2z4IJ/EpP+X\ncXtyP7+fX49LEZ9RvUONItIzdpTEp76aFjE1JmRryosbRBL7hTv7m6g5CvdLmGJnLY6tHJTl7hSR\nwkVxwxZdiDLiR38xO3NlpKnKswEAANBwLNkrM0REclPjx1dEw2evmBjp23vKvLjCYUnjhyWJiETN\nnh9nG403mcfNSfg5PnnSkBQRkeEz0wa62g5MV8DOqdUwmueuXVsmYhAxGOXrd343ZUlkWtbktu7Q\ndwAAgOuaacScTSPUrxgCx8zZ9HBRUXm5mAL9K0+UMMfOWDugyFIuBqOvr8m9SjoK9+oYjEb72Lpf\n6wAJCw1wj44DAADc0Hz9/dXc6OvvsvPatX2X7Oplnccacr/6Nyx2zqbY6g8DAAAArkrlkj09XaZN\ni6hyCCPuAAAAgLNFRFSu1PPy8vIuTcS5hbs77ZwKAAAA1Le8vLy8vLz0dKlStYtYrTW91QNG3AEA\nAICLLtTrjLgDAAAALk8ZbhcRsdb4VvcYcQcAAAAupw23C6vKAAAAAK7CtrZMeroodTsbMAEAAAAu\nwj7H3cn9qII57gAAAMDlIiIitJ2YmOMOAAAAuAGmygAAAABugMIdAAAAcAMU7gAAAIDrs7IcpOvp\nrYUWBweP7KyE2flK2KLGzRY5ONcEbSuAL7SLntdpT//aQbM3aeETWtjVQQtVHXCQz9fCWVr4gRY6\nerv00cJzWrhLC/tp4bcOzvWCFmZr4dNa+KMWhjs418taOEILD2qh2isRaaqF/9HCm7UwRgvbOTjX\nKi1M18LTWujhoNm7tLClFn6pheo3G+rgXI9o4Q4tPKWF6ot2k4NzndTCSC38TAv3OGhWfY8P0sJ/\n1rjZyQ7OtUILH9NC9XXo6Dc+Rgvf08IzWqi+YDY6OJc6nqb2drUWLtPWffjQwYdXmhaqb2f1Rfvu\nYb3Zf2jhb7WwixaqP5kA/VQSp4XHtbCVFpY5aPYeLSzUQvVl0EMLWzs4VxMt3K+F6qvLrIUrHZzL\nUR/gamyXpWrruDPiDgAAALgGbTEZOwp3AAAAwDXYB9q1zVMp3AEAAAA3QOEOAAAAuD4rhTsAAADg\nBlhVBgAAAHADjLgDAAAAroFVZQAAAACXZi/Z09NFRKZNYx13AAAAwPVUWvwxT9TlIJ16caq2vRsA\nAABwA7PV6w52Tq3hre4x4g4AAABcZJswk54uSt3OVBkAAADARVwYaFcvUXXmcpBMlQEAAAAuFxER\noSwvY7XW9FYPGHEHAAAAaoipMgAAAIAboHAHAAAAnO2KWy/ZsBwkAAAA4Gza+o+XYTlIAAAAwAVU\nrt21i1OduaoMhTsAAABQQ8xxBwAAgLsrLljz+XavOwb0DvMVEZHyPdmrP0zfXPirhPcZ/NuHe/vb\nC09LQVrKwi37jgeFR4+dEBNIQVozzHEHAADAtTqYkzZ4SNzM5ORZn/5oS/LTXhg9JSlXAiLDmy5J\nThw6cn6R7QuW/CmD4lIyCsO7BG9ZkjRs5DsHndftq3e+xre6R+EOAACAa1KWP3/YpJROcQkxQeLt\n2URERCxfL8+VPtMXz5o8ZuKMzDmjpDBzr0VEJD/jrWwJm70ideK4yZ8smCyFS97f6EaluzMvTqVw\nBwAAwDUpb9I2YWbarDEP31I5La10wNkzFx5bvl5e4BPzVKSviIghNDohTLZ8uacBO3uNWFUGAAAA\nbssU1j82TEQsZyplsa8npI6fPjh+w/1BpzMys8NGze5qqviad0DzC4cZO/YKK1m2vXhylG/D9rmW\nrFycCgAAgOtK+e7vC2z3zp4SESnYnfdLWWRbo4hIgMmr2udv25ZV+WHXrn3rvItXlpeXpy3rznKQ\nAAAAuJ4Uf52YnDloetrU/m1FZGpR9mNDp7y3of+MgS2kVI4cPWE/8MSRQxLiZ6zSQMNX6na25dvT\n06X67ZgaFnPcAQAAUMcs+7aXiHTv3LbisX/Hnj7y3Q+HRIyB3aRw/XeWii8cWJ1REnZvx6qFuxNF\nREREREQMHaptwMSqMgAAALg+2C5BNYX3DBOZ+ee5+QeLLcUHN85/c0mJDIlqJ2LoGTtKClNfTcsp\nthStSXpxg8iwfuHO7bNKmycjYrXW9FYPmCoDAACAOtOqmUFExNj5zb9P/sP4pPHDFtnyPhNm/y7S\nV0RM5nFzEn6OT540JEVEZPjMtIHutAMTF6cCAADA7ZnGLN405sID384xqZseLC4qLhcxmvxNlWbD\nmGNnrB1QZCkXg9HX1+Re5SiFOwAAAK5DBl9/f/ULRl9/l5rXXpl9arurrSrDHHcAAADgItvFqSLq\nxanOxIg7AAAAcAlbya6NuDtzqgwj7gAAAMBF9oF2ZcTder6mt3rAiLvuKy10tMdXer4SNtOO3KmF\n3bRwloNtfx/T/scmQTsyWAtv1VuVQi1cpoV7tXCGFs5xcK4QLczWQnVpqPUOmj2phQdqfK44Ldzv\n4FwdtbC7FvbQQpMWJjk4l/rL/VYL3xythO0X6M2O1cKJWviOFv5PjY8UkUAt/KsWNtfC3zhoVv0h\nLNbC3Vq7h04o4QgH51KbVadmqi38WwtvcnCuIi1sq4Vqr75w0Kz6si/XQvVTIlYL73VwLj8t3KSF\nT2rhyw6aPaaFY7RQfYupP66WDs71sRb+TQtbaOFn2t/X7RycS/0rQPWQFh50cHBvLfxv7ZU0Xvug\nXPGiEp58Wz/XO2eUcIB25BItPK23KiVaqP41qv5k1HfoBw7OFa2FjbUwVQu1KkDedHAuV1z1EFVE\nRES45og7hTsAAABw0RWntjNVBgAAAHAN9oF2rYK31vhW9xhxBwAAAC7Ky8tLTxcRmTatylSZ+pm8\nXkOMuAMAAAAVXG0JyMoYcQcAAABEKlXtQ4c6OsSZI+4U7gAAAIBIlWVk8vLyqiwsw6oyAAAAgBug\ncAcAAABcn5XCHQAAAHADrCoDAAAAuBJtgruTMeIOAAAAXGRbWyY9XbS6nakyNVF2MON/3//s34Ut\ngro8+NvHokJ9nd0hAAAAXJ9sGzBpmCpTrbKC1x4YlrRoS1B4+Okti6aMHjI/3+LsPgEAAOD65HAd\nd6u1prd64B4j7gUfv50pYbPSU6P8RSY+MfexIakfbR41Y6B79B4AAADu48LU9jzWca8Fy5bluUGj\n5kT5FuXm7JWb/H63eNM4Z/cJAAAA1xn7zqkikp4u06ZVneRO4V6NchEpXJTYa1HJhaTPnBUzzMxy\nBwAAwDWz1+uOp7bbUbhfoiwn4+M8i3iKyJkzpvD+Md1O7CgUEZkwe+mIyEDLgY2vjkiMf21N1qzL\np8pkZWXZ7vTt27eBOw0AAAA3VWk+TF7lnKky1Srfu3n5sn3iLSKlpeZn7o8xBncNk+yg+BGRgSJi\natv7d3FB2cv2WUQuG3OnXgcAAECtXVamV545U8HqzFVlXLBwN8XOWhx7SWIRESm0lIkYRUSk/GTD\n9woAAABw5oi7WywHaYp5Pk4KkmembTxYXJS/bm78ksKg/7qTKe4AAABoWNYa3+qeC464K0zmMXMS\nCuOTEzekiIgEDZo8d2KkszsFAACAGw1z3GvAHDt10+DniyxlYjD5+xqd3R0AAABct2yz26tcmSoU\n7jVmNPkbTc7uBAAAAK5btpLdti6kVrczxx0AAABwNvsyMkOHOjqEOe4AAACAs106NyZPW8fdmctB\nMuIOAAAAXE6b4C6MuAMAAACuRRtuFy5OBQAAAFyF/fpUV7s4lcIdAAAAdaG4YM3n273uGNA7rGKf\nTMue7A/eT991XIIj+z3++MC29gW9LQVpKQu37DseFB49dkJMoOsVpLZVZTSsKgMAAAB3djAnbfCQ\nuJnJybM+/dGWFOemDRo9ZUmBhIc3zUidOeKBaXvKRUTEkj9lUFxKRmF4l+AtS5KGjXznoBP7rYmI\niHDNVWUo3AEAAHBNyvLnD5uU0ikuISZIvD2biIhI0cLEFIlKyFw8a+LEGZuWThfZ8Fl+sYjkZ7yV\nLWGzV6ROHDf5kwWTpXDJ+xtdrXSvqN3tq0NWcr7Gt7rnev8zAQAAALdS3qRtwsy02N6t0zKTc2xR\n0Y5PS2TCUwMNBwtyfj5xU6s7N23aJCIilq+XF/jEzIr0FRExhEYnhCXN/3KP9A50Wu8rqVypp6fL\ntGlcnAoAAIDriCmsf2yYiFjOXEgs//mpRGTd64+nFJTYkqBBif87daBtlrt3QPMLBxo79gorWba9\neHKUb8P2WWVbRsZWvttG3C9fWIaLUwEAAHBdMYiIFBy6P3XFpDBfKViTEjdz5js9u07ubRKRAJNX\ntQ1s25ZV+WHXrn3rp6MiokyJsV2cyoi7e3hpthI+NUk/+LQWTtUuH2h8qxK+uFcJ/16sn+uUFh7X\nQnXPgNf1VnUztfCvWjhWC4c7aPYbLRynhcu0sJmDZj218D4tbFXjp691cK6WWvh4jY9cr4W3ODiX\nOumvSAvTFyjhnx00+6sWenZVwj+OUcIjLyjhPgfnerKJEq44q4Q52tPnOGj231o4TwsHn1DCUu3I\nGAfnUl+K8Vp4RgtXaWGsg3O9poU3aeHHWvipg2bf0cJ2NQ7VxRV+dHCubC18VgvV94L2MhQR2aSF\n6g+hQAu194ekOThXcHclPP2tEu7Xnq6+bTc7OFeyFqrv3L9oH+vbqs6/FREHP5n/O6CEf9KOnPiG\nEgbrp5KPtPB5rSo7p330pDpoVn3jjNfCxVr4Ty10NKCrvkFe0cLpWthX+xv/rw5mOP+PFubrx7o3\ng5dJRIZPfzrM1yAiYQOfGDVnyYrcnyf37iClcuToxY/mE0cOSYifsUoL9VqpX6byQHt1KNwBAABw\nHTG2bh8kcrik7EJQdrTEdt2qMbCbFK7/zjLObBIRObA6oyRsQseqhXvDu3RWTLhUtyIAACAASURB\nVJ7oezBRuAMAAOC6UPFfmsbOzw3ySZyemOHz8r0hsuWDP2eKJPQNFzH0jB0l8amvpkVMjQnZmvLi\nBpHEfuFO7bLDsXZ2TgUAAMB1q1UzW3lp6D0lJa54QtKk0bZ8+PQFsWFGETGZx81J+Dk+edKQFBGR\n4TPTBjp1BybbsPpltbttjrtWt9fLOo81ROEOAACAOmEas3jTGPsjQ9sxs1bGFheXS7nB5G+qVHWa\nY2esHVBkKReD0dfX5ORy1DasXmVw3dF8d0bcAQAAcD0y+epXBRt9/V1hXrsj9stVmeMOAAAAuCMK\ndwAAAMANULgDAAAAro+dUwEAAAB3wKoyAAAAgBtw5oi7tksvAAAAcGPTlpRxMkbcAQAAgItsmzGl\np2sbMDFVBgAAAHA6e8nukFMvTmWqDAAAACByYd+loUNl6FBHh1hrfKt7jLgDAAAAFSrNa89j51QA\nAADAddkmzMglRbydM+e4M1UGAAAAuCgiIsJWstsr+EqYKgMAAAC4DFvJroy4s3MqAAAA4HT2IXbb\nwjLacpAU7gAAAIALuNJakCIU7gAAAIDzRUREiFyc1+5qq8pwcSoAAACgiIiIuPz6VOv5mt7qASPu\nAAAAgIg2x50RdwAAAMDl2BeCdE2MuAMAAAAXXTbT/VLO3ICJwh0AAAC4hH0DpoaYKnP+V2nkVZMD\nmSoDAAAAXE6r2qWOd061nhURKd1Ywy5RuAMAAAAX5eXl5eXl6Qu6W601vVXr/Ekp/qf820N+3VrD\njjFVBgAAALjowkB7njboXhdz3M+VyJkCOTBKThdc1fMo3AEAAG5opaWlBw4cKC0t9fLyCgoK8vHx\ncXaPXEXdrzBzvlSsp+XnsXJieS2eXfvC3WKxnDhxomnTpr6+vo0bN651OwAAAHCK/Pz8uXPn5ubm\nenl5eXt7Hzt27OzZs7feeuvAgQMfeeQRb29vZ3fQOWyruaeni1a313bE3VouYpUjs+Twq7Xu2FUX\n7qWlpQsXLly7du3hw4dtSZMmTcLDw/v16/fggw/esL9gAAAA95KcnHzkyJHY2NgZM2bYRtmtVmtR\nUdGPP/6Ynp6enp7+wQcf3Gij7/aS3bFarSpzrkQsn8vPo+X8r7XrmM3VFe5ffPHFwoULo6Kipk2b\nFhoa2qxZs5MnT/7yyy/79+9ftWpVWlram2++edttt11LhwAAANAAYmNjb7nllsqJh4dHQEBAQEBA\nVFTUzz//7Onp6ay+OUtEREReXt7QoY5r95pcdVrZ+RI5WygHRsmpb6+5d1dZuN98881///vfDYaL\nz/Lx8fHx8enQoUN0dPRPP/3UpEmTa+8TAAAA6ttlVftl2rRp02A9cR11OOL+2p+nyflfpXCiHF9Y\nBz0TEREP69X+u8FV9erVa9OmTXXV2kseHlXDmx0crJ71bi1ULwV4TAtfdnCuzVr4vBaeqvHTRSRU\nC18JV8Kpu5TwF+3p5xyc64wWqv+CfFMLdzhodkA/JXx4vRIubamE3x1TwgMOzrVPC3tqofqZl6qF\nhx2ca48W/qupEh49rYRJDpqdoYXLtHCvFj6ohdqPUESkf6ASnj+ohK9rTy9z0OzHWrhWC3+vhR9p\nL+/B2stbRFK0UB2lUI/8jRY6ejOq0w3XaKE6DhbgoFn14B+1sJkWTtXCUgfnUgsB9SejvmvUb1ZE\n7tJC7S0uwQ5aqMrRUJP6ramf1XcMVkKPm5TwraX6uTprofpmVD/VP0zQm30/WQm1TPK0N94J7bPD\n67f6uf78jhKqv0f1Kj9H8zAe18Jw7W/iudoHaFft6Y6q1L9pofom/Z0WFmnhDw7Olap9C60OObMY\nKysre/PNN7dt23bmzMW/on//+9/ff//9TuxVr169kpPrrK67Wrby3aby9al33ulhza1pI2c7lDY5\nFCfFH1V/6M1/lFbTa9JmLS9OXbFixfr163/99eI0nf79+w8fPrx2rQEAAMApli9f/v333yckJLRq\n1coeBgZqgy43gMole3q6TJtW5d+bNf5H1i1tQg7/8oMETJUDo6Rse510rzaF+/fff5+cnDxy5Mh2\n7dpd7NwV/7cFAAAALqikpOShhx7q2VP9P7AbSA0myVydI0eOSGMfadxFbtsoljVy4Hdi1f5z/GrU\npnAvLCy85557nnzyyWs8NwAAAJzrvvvu+9e//nXmzJkb8FJUO9tGS7bLUqvml0S1WA2ysY80f1Q6\nx8qhV+TIa9fSz9oU7nfccUdGRsa5c+dYvh0AAMCtde7cedmyZQ8//HDbtm3tYVxcXI8ePa66reKC\nNZ9v97pjQO8w38rxwdx16/OPd+432BxorIgsBWkpC7fsOx4UHj12Qkygs3cEtVXnlWt02wB81Q2Y\nrLVbxt3DICJy81QJ+L0ceFJOrqhdP2vzcwoICOjVq9ejjz5qNps9LlzEec899wwcOLB2nQAAAIBT\nrF+/ftu2bU8//bS/v789DA1V1624koM5aU9NSikR8Rke0jss8uIXirMT4qcXigzvPKCicLfkTxk0\nPlvCho/q8OmipMzN+5YunuhSc+orz3S/3LVcSNzIW8Rb2i6Q07vkwCg5o64RcCW1KdwPHz48b968\nfv36hYSE2MMb9iIGAAAA9/Xjjz8+/PDDQy+bI3KVyvLnD5uUGhWXEJCZnONZecUmy7KXpxSGDYo6\nlGmfiJOf8Va2hM1ekRrpKxOiw/uOTnp/47CpvV2okrQPtCtTZa59BaDGvuLVQ9p/KyVL5ee4q3pq\nbQr3vLy8O+64Y8qUKbV4LgAAAFzHvffeu3r16mtspLxJ24SZabG9W6dlJudUyg9ufDs5V2amP3v4\nucwLi0dbvl5e4BMzK9JXRMQQGp0QljT/yz3iSoX7ldTN0p0e0qiZ+I6SFk/KLy/U/Gm1Kdw7deq0\nevVqq9XqoS12DgAAAHdRUlKSn58fFxfXunVrezhs2DCz2VzzRkxh/WPDRMRyyW4tZbmJiZlhE/7e\n298499L9EbwDml+4a+zYK6xk2fbiyVGXzIt3Acpwu9RV4S4iIh6eIiKt/lzzifO1KdzLy8sNBkN8\nfHzHjh3ttbvZbGYhIQAAAPfi5+cXExNzWdiypbZb4VXa+FZigcQsHdFZpKypyJlKZWeAyavap2/b\nllX5Ydeufa+9SzVUX3PcVY3Uje90tSncz58/X/m6YwAAALipDh06dOjQoc6bLT+QkZhZYp7QVw4c\nOCDHjoic2Lf74C23B/qLlMqRoyfsR544ckhC/IxVWmjISv0yV5jjXstVZepIbQr3W2+99bnnnqvz\nrgAAAKAh7dixY/v27d27dw8LC/vggw8+/vhjf3//5557LjIysvonX1HZsV9EJDdl0rCUC1FS/AYZ\nlbkpLrCbFK7/zjLObBIRObA6oyRsQseqhbuLqvMR96tx1YX7yZMnc3Nzb7nlltDQ0G3bts2bN89g\nMDz22GNRUVH10T+7soO5Hy1clrPveIvge2OfeOTiOqAAAAC4eps3b37llVciIyMzMjJGjBjx1Vdf\n/elPf/rxxx9feeWVpUuXent7165Z22x2U+e4zMyRBoNBRAyG4tSHh51IXDo5KlBEesaOkvjUV9Mi\npsaEbE15cYNIYr/wuvqm6orD2TJuNOJ+9OjRsWPHGo3GsrKyxMTEWbNm/fa3vz116tQrr7zy/vvv\n19/8mfKDax4YNlN8zKNiu/x7WUp8RtrMpZ/0dvpi/QAAAG5r5cqV8fHxjzzyyNGjR4cNG/bGG290\n7969e/fuX3zxxY4dO+66667aNduqmUFExGAwmUwXMlNTEaNXxUOTedychJ/jkycNSRERGT4zbaDL\nFHX2ej09XURk2rQqF6c61dX9mNasWdO5c+eZM2eeOnUqLi5u8ODBjz76qIgcOnRo8+bNv/3tb+un\nk7JrzVKRQWkrp7YVkTHR03qN/tvy/N7jruJiZwAAAFR29OjR8PBwEfHz8/Pz8wsICLDlrVq1On78\neK2aNI1ZvGmMmq/cVPmxOXbG2gFFlnIxGH19Ta5StcuF2e1XujjVqSPuja7q6EOHDkVGRnp4eHh5\neYWEhNiH2Fu3bl1UVFQP3avQxHSTyKly24Pys6dFgoPr4GJnAACAG5bVenG+tqenp32pwIZZ79vo\n6+/v7+9SVXtlDjekstb4Vg+u7od1/vz5Ro0qav2mTZs2btzYdt/Dw6Py777OhQ3+w6Dk0aMHx/W5\nN6hwy4YCn5gFfVjWBgAA4Jps3Ljxhx9+EBGLxfL555/7+vqKyIEDB+6++25nd82ZLqwko427u9Ec\ndxHZu3fvl19+KSJHjx794YcfbrrpJhHZv3+/7U5dKMvJ+DjPIp4icuaMKbx/TFRby/5du0VEpOIc\nJTt37beEhpkue2ZWVsV6n337Om39IAAAALfQqVOnXbt27dq1S0Rsi47Yci8vLz8/P6d2zSVEREQo\ny0G60aoyLVq0WLt27datW20P161bt27dOtv9Bx98sI66VL538/Jl+8RbREpLzc/cHyOWZdNmFkRN\nzpwVYxIRKV4WP2TmtIyei0dcVrlTrwMAANTQ73//e2d3wQ25UeEeFxcXFxdXT125wBQ7a3HsJYlF\nRCQg6EKZ7ntHZJAsO1lez/0AAAC4Xp07d66kpMTRV00mk6enZ0P2x9XYrk+9bLhdxK0KdycxtAwW\nyZifEe3XO7jF8R8/fz21UPq0u3yiDAAAAGrmhx9+ePrppysn9ksWPT09p06d2r9/fyd1zfny8vJs\ny0FWrdvdqXDv16+foy/FxsY+++yz19wflTHm1QW/vDgxKX50koiI+ESNWvDf/d3i3xwAAAAuqEOH\nDps2bRKRX3/9dfr06TExMT169Dh//nxWVlZ2dvb999/v7A46x5UWgrRxo8I9LS3Ndmf+/Pne3t4P\nPvhg06ZNt23b9tlnn40YMaIeuneBMXTcnJW/Ky6yiIiY/H3ZNhUAAKAOfPrppx07duzZs6ft4aBB\ng7Zv3/71119HRUU5t2POYhtrd8iNVpUJDAwUkd27dx8+fPitt96yhW3atCktLV29enX91u4iRl9/\nCnYAAIA6dPjw4aZNm1ZOrFbrwYMHndUf54qIiNBXgbzA6kYbMNns3bu3WbNmlZNmzZrt3bu3bnoE\nAACAhtKjR4/FixdnZWWdPHmyuLg4IyMjKyvrzjvvdHa/XEL1M2caVm0minfq1GnWrFkbNmzo06eP\niPz0008LFy4cOXJkHXcNAAAA9axbt26TJk169913baPsISEh06dPv/XWW53dL+ewX5ZqM22a+68q\n07p165deemn27Nl//vOfmzRpcvr06UcfffShhx6q884BAACgvkVHR0dHR1sslsaNG9fdlprXKTea\n427Xp0+f++67r7Cw8PTp023atPHy8qrbbgEAAKAhmUwVS21/9NFHQUFBvXv3dm5/nGXo0Cten+pG\nI+5HjhwJCAiw3W/SpElwcHDlr5aWlp4+fbply5Z11jsAAADUp/T09MWLF1dOjh49+vbbbzurP84V\nERGRl5d3pdrdjQr3jRs3bt26dfDgwd27d7dfn3rmzJl9+/atWrXq888//8tf/kLhDgAA4C7uu+++\n22+/3XbfarXu3Llzz549YWFhzu2Vs9ivRnVYu7vRVJlHH330zjvvfPfdd1955RU/P79mzZqVlJQc\nO3bMy8urb9++77777g17KQMAAIA7uvnmm2+++Wb7Q7PZPGvWrM2bN9+YezBFXLJXal5eXt6liZOX\ng7zqOe4hISGzZs0qLS3dvXv3iRMnPD09/f39Q0JCGjWqzcqSAAAAcCmNGzcuLS11di+cyTbunp6u\nrSrjVLW8ONXb2/uOO+6o264AAACggRUUFOzYscP+sLCw8P/+7/9CQkI++eSTW2+9tXv37k7sm7Nc\nGGVXRtzdaY47AAAArif/+c9/vvzyy8pJeHh4Tk6OiJw5c+bGLNyvNOLuXlNlAAAAcN3o27dv3759\nnd0L1+KyI+5MTAcAALgRff3111arXoeeP39+8+bNJ0+ebOAuOV1eJenpcnnVLiLWGt/qQW1G3L/6\n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\n3DtPnAgbOdKbJQMf3Nvf3V5dbRozRkSOyURdanKspyVtLdUp2RVRaQWrUg3KBcjrAAAAEB8m9V58\nG9w7OzuPHz+1d++I66/3ZvHAB3dD6uNbU8+9mKNt213LSqKSCzYsT/D/QQEAAOA85uFZSx7nkPE2\n0/suuH9jsTjefffIwoWj77//vAnunp0489LS+OCCAqtE3T9rXFNj46lTpy6KvMI4OSJwxwYAAIDz\njDLNe3tbqpMvetw7v/rqG4vFcs89J7vbvL00fIO7ZvTlrte2A+82iYi0F2Uv6yqFp9dvXRqI4wIA\nAMD5yr2FZiingOw8eTJMo/kqL+/Y6tUDWH34Bnft5OT6+mTna51xaX09MR0AAAAD4crrg43pgxhx\n77TZjm/YYL333gFv4YKB7xwAAAA4H7iaZFwtMQPT+Y23X2etZbWeevvtw9OmDSa1y3AecQcAAAB8\npUeD+yC6Zfp5c2rnsWOdX39tWbLkxNat/VtTheAOAACAEKK6RdX3je/L7rtPTp+2FRTYfvvbwW6r\nG8EdAAAAIS0mJsbbp6h63eP+5O9+98Utt5zcsWNQR3Y2gjsAAABCmve3rnrfKfP9mTP3vPnmqb/9\nzbJo0Teffz7wg+uB4A4AAICQ5t7+7inBez+pzL59+y4YO3bkTTd96+OPv3766aM5OYM6RBFhVhkA\nAABAVFO8u+v0+qvLhReGjRo1+oEHIr/+etTChYM8QoI7AAAAQlpzc7OXPe79Du4iIhI2alTYqFHh\nTz01/v33L4qNHfBx0ioDAACA4OTNILq7lBSP2b2fs0GeJUyv1+j1l27ffvKNNyz33NNps/V3CwR3\nAAAABAllUh/83I4ug3hwapcL9PqRycmXffGF7be/teXn92tdgjsAAACCRM852l0h3vm0VJ/E98EH\ndxEJ02hERPfww2NWrLBmZHi/IsEdAAAAQaKP3hhnfO+lv2l+MK0yvYSNGRMmEv7cc53Hj3u5CsFd\nbV9/Fm7dqyi+9rCi+MsGRdFWpigmethX51eK4tZLFMWwcMXp+YMm9en5wzH/2714+Jb/516syVas\nrldt85vDZuW+rtl/pXvxdOuH7kXNFbPdi9/98RvKzY6YrijGZyrO8OO1Dvfihaqt7tuv3JVs/Iui\n+GXG1+7FB1Wrr/+eopi1VL2v4ocUxdNtiuKyXyuKz9SqN3tip6KoOhPln9sUxetK3J85Jw+4PXbO\n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\ngjsAAABwHvj/flOHmmUdY54AAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "qc.QtPlot(data1.VNA_magnitude)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { From 2ddc94e430d4325c4e1534f96115edec21aabdbe Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 19 May 2017 11:00:27 +0200 Subject: [PATCH 05/19] Znb 20 add setpoint unit --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 2b7831ad9676..f09dd5c86496 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -36,6 +36,7 @@ def __init__(self, name, instrument, start, stop, npts): self.set_sweep(start, stop, npts) self.names = ('magnitude', 'phase') self.units = ('dBm', 'rad') + self.setpoint_units = (('Hz',), ('Hz',)) self.setpoint_names = (('frequency',), ('frequency',)) def set_sweep(self, start, stop, npts): From 8bdc469c54e8f4afcc697919663b1d2acbdc00a6 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 19 May 2017 10:37:37 +0200 Subject: [PATCH 06/19] Fix: wip towards more channels in znb20 --- .../instrument_drivers/rohde_schwarz/ZNB20.py | 138 ++++++++++-------- 1 file changed, 74 insertions(+), 64 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index f09dd5c86496..836fd5c66bb5 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -1,3 +1,5 @@ +from functools import partial + from qcodes import VisaInstrument from qcodes.utils import validators as vals from cmath import phase @@ -30,10 +32,11 @@ class FrequencySweep(MultiParameter): TODO: - ability to choose for abs or db in magnitude return """ - def __init__(self, name, instrument, start, stop, npts): + def __init__(self, name, instrument, start, stop, npts, channel): super().__init__(name, names=("", ""), shapes=((), ())) self._instrument = instrument self.set_sweep(start, stop, npts) + self._channel = channel self.names = ('magnitude', 'phase') self.units = ('dBm', 'rad') self.setpoint_units = (('Hz',), ('Hz',)) @@ -47,15 +50,15 @@ def set_sweep(self, start, stop, npts): self.shapes = ((npts,), (npts,)) def get(self): - self._instrument.write('SENS1:AVER:STAT ON') - self._instrument.write('AVER:CLE') + self._instrument.write('SENS{}:AVER:STAT ON'.format(self._channel)) + self._instrument.write('SENS{}:AVER:CLE'.format(self._channel)) self._instrument.cont_meas_off() # instrument averages over its last 'avg' number of sweeps # need to ensure averaged result is returned for avgcount in range(self._instrument.avg()): self._instrument.write('INIT:IMM; *WAI') - data_str = self._instrument.ask('CALC:DATA? SDAT').split(',') + data_str = self._instrument.ask('CALC{}:DATA? SDAT'.format(self._channel)).split(',') data_list = [float(v) for v in data_str] # data_list of complex numbers [re1,im1,re2,im2...] @@ -82,56 +85,52 @@ class ZNB20(VisaInstrument): def __init__(self, name, address, **kwargs): super().__init__(name=name, address=address, **kwargs) - - self.add_parameter(name='power', - label='Power', - unit='dBm', - get_cmd='SOUR:POW?', - set_cmd='SOUR:POW {:.4f}', - get_parser=int, - vals=vals.Numbers(-150, 25)) - - self.add_parameter(name='bandwidth', - label='Bandwidth', - unit='Hz', - get_cmd='SENS:BAND?', - set_cmd='SENS:BAND {:.4f}', - get_parser=int, - vals=vals.Numbers(1, 1e6)) - - self.add_parameter(name='avg', - label='Averages', - unit='', - get_cmd='AVER:COUN?', - set_cmd='AVER:COUN {:.4f}', - get_parser=int, - vals=vals.Numbers(1, 5000)) - - self.add_parameter(name='start', - get_cmd='SENS:FREQ:START?', - set_cmd=self._set_start, - get_parser=float) - - self.add_parameter(name='stop', - get_cmd='SENS:FREQ:STOP?', - set_cmd=self._set_stop, - get_parser=float) - - self.add_parameter(name='center', - get_cmd = 'SENS:FREQ:CENT?', - set_cmd = self._set_center, - get_parser=float) - - self.add_parameter(name='span', - get_cmd = 'SENS:FREQ:SPAN?', - set_cmd=self._set_span, - get_parser=float) - - self.add_parameter(name='npts', - get_cmd='SENS:SWE:POIN?', - set_cmd=self._set_npts, - get_parser=int) - + n = 0 + + for i in range(2): + for j in range(2): + self.add_parameter(name='power{}{}'.format(i, j), + label='Power{}{}'.format(i, j), + unit='dBm', + get_cmd='SOUR{}:POW?'.format(n), + set_cmd='SOUR{}:POW {:.4f}'.format(n), + get_parser=int, + vals=vals.Numbers(-150, 25)) + self.add_parameter(name='bandwidth{}{}.format(i, j)', + label='Bandwidth{}{}.format(i, j)', + unit='Hz', + get_cmd='SENS{}:BAND?'.format(n), + set_cmd='SENS{}:BAND {:.4f}'.format(n), + get_parser=int, + vals=vals.Numbers(1, 1e6)) + self.add_parameter(name='avg{}{}'.format(i ,j), + label='Averages{}{}'.format(i ,j), + unit='', + get_cmd='SENS{}:AVER:COUN?'.format(n), + set_cmd='SENS{}:AVER:COUN {:.4f}'.format(n), + get_parser=int, + vals=vals.Numbers(1, 5000)) + self.add_parameter(name='start{}{}'.format(i ,j), + get_cmd='SENS{}:FREQ:START?'.format(n), + set_cmd=partial(self._set_start, channel=n), + get_parser=float) + self.add_parameter(name='stop{}{}'.format(i ,j), + get_cmd='SENS{}:FREQ:STOP?'.format(n), + set_cmd=partial(self._set_stop, channel=n), + get_parser=float) + self.add_parameter(name='center{}{}'.format(i ,j), + get_cmd='SENS{}:FREQ:CENT?'.format(n), + set_cmd=partial(self._set_center, channel=n), + get_parser=float) + self.add_parameter(name='span{}{}'.format(i ,j), + get_cmd = 'SENS{}:FREQ:SPAN?'.format(n), + set_cmd=partial(self._set_span, channel=n), + get_parser=float) + self.add_parameter(name='npts{}{}'.format(i ,j), + get_cmd='SENS:SWE:POIN?', + set_cmd=partial(self._set_npts, channel=n), + get_parser=int) + n += 1 self.add_parameter(name='trace', start=self.start(), stop=self.stop(), @@ -152,27 +151,38 @@ def __init__(self, name, address, **kwargs): self.initialise() self.connect_message() - def _set_start(self, val): - self.write('SENS:FREQ:START {:.4f}'.format(val)) + def _setup_s_channels(self): + """ + Sets up 4 channels with a single trace in each. + Each channel will contain one trace. + """ + n = 0 + for i in range(2): + for j in range(2): + self.write("CALC{}:PAR:SDEF 'Trc1', 'S{}{}".format(n, i, j)) + n += 1 + + def _set_start(self, val, channel): + self.write('SENS{}:FREQ:START {:.4f}'.format(channel, val)) # update setpoints for FrequencySweep param self.trace.set_sweep(val, self.stop(), self.npts()) - def _set_stop(self, val): - self.write('SENS:FREQ:STOP {:.4f}'.format(val)) + def _set_stop(self, val, channel): + self.write('SENS{}:FREQ:STOP {:.4f}'.format(channel, val)) # update setpoints for FrequencySweep param self.trace.set_sweep(self.start(), val, self.npts()) - def _set_npts(self, val): - self.write('SENS:SWE:POIN {:.4f}'.format(val)) + def _set_npts(self, val, channel): + self.write('SENS{}:SWE:POIN {:.4f}'.format(channel, val)) # update setpoints for FrequencySweep param self.trace.set_sweep(self.start(), self.stop(), val) - def _set_span(self, val): - self.write('SENS:FREQ:SPAN {:.4f}'.format(val)) + def _set_span(self, val, channel): + self.write('SENS{}:FREQ:SPAN {:.4f}'.format(channel, val)) self.trace.set_sweep(self.start(), self.stop(), self.npts()) - def _set_center(self, val): - self.write('SENS:FREQ:CENT {:.4f}'.format(val)) + def _set_center(self, val, channel): + self.write('SENS{}:FREQ:CENT {:.4f}'.format(channel, val)) self.trace.set_sweep(self.start(), self.stop(), self.npts()) def initialise(self): From 5115b07437548f33191993b9ca0f1e2a97e6bb02 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 19 May 2017 14:23:09 +0200 Subject: [PATCH 07/19] Working snm for ZNB --- .../instrument_drivers/rohde_schwarz/ZNB20.py | 98 +++++++++++++------ 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 836fd5c66bb5..bba45fed4516 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -32,11 +32,12 @@ class FrequencySweep(MultiParameter): TODO: - ability to choose for abs or db in magnitude return """ - def __init__(self, name, instrument, start, stop, npts, channel): + def __init__(self, name, instrument, start, stop, npts, channel, sindex): super().__init__(name, names=("", ""), shapes=((), ())) self._instrument = instrument self.set_sweep(start, stop, npts) self._channel = channel + self._sindex = sindex self.names = ('magnitude', 'phase') self.units = ('dBm', 'rad') self.setpoint_units = (('Hz',), ('Hz',)) @@ -56,7 +57,7 @@ def get(self): # instrument averages over its last 'avg' number of sweeps # need to ensure averaged result is returned - for avgcount in range(self._instrument.avg()): + for avgcount in range(getattr(self._instrument, 'avg{}{}'.format(*self._sindex))()): self._instrument.write('INIT:IMM; *WAI') data_str = self._instrument.ask('CALC{}:DATA? SDAT'.format(self._channel)).split(',') data_list = [float(v) for v in data_str] @@ -79,35 +80,37 @@ class ZNB20(VisaInstrument): Requires FrequencySweep parameter for taking a trace TODO: - - centre/span settable for frequwncy sweep + - centre/span settable for frequency sweep - check initialisation settings and test functions """ def __init__(self, name, address, **kwargs): super().__init__(name=name, address=address, **kwargs) - n = 0 - - for i in range(2): - for j in range(2): + n = 1 + self._sindex_to_channel = {} + self._channel_to_sindex = {} + for i in range(1,3): + self._sindex_to_channel[i] = {} + for j in range(1,3): self.add_parameter(name='power{}{}'.format(i, j), label='Power{}{}'.format(i, j), unit='dBm', get_cmd='SOUR{}:POW?'.format(n), - set_cmd='SOUR{}:POW {:.4f}'.format(n), + set_cmd='SOUR{}'.format(n)+':POW {:.4f}', get_parser=int, vals=vals.Numbers(-150, 25)) - self.add_parameter(name='bandwidth{}{}.format(i, j)', - label='Bandwidth{}{}.format(i, j)', + self.add_parameter(name='bandwidth{}{}'.format(i, j), + label='Bandwidth{}{}'.format(i, j), unit='Hz', get_cmd='SENS{}:BAND?'.format(n), - set_cmd='SENS{}:BAND {:.4f}'.format(n), + set_cmd='SENS{}'.format(n)+':BAND {:.4f}', get_parser=int, vals=vals.Numbers(1, 1e6)) self.add_parameter(name='avg{}{}'.format(i ,j), label='Averages{}{}'.format(i ,j), unit='', get_cmd='SENS{}:AVER:COUN?'.format(n), - set_cmd='SENS{}:AVER:COUN {:.4f}'.format(n), + set_cmd='SENS{}'.format(n)+':AVER:COUN {:.4f}', get_parser=int, vals=vals.Numbers(1, 5000)) self.add_parameter(name='start{}{}'.format(i ,j), @@ -130,12 +133,16 @@ def __init__(self, name, address, **kwargs): get_cmd='SENS:SWE:POIN?', set_cmd=partial(self._set_npts, channel=n), get_parser=int) - n += 1 - self.add_parameter(name='trace', - start=self.start(), - stop=self.stop(), - npts=self.npts(), - parameter_class=FrequencySweep) + self.add_parameter(name='trace{}{}'.format(i, j), + start=getattr(self, 'start{}{}'.format(i, j))(), + stop=getattr(self, 'stop{}{}'.format(i, j))(), + npts=getattr(self, 'npts{}{}'.format(i, j))(), + channel=n, + sindex=(i, j), + parameter_class=FrequencySweep) + self._sindex_to_channel[i][j] = n + self._channel_to_sindex[n] = (i, j) + n += 1 self.add_function('reset', call_cmd='*RST') self.add_function('tooltip_on', call_cmd='SYST:ERR:DISP ON') @@ -149,6 +156,7 @@ def __init__(self, name, address, **kwargs): self.add_function('rf_on', call_cmd='OUTP1 ON') self.initialise() + self._setup_s_channels() self.connect_message() def _setup_s_channels(self): @@ -156,34 +164,63 @@ def _setup_s_channels(self): Sets up 4 channels with a single trace in each. Each channel will contain one trace. """ - n = 0 - for i in range(2): - for j in range(2): - self.write("CALC{}:PAR:SDEF 'Trc1', 'S{}{}".format(n, i, j)) - n += 1 + for i in range(1,3): + for j in range(1,3): + n = self._sindex_to_channel[i][j] + self.write("CALC{}:PAR:SDEF 'Trc{}', 'S{}{}'".format(n, n, i, j)) def _set_start(self, val, channel): self.write('SENS{}:FREQ:START {:.4f}'.format(channel, val)) + i, j = self._channel_to_sindex[channel] + stop = getattr(self, 'stop{}{}'.format(i, j))() + npts = getattr(self, 'npts{}{}'.format(i, j))() + trace = getattr(self, 'trace{}{}'.format(i, j)) # update setpoints for FrequencySweep param - self.trace.set_sweep(val, self.stop(), self.npts()) + trace.set_sweep(val, stop, npts) def _set_stop(self, val, channel): self.write('SENS{}:FREQ:STOP {:.4f}'.format(channel, val)) + i, j = self._channel_to_sindex[channel] + start = getattr(self, 'start{}{}'.format(i, j))() + npts = getattr(self, 'npts{}{}'.format(i, j))() + trace = getattr(self, 'trace{}{}'.format(i, j)) # update setpoints for FrequencySweep param - self.trace.set_sweep(self.start(), val, self.npts()) + trace.set_sweep(start, val, npts) def _set_npts(self, val, channel): self.write('SENS{}:SWE:POIN {:.4f}'.format(channel, val)) + i, j = self._channel_to_sindex[channel] + start = getattr(self, 'start{}{}'.format(i, j))() + stop = getattr(self, 'stop{}{}'.format(i, j))() + trace = getattr(self, 'trace{}{}'.format(i, j)) # update setpoints for FrequencySweep param - self.trace.set_sweep(self.start(), self.stop(), val) + trace.set_sweep(start, stop, val) def _set_span(self, val, channel): self.write('SENS{}:FREQ:SPAN {:.4f}'.format(channel, val)) - self.trace.set_sweep(self.start(), self.stop(), self.npts()) + i, j = self._channel_to_sindex[channel] + start = getattr(self, 'start{}{}'.format(i, j))() + stop = getattr(self, 'stop{}{}'.format(i, j))() + npts = getattr(self, 'npts{}{}'.format(i, j))() + trace = getattr(self, 'trace{}{}'.format(i, j)) + trace.set_sweep(start, stop, npts) def _set_center(self, val, channel): self.write('SENS{}:FREQ:CENT {:.4f}'.format(channel, val)) - self.trace.set_sweep(self.start(), self.stop(), self.npts()) + i, j = self._channel_to_sindex[channel] + start = getattr(self, 'start{}{}'.format(i, j))() + stop = getattr(self, 'stop{}{}'.format(i, j))() + npts = getattr(self, 'npts{}{}'.format(i, j))() + trace = getattr(self, 'trace{}{}'.format(i, j)) + trace.set_sweep(start, stop, npts) + + def _set_default_values(self): + for i in range(1,3): + for j in range(1,3): + getattr(self, 'start{}{}'.format(i,j))(1e6) + getattr(self, 'stop{}{}'.format(i, j))(2e6) + getattr(self, 'npts{}{}'.format(i, j))(10) + getattr(self, 'power{}{}'.format(i, j))(-50) def initialise(self): self.write('*RST') @@ -192,7 +229,4 @@ def initialise(self): self.write('TRIG1:SEQ:SOUR IMM') self.write('SENS1:AVER:STAT ON') self.update_display_on() - self.start(1e6) - self.stop(2e6) - self.npts(10) - self.power(-50) + self._set_default_values() \ No newline at end of file From 8cdffbb5a8a6514950d96d869b1647732e6fc5d2 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 19 May 2017 14:23:42 +0200 Subject: [PATCH 08/19] refresh znb noteboo --- ...odes example with Rohde Schwarz ZN20.ipynb | 210 ++++++++++++------ 1 file changed, 145 insertions(+), 65 deletions(-) diff --git a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb index 080c7cd5378d..c7fa050429ac 100644 --- a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb +++ b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb @@ -10,7 +10,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "%matplotlib nbagg\n", @@ -49,7 +51,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Rohde-Schwarz ZNB20-2Port (serial:1311601062101551, firmware:2.10) in 0.11s\n" + "1\n", + "2\n", + "3\n", + "4\n", + "Connected to: Rohde-Schwarz ZNB20-2Port (serial:1311601062101551, firmware:2.10) in 0.23s\n" ] } ], @@ -61,6 +67,26 @@ { "cell_type": "code", "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"'Trc4,S22'\\n\"" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1.ask('CALC4:PAR:CAT?')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, "metadata": { "collapsed": true }, @@ -71,60 +97,115 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "([0.009646977277334165,\n", - " 0.0021979858842479604,\n", - " 0.011385066678388848,\n", - " 0.0036578559616232834,\n", - " 0.001534106152954764,\n", - " 0.0037237462606044343,\n", - " 0.0003013562395182502,\n", - " 0.005760142857503463,\n", - " 0.005929500614331058,\n", - " 0.0064628871815816695],\n", - " [2.4181310614736207,\n", - " 1.9080227951332198,\n", - " -0.5016603343918788,\n", - " -2.9137114727849935,\n", - " -1.7222804801278566,\n", - " 2.727342904656236,\n", - " 2.834714809822022,\n", - " 1.5005701652238659,\n", - " -1.1597524510801358,\n", - " 2.9650693082434896])" + "{'IDN': ,\n", + " 'avg11': ,\n", + " 'avg12': ,\n", + " 'avg21': ,\n", + " 'avg22': ,\n", + " 'bandwidth11': ,\n", + " 'bandwidth12': ,\n", + " 'bandwidth21': ,\n", + " 'bandwidth22': ,\n", + " 'center11': ,\n", + " 'center12': ,\n", + " 'center21': ,\n", + " 'center22': ,\n", + " 'npts11': ,\n", + " 'npts12': ,\n", + " 'npts21': ,\n", + " 'npts22': ,\n", + " 'power11': ,\n", + " 'power12': ,\n", + " 'power21': ,\n", + " 'power22': ,\n", + " 'span11': ,\n", + " 'span12': ,\n", + " 'span21': ,\n", + " 'span22': ,\n", + " 'start11': ,\n", + " 'start12': ,\n", + " 'start21': ,\n", + " 'start22': ,\n", + " 'stop11': ,\n", + " 'stop12': ,\n", + " 'stop21': ,\n", + " 'stop22': ,\n", + " 'timeout': ,\n", + " 'trace11': ,\n", + " 'trace12': ,\n", + " 'trace21': ,\n", + " 'trace22': }" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "v1.trace()" + "v1.parameters" ] }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true - }, - "outputs": [], + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "([0.994883080464622,\n", + " 0.9931391040095283,\n", + " 0.996905045122227,\n", + " 0.9786384133401488,\n", + " 1.0027617818162764,\n", + " 1.0310496085724696,\n", + " 0.9925515317235981,\n", + " 1.0108186310605263,\n", + " 0.9925872120523569,\n", + " 0.9926692143467003],\n", + " [0.05036939097186489,\n", + " 0.01764821060448947,\n", + " 0.011866393565832002,\n", + " 0.019511389866488284,\n", + " 0.01837896283827168,\n", + " 0.023404214898075926,\n", + " 0.00574883490212149,\n", + " -0.013211149195320264,\n", + " 0.0023023030330283785,\n", + " 0.011257041625421755])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "v1.start(10e6)\n", - "v1.stop(800e6)\n", - "v1.avg(2)\n", - "v1.npts(100)" + "v1.trace11()" ] }, { "cell_type": "code", "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "v1.start11(10e6)\n", + "v1.stop11(800e6)\n", + "v1.avg11(2)\n", + "v1.npts12(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, "metadata": { "scrolled": false }, @@ -133,25 +214,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "Started at 2017-05-19 10:47:47\n", + "Started at 2017-05-19 14:21:38\n", "DataSet:\n", - " location = 'data/2017-05-19/#001_{name}_10-47-47'\n", - " | | | \n", - " Setpoint | VNA_power_set | power | (14,)\n", - " Setpoint | frequency_set | frequency | (14, 100)\n", - " Measured | VNA_magnitude | magnitude | (14, 100)\n", - " Measured | VNA_phase | phase | (14, 100)\n", - "Finished at 2017-05-19 10:47:48\n" + " location = 'data/2017-05-19/#006_{name}_14-21-38'\n", + " | | | \n", + " Setpoint | VNA_power11_set | power11 | (15,)\n", + " Setpoint | frequency_set | frequency | (15, 10)\n", + " Measured | VNA_magnitude | magnitude | (15, 10)\n", + " Measured | VNA_phase | phase | (15, 10)\n", + "Finished at 2017-05-19 14:21:38\n" ] } ], "source": [ - "data1 = qc.Loop(v1.power[-15:-1:1]).each(v1.trace).run()" + "data1 = qc.Loop(v1.power11.sweep(-15,-1,1)).each(v1.trace11).run()" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "scrolled": false }, @@ -936,7 +1017,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -948,10 +1029,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -962,7 +1043,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -1745,7 +1826,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1757,10 +1838,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -1771,25 +1852,24 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\nDps2bRKRX3/9dfr06TExMT169Dh//nxWVlZ2dvb999/v7A46x5UWgrRxo8I9LS3Ndmf+/Pne3t4P\nPvhg06ZNt23b9tlnn40YMaIeuneBMXTcnJW/Ky6yiIiY/H3ZNhUAAKAOfPrppx07duzZs6ft4aBB\ng7Zv3/71119HRUU5t2POYhtrd8iNVpUJDAwUkd27dx8+fPitt96yhW3atCktLV29enX91u4iRl9/\nCnYAAIA6dPjw4aZNm1ZOrFbrwYMHndUf54qIiNBXgbzA6kYbMNns3bu3WbNmlZNmzZrt3bu3bnoE\nAACAhtKjR4/FixdnZWWdPHmyuLg4IyMjKyvrzjvvdHa/XEL1M2caVm0minfq1GnWrFkbNmzo06eP\niPz0008LFy4cOXJkHXcNAAAA9axbt26TJk169913baPsISEh06dPv/XWW53dL+ewX5ZqM22a+68q\n07p165deemn27Nl//vOfmzRpcvr06UcfffShhx6q884BAACgvkVHR0dHR1sslsaNG9fdlprXKTea\n427Xp0+f++67r7Cw8PTp023atPHy8qrbbgEAAKAhmUwVS21/9NFHQUFBvXv3dm5/nGXo0Cten+pG\nI+5HjhwJCAiw3W/SpElwcHDlr5aWlp4+fbply5Z11jsAAADUp/T09MWLF1dOjh49+vbbbzurP84V\nERGRl5d3pdrdjQr3jRs3bt26dfDgwd27d7dfn3rmzJl9+/atWrXq888//8tf/kLhDgAA4C7uu+++\n22+/3XbfarXu3Llzz549YWFhzu2Vs9ivRnVYu7vRVJlHH330zjvvfPfdd1955RU/P79mzZqVlJQc\nO3bMy8urb9++77777g17KQMAAIA7uvnmm2+++Wb7Q7PZPGvWrM2bN9+YezBFXLJXal5eXt6liZOX\ng7zqOe4hISGzZs0qLS3dvXv3iRMnPD09/f39Q0JCGjWqzcqSAAAAcCmNGzcuLS11di+cyTbunp6u\nrSrjVLW8ONXb2/uOO+6o264AAACggRUUFOzYscP+sLCw8P/+7/9CQkI++eSTW2+9tXv37k7sm7Nc\nGGVXRtzdaY47AAAArif/+c9/vvzyy8pJeHh4Tk6OiJw5c+bGLNyvNOLuXlNlAAAAcN3o27dv3759\nnd0L1+KyI+5MTAcAALgRff3111arXoeeP39+8+bNJ0+ebOAuOV1eJenpcnnVLiLWGt/qQW1G3L/6\n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\n3DtPnAgbOdKbJQMf3Nvf3V5dbRozRkSOyURdanKspyVtLdUp2RVRaQWrUg3KBcjrAAAAEB8m9V58\nG9w7OzuPHz+1d++I66/3ZvHAB3dD6uNbU8+9mKNt213LSqKSCzYsT/D/QQEAAOA85uFZSx7nkPE2\n0/suuH9jsTjefffIwoWj77//vAnunp0489LS+OCCAqtE3T9rXFNj46lTpy6KvMI4OSJwxwYAAIDz\njDLNe3tbqpMvetw7v/rqG4vFcs89J7vbvL00fIO7ZvTlrte2A+82iYi0F2Uv6yqFp9dvXRqI4wIA\nAMD5yr2FZiingOw8eTJMo/kqL+/Y6tUDWH34Bnft5OT6+mTna51xaX09MR0AAAAD4crrg43pgxhx\n77TZjm/YYL333gFv4YKB7xwAAAA4H7iaZFwtMQPT+Y23X2etZbWeevvtw9OmDSa1y3AecQcAAAB8\npUeD+yC6Zfp5c2rnsWOdX39tWbLkxNat/VtTheAOAACAEKK6RdX3je/L7rtPTp+2FRTYfvvbwW6r\nG8EdAAAAIS0mJsbbp6h63eP+5O9+98Utt5zcsWNQR3Y2gjsAAABCmve3rnrfKfP9mTP3vPnmqb/9\nzbJo0Teffz7wg+uB4A4AAICQ5t7+7inBez+pzL59+y4YO3bkTTd96+OPv3766aM5OYM6RBFhVhkA\nAABAVFO8u+v0+qvLhReGjRo1+oEHIr/+etTChYM8QoI7AAAAQlpzc7OXPe79Du4iIhI2alTYqFHh\nTz01/v33L4qNHfBx0ioDAACA4OTNILq7lBSP2b2fs0GeJUyv1+j1l27ffvKNNyz33NNps/V3CwR3\nAAAABAllUh/83I4ug3hwapcL9PqRycmXffGF7be/teXn92tdgjsAAACCRM852l0h3vm0VJ/E98EH\ndxEJ02hERPfww2NWrLBmZHi/IsEdAAAAQaKP3hhnfO+lv2l+MK0yvYSNGRMmEv7cc53Hj3u5CsFd\nbV9/Fm7dqyi+9rCi+MsGRdFWpigmethX51eK4tZLFMWwcMXp+YMm9en5wzH/2714+Jb/516syVas\nrldt85vDZuW+rtl/pXvxdOuH7kXNFbPdi9/98RvKzY6YrijGZyrO8OO1Dvfihaqt7tuv3JVs/Iui\n+GXG1+7FB1Wrr/+eopi1VL2v4ocUxdNtiuKyXyuKz9SqN3tip6KoOhPln9sUxetK3J85Jw+4PXbO\n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\ngjsAAABwHvj/flOHmmUdY54AAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "qc.QtPlot(data1.VNA_magnitude)" ] }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "v1.close()" + ] + }, { "cell_type": "code", "execution_count": null, From 1c64fec35d582991acfc4aca069e51a8f354beac Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 19 May 2017 16:43:44 +0200 Subject: [PATCH 09/19] Add autosacle and display to vna --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index bba45fed4516..a977a503e4e0 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -152,13 +152,20 @@ def __init__(self, name, address, **kwargs): self.add_function('update_display_once', call_cmd='SYST:DISP:UPD ONCE') self.add_function('update_display_on', call_cmd='SYST:DISP:UPD ON') self.add_function('update_display_off', call_cmd='SYST:DISP:UPD OFF') + self.add_function('display_sij_split', call_cmd='DISP:LAY GRID;:DISP:LAY:GRID 2,2') self.add_function('rf_off', call_cmd='OUTP1 OFF') self.add_function('rf_on', call_cmd='OUTP1 ON') self.initialise() self._setup_s_channels() + self.autoscale_all() self.connect_message() + + def autoscale_all(self): + for i in range(1,5): + self.write('DISPlay:TRACe1:Y:SCALe:AUTO ONCE, "Trc{}"'.format(i)) + def _setup_s_channels(self): """ Sets up 4 channels with a single trace in each. From 9b4da91a9dab8bcded0c0099e086fe2601dd75da Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 22 May 2017 17:20:53 +0200 Subject: [PATCH 10/19] Add validators for freq settings --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index a977a503e4e0..9eefacc5604e 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -89,6 +89,8 @@ def __init__(self, name, address, **kwargs): n = 1 self._sindex_to_channel = {} self._channel_to_sindex = {} + self._max_freq = 20e9 + self._min_freq = 100e3 for i in range(1,3): self._sindex_to_channel[i] = {} for j in range(1,3): @@ -116,19 +118,23 @@ def __init__(self, name, address, **kwargs): self.add_parameter(name='start{}{}'.format(i ,j), get_cmd='SENS{}:FREQ:START?'.format(n), set_cmd=partial(self._set_start, channel=n), - get_parser=float) + get_parser=float, + vals=vals.Numbers(self._min_freq, self._max_freq-10)) self.add_parameter(name='stop{}{}'.format(i ,j), get_cmd='SENS{}:FREQ:STOP?'.format(n), set_cmd=partial(self._set_stop, channel=n), - get_parser=float) + get_parser=float, + vals = vals.Numbers(self._min_freq+1, self._max_freq)) self.add_parameter(name='center{}{}'.format(i ,j), get_cmd='SENS{}:FREQ:CENT?'.format(n), set_cmd=partial(self._set_center, channel=n), - get_parser=float) + get_parser=float, + vals=vals.Numbers(self._min_freq + 0.5, self._max_freq-10)) self.add_parameter(name='span{}{}'.format(i ,j), get_cmd = 'SENS{}:FREQ:SPAN?'.format(n), set_cmd=partial(self._set_span, channel=n), - get_parser=float) + get_parser=float, + vals = vals.Numbers(1, self._max_freq - self._min_freq)) self.add_parameter(name='npts{}{}'.format(i ,j), get_cmd='SENS:SWE:POIN?', set_cmd=partial(self._set_npts, channel=n), @@ -153,6 +159,7 @@ def __init__(self, name, address, **kwargs): self.add_function('update_display_on', call_cmd='SYST:DISP:UPD ON') self.add_function('update_display_off', call_cmd='SYST:DISP:UPD OFF') self.add_function('display_sij_split', call_cmd='DISP:LAY GRID;:DISP:LAY:GRID 2,2') + self.add_function('display_sij_overlay', call_cmd='DISP:LAY GRID;:DISP:LAY:GRID 1,1') self.add_function('rf_off', call_cmd='OUTP1 OFF') self.add_function('rf_on', call_cmd='OUTP1 ON') From 9ae7b80a80b3258b2695ecc91053254ba613bf00 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 22 May 2017 17:21:16 +0200 Subject: [PATCH 11/19] Init for all channels --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 9eefacc5604e..3cebd09eb514 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -238,9 +238,10 @@ def _set_default_values(self): def initialise(self): self.write('*RST') - self.write('SENS1:SWE:TYPE LIN') - self.write('SENS1:SWE:TIME:AUTO ON') - self.write('TRIG1:SEQ:SOUR IMM') - self.write('SENS1:AVER:STAT ON') + for n in range(1,5): + self.write('SENS{}:SWE:TYPE LIN'.format(n)) + self.write('SENS{}:SWE:TIME:AUTO ON'.format(n)) + self.write('TRIG{}:SEQ:SOUR IMM'.format(n)) + self.write('SENS{}:AVER:STAT ON'.format(n)) self.update_display_on() self._set_default_values() \ No newline at end of file From dca18ce441123e258968b3ad448372f195910600 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Tue, 23 May 2017 11:37:07 +0200 Subject: [PATCH 12/19] Ensure that start= stop: + raise ValueError("Stop frequency must be larger than start frequency.") + # we get start as the vna may not be able to set it to the exact value provided + start = getattr(self, 'start{}{}'.format(i, j))() # update setpoints for FrequencySweep param - trace.set_sweep(val, stop, npts) + trace.set_sweep(start, stop, npts) def _set_stop(self, val, channel): - self.write('SENS{}:FREQ:STOP {:.4f}'.format(channel, val)) i, j = self._channel_to_sindex[channel] start = getattr(self, 'start{}{}'.format(i, j))() npts = getattr(self, 'npts{}{}'.format(i, j))() trace = getattr(self, 'trace{}{}'.format(i, j)) + if val <= start: + raise ValueError("Stop frequency must be larger than start frequency.") + self.write('SENS{}:FREQ:STOP {:.4f}'.format(channel, val)) + # we get stop as the vna may not be able to set it to the exact value provided + stop = getattr(self, 'stop{}{}'.format(i, j))() # update setpoints for FrequencySweep param - trace.set_sweep(start, val, npts) + trace.set_sweep(start, stop, npts) def _set_npts(self, val, channel): self.write('SENS{}:SWE:POIN {:.4f}'.format(channel, val)) From 8a529cb56557defd98513f618218f30da9639fc0 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Tue, 23 May 2017 12:57:44 +0200 Subject: [PATCH 13/19] Add warnings if start and stop cannot be set exactly --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 5c34a0e72966..00771fbcbf29 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -1,4 +1,5 @@ from functools import partial +import logging from qcodes import VisaInstrument from qcodes.utils import validators as vals @@ -6,6 +7,7 @@ import numpy as np from qcodes import MultiParameter, Parameter +log = logging.getLogger(__name__) class FrequencySweep(MultiParameter): """ @@ -193,6 +195,8 @@ def _set_start(self, val, channel): raise ValueError("Stop frequency must be larger than start frequency.") # we get start as the vna may not be able to set it to the exact value provided start = getattr(self, 'start{}{}'.format(i, j))() + if val != start: + log.warning("Could not set start to {} setting it to {}".format(val, start)) # update setpoints for FrequencySweep param trace.set_sweep(start, stop, npts) @@ -206,6 +210,8 @@ def _set_stop(self, val, channel): self.write('SENS{}:FREQ:STOP {:.4f}'.format(channel, val)) # we get stop as the vna may not be able to set it to the exact value provided stop = getattr(self, 'stop{}{}'.format(i, j))() + if val != stop: + log.warning("Could not set stop to {} setting it to {}".format(val, stop)) # update setpoints for FrequencySweep param trace.set_sweep(start, stop, npts) From 4a68546cea4e06d507a1fe644c052e03d7a635f3 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 24 May 2017 10:02:11 +0200 Subject: [PATCH 14/19] Znb20 small improvements --- .../instrument_drivers/rohde_schwarz/ZNB20.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 00771fbcbf29..311cd422c828 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -28,11 +28,8 @@ class FrequencySweep(MultiParameter): setpoint arrays of the parameter to correspond with the sweep get(): executes a sweep and returns magnitude and phase arrays - get_ramping: Queries the value of self.ramp_state and - self.ramp_time. Returns a string. - TODO: - - ability to choose for abs or db in magnitude return + - ability to choose for linear or db in magnitude return """ def __init__(self, name, instrument, start, stop, npts, channel, sindex): super().__init__(name, names=("", ""), shapes=((), ())) @@ -40,8 +37,10 @@ def __init__(self, name, instrument, start, stop, npts, channel, sindex): self.set_sweep(start, stop, npts) self._channel = channel self._sindex = sindex - self.names = ('magnitude', 'phase') - self.units = ('dBm', 'rad') + sname = 's' + str(sindex[0]) + str(sindex[1]) + self.names = ('{}_magnitude'.format(sname) , '{}_phase'.format(sname)) + self.labels = ('{} magnitude'.format(sname), '{} phase'.format(sname)) + self.units = ('', 'rad') self.setpoint_units = (('Hz',), ('Hz',)) self.setpoint_names = (('frequency',), ('frequency',)) @@ -53,6 +52,8 @@ def set_sweep(self, start, stop, npts): self.shapes = ((npts,), (npts,)) def get(self): + if not self._instrument.rf_power(): + log.warning("RF output is off") self._instrument.write('SENS{}:AVER:STAT ON'.format(self._channel)) self._instrument.write('SENS{}:AVER:CLE'.format(self._channel)) self._instrument.cont_meas_off() @@ -151,6 +152,10 @@ def __init__(self, name, address, **kwargs): self._sindex_to_channel[i][j] = n self._channel_to_sindex[n] = (i, j) n += 1 + self.add_parameter(name='rf_power', + get_cmd='OUTP1?', + set_cmd='OUTP1 {}', + val_mapping={True: '1\n', False: '0\n'}) self.add_function('reset', call_cmd='*RST') self.add_function('tooltip_on', call_cmd='SYST:ERR:DISP ON') From d39402082515c2b81a7c1160d777f3dd4a6c59ae Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 24 May 2017 10:03:20 +0200 Subject: [PATCH 15/19] Update Znb20 notebook --- ...odes example with Rohde Schwarz ZN20.ipynb | 1904 ------------ ...es example with Rohde Schwarz ZNB 20.ipynb | 2741 +++++++++++++++++ 2 files changed, 2741 insertions(+), 1904 deletions(-) delete mode 100644 docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb create mode 100644 docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZNB 20.ipynb diff --git a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb deleted file mode 100644 index c7fa050429ac..000000000000 --- a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZN20.ipynb +++ /dev/null @@ -1,1904 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Qcodes example with Rohde Schwarz ZN20" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "%matplotlib nbagg\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from imp import reload\n", - "import qcodes as qc\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import qcodes.instrument_drivers.rohde_schwarz.ZNB20 as vna; reload(vna)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "2\n", - "3\n", - "4\n", - "Connected to: Rohde-Schwarz ZNB20-2Port (serial:1311601062101551, firmware:2.10) in 0.23s\n" - ] - } - ], - "source": [ - "# v1 =vna.ZNB20('VNA', 'TCPIP0::172.20.2.234::inst0::INSTR', server_name=None)\n", - "v1 =vna.ZNB20('VNA', 'TCPIP0::192.168.15.100::inst0::INSTR', server_name=None)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"'Trc4,S22'\\n\"" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v1.ask('CALC4:PAR:CAT?')" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "station = qc.Station(v1)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'IDN': ,\n", - " 'avg11': ,\n", - " 'avg12': ,\n", - " 'avg21': ,\n", - " 'avg22': ,\n", - " 'bandwidth11': ,\n", - " 'bandwidth12': ,\n", - " 'bandwidth21': ,\n", - " 'bandwidth22': ,\n", - " 'center11': ,\n", - " 'center12': ,\n", - " 'center21': ,\n", - " 'center22': ,\n", - " 'npts11': ,\n", - " 'npts12': ,\n", - " 'npts21': ,\n", - " 'npts22': ,\n", - " 'power11': ,\n", - " 'power12': ,\n", - " 'power21': ,\n", - " 'power22': ,\n", - " 'span11': ,\n", - " 'span12': ,\n", - " 'span21': ,\n", - " 'span22': ,\n", - " 'start11': ,\n", - " 'start12': ,\n", - " 'start21': ,\n", - " 'start22': ,\n", - " 'stop11': ,\n", - " 'stop12': ,\n", - " 'stop21': ,\n", - " 'stop22': ,\n", - " 'timeout': ,\n", - " 'trace11': ,\n", - " 'trace12': ,\n", - " 'trace21': ,\n", - " 'trace22': }" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v1.parameters" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "([0.994883080464622,\n", - " 0.9931391040095283,\n", - " 0.996905045122227,\n", - " 0.9786384133401488,\n", - " 1.0027617818162764,\n", - " 1.0310496085724696,\n", - " 0.9925515317235981,\n", - " 1.0108186310605263,\n", - " 0.9925872120523569,\n", - " 0.9926692143467003],\n", - " [0.05036939097186489,\n", - " 0.01764821060448947,\n", - " 0.011866393565832002,\n", - " 0.019511389866488284,\n", - " 0.01837896283827168,\n", - " 0.023404214898075926,\n", - " 0.00574883490212149,\n", - " -0.013211149195320264,\n", - " 0.0023023030330283785,\n", - " 0.011257041625421755])" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v1.trace11()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "v1.start11(10e6)\n", - "v1.stop11(800e6)\n", - "v1.avg11(2)\n", - "v1.npts12(100)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Started at 2017-05-19 14:21:38\n", - "DataSet:\n", - " location = 'data/2017-05-19/#006_{name}_14-21-38'\n", - " | | | \n", - " Setpoint | VNA_power11_set | power11 | (15,)\n", - " Setpoint | frequency_set | frequency | (15, 10)\n", - " Measured | VNA_magnitude | magnitude | (15, 10)\n", - " Measured | VNA_phase | phase | (15, 10)\n", - "Finished at 2017-05-19 14:21:38\n" - ] - } - ], - "source": [ - "data1 = qc.Loop(v1.power11.sweep(-15,-1,1)).each(v1.trace11).run()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\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", - " if (mpl.ratio != 1) {\n", - " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", - " }\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 backingStore = this.context.backingStorePixelRatio ||\n", - "\tthis.context.webkitBackingStorePixelRatio ||\n", - "\tthis.context.mozBackingStorePixelRatio ||\n", - "\tthis.context.msBackingStorePixelRatio ||\n", - "\tthis.context.oBackingStorePixelRatio ||\n", - "\tthis.context.backingStorePixelRatio || 1;\n", - "\n", - " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n", - " canvas.attr('height', height * mpl.ratio);\n", - " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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.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" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "qc.MatPlot(data1.VNA_magnitude)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "qc.QtPlot(data1.VNA_magnitude)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "v1.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.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZNB 20.ipynb b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZNB 20.ipynb new file mode 100644 index 000000000000..77e040d78557 --- /dev/null +++ b/docs/examples/driver_examples/Qcodes example with Rohde Schwarz ZNB 20.ipynb @@ -0,0 +1,2741 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Qcodes example with Rohde Schwarz ZN20" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%matplotlib nbagg\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import qcodes as qc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import qcodes.instrument_drivers.rohde_schwarz.ZNB20 as vna" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Connected to: Rohde-Schwarz ZNB20-2Port (serial:1311601062101551, firmware:2.82) in 0.28s\n" + ] + } + ], + "source": [ + "vna = vna.ZNB20('VNA', 'TCPIP0::192.168.15.100::inst0::INSTR', server_name=None)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "station = qc.Station(vna)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The QCoDes driver for the Rohde Schwarz ZNB 20 is setup with 4 channels each containing one trace and reprecenting the 4 standars S parameters (S11, S12, S21 and S22). For each S parameter you can define a frequency sweep as and the power of the rf source i.e for s11 sweep from 100 KHz to 6 MHz in 100 steps:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "vna.start11(100e3)\n", + "vna.stop11(6e6)\n", + "vna.npts11(100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With a power of -30 dBm" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "vna.power11(-30)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can meassure a frequency trace, first remembering to turn on the rf source." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DataSet:\n", + " location = 'data/2017-05-24/#009_{name}_09-59-42'\n", + " | | | \n", + " Setpoint | frequency_set | frequency | (100,)\n", + " Measured | VNA_s11_magnitude | s11_magnitude | (100,)\n", + " Measured | VNA_s11_phase | s11_phase | (100,)\n", + "acquired at 2017-05-24 09:59:43\n" + ] + } + ], + "source": [ + "vna.rf_on()\n", + "data = qc.Measure(vna.trace11).run()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\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", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\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 backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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.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": [ + "data = qc.Measure(vna.trace11).run()\n", + "plot = qc.MatPlot(subplots=(1,2))\n", + "plot.add(data.VNA_s11_magnitude, subplot=1)\n", + "plot.add(data.VNA_s11_phase, subplot=2)\n", + "plot.fig.tight_layout(rect=(0, 0, 1, 0.95))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can display all 4 S parameters in a split view on the VNA display." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "vna.display_sij_split()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or we can display all 4 parameters in one view." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "vna.display_sij_overlay()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can autoscale the scale the y axis" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "vna.autoscale_all()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is possible to switch the display update on and off" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "vna.update_display_on()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "vna.update_display_off()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And switch the rf output on and off" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "vna.rf_on()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "vna.rf_off()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Doing a 2D sweep is supported too" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Started at 2017-05-24 09:59:47\n", + "DataSet:\n", + " location = 'data/2017-05-24/#011_{name}_09-59-47'\n", + " | | | \n", + " Setpoint | VNA_power11_set | power11 | (15,)\n", + " Setpoint | frequency_set | frequency | (15, 100)\n", + " Measured | VNA_s11_magnitude | s11_magnitude | (15, 100)\n", + " Measured | VNA_s11_phase | s11_phase | (15, 100)\n", + "Finished at 2017-05-24 09:59:49\n" + ] + } + ], + "source": [ + "vna.rf_on()\n", + "data1 = qc.Loop(vna.power11.sweep(-15,-1,1)).each(vna.trace11).run()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\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", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\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 backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\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 * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\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.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": [ + "data = qc.Measure(vna.trace11).run()\n", + "plot = qc.MatPlot(subplots=(1,2))\n", + "plot.add(data.VNA_s11_magnitude, subplot=1)\n", + "plot.add(data.VNA_s11_phase, subplot=2)\n", + "plot.fig.tight_layout(rect=(0, 0, 1, 0.95))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also measure the magniture in dB." + ] + }, + { + "cell_type": "code", + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -955,12 +1780,10 @@ "output_type": "stream", "text": [ "DataSet:\n", - " location = 'data/2017-05-24/#010_{name}_09-59-44'\n", - " | | | \n", - " Setpoint | frequency_set | frequency | (100,)\n", - " Measured | VNA_s11_magnitude | s11_magnitude | (100,)\n", - " Measured | VNA_s11_phase | s11_phase | (100,)\n", - "acquired at 2017-05-24 09:59:44\n" + " location = 'data/2017-05-24/#049_{name}_14-35-58'\n", + " | | | \n", + " Measured | VNA_tracedb11 | tracedb11 | (100,)\n", + "acquired at 2017-05-24 14:35:58\n" ] }, { @@ -1743,7 +2566,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1754,11 +2577,9 @@ } ], "source": [ - "data = qc.Measure(vna.trace11).run()\n", - "plot = qc.MatPlot(subplots=(1,2))\n", - "plot.add(data.VNA_s11_magnitude, subplot=1)\n", - "plot.add(data.VNA_s11_phase, subplot=2)\n", - "plot.fig.tight_layout(rect=(0, 0, 1, 0.95))" + "vna.rf_on()\n", + "data = qc.Measure(vna.tracedb11).run()\n", + "plot = qc.MatPlot(data.VNA_tracedb11)" ] }, { @@ -1770,7 +2591,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -1786,7 +2607,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -1802,7 +2623,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -1818,7 +2639,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -1827,7 +2648,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "collapsed": true }, @@ -1845,7 +2666,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -1854,7 +2675,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": { "collapsed": true }, @@ -1872,22 +2693,22 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Started at 2017-05-24 09:59:47\n", + "Started at 2017-05-24 14:36:07\n", "DataSet:\n", - " location = 'data/2017-05-24/#011_{name}_09-59-47'\n", + " location = 'data/2017-05-24/#050_{name}_14-36-07'\n", " | | | \n", " Setpoint | VNA_power11_set | power11 | (15,)\n", " Setpoint | frequency_set | frequency | (15, 100)\n", " Measured | VNA_s11_magnitude | s11_magnitude | (15, 100)\n", " Measured | VNA_s11_phase | s11_phase | (15, 100)\n", - "Finished at 2017-05-24 09:59:49\n" + "Finished at 2017-05-24 14:36:10\n" ] } ], @@ -1898,7 +2719,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -2681,7 +3502,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2698,15 +3519,6 @@ "plot.fig.tight_layout(rect=(0, 0, 1, 0.95))" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - }, { "cell_type": "code", "execution_count": null, From 9642a39af69beffde55960ec6225501ece51ee40 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 24 May 2017 14:38:48 +0200 Subject: [PATCH 18/19] Correct initial values --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 599bcc8120ee..828b079bc994 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -257,8 +257,8 @@ def __init__(self, name, address, **kwargs): self.add_function('rf_off', call_cmd='OUTP1 OFF') self.add_function('rf_on', call_cmd='OUTP1 ON') - self.initialise() self._setup_s_channels() + self.initialise() self.autoscale_all() self.connect_message() @@ -361,4 +361,6 @@ def initialise(self): self.write('TRIG{}:SEQ:SOUR IMM'.format(n)) self.write('SENS{}:AVER:STAT ON'.format(n)) self.update_display_on() - self._set_default_values() \ No newline at end of file + self._set_default_values() + self.rf_off() + self.display_sij_split() \ No newline at end of file From 3c8d5df128689f9e196d1ec66d63fd37bdd67a53 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Thu, 15 Jun 2017 10:50:34 +0200 Subject: [PATCH 19/19] docs: add params to znb docstrings --- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py index 828b079bc994..a98177594357 100644 --- a/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +++ b/qcodes/instrument_drivers/rohde_schwarz/ZNB20.py @@ -24,6 +24,8 @@ class FrequencySweepMagPhase(MultiParameter): start: starting frequency of sweep stop: ending frequency of sweep npts: number of points in frequency sweep + channel: channel number. This maps to a hardware channel on znb + sindex: (tuple of ints) Which s'parameter this corresponds to. Only used for labels Methods: set_sweep(start, stop, npts): sets the shapes and @@ -91,6 +93,8 @@ class FrequencySweep(ArrayParameter): start: starting frequency of sweep stop: ending frequency of sweep npts: number of points in frequency sweep + channel: channel number. This maps to a hardware channel on znb + sindex: (tuple of ints) Which s'parameter this corresponds to. Only used for labels Methods: set_sweep(start, stop, npts): sets the shapes and