diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index 8d56cff3c..da7ebdbdd 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -1,26 +1,48 @@ -name: Upload Python Package +name: Publish Python Package on: + workflow_dispatch: {} release: - types: [created] + types: [published] jobs: - deploy: + build: + if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'release' }} + name: Build release artifacts runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: '3.8' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install --upgrade build twine - - name: Build and publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python -m build - python -m twine upload dist/* + - name: Checkout code + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install build tool + run: python3 -m pip install --upgrade build + - name: Build wheel & sdist + run: python3 -m build + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: dist-files + path: dist/ + + test-publish: + if: ${{ github.event_name == 'workflow_dispatch' }} + needs: build + uses: ./.github/workflows/upload_to_repository.yml + with: + repository-url: https://test.pypi.org/legacy/ + secrets: + pypi-token: ${{ secrets.TEST_PYPI_API_TOKEN }} + + publish: + if: ${{ github.event_name == 'release' }} + needs: build + uses: ./.github/workflows/upload_to_repository.yml + with: + repository-url: https://upload.pypi.org/legacy/ + secrets: + pypi-token: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/pythontest.yaml b/.github/workflows/pythontest.yaml index cacee5647..a8d5ab833 100644 --- a/.github/workflows/pythontest.yaml +++ b/.github/workflows/pythontest.yaml @@ -11,10 +11,10 @@ on: - '**' paths: - 'qupulse/**y' - - 'qctoolkit/**' - 'tests/**' - 'setup.*' - 'pyproject.toml' + - '.github/workflows/*' jobs: test: @@ -22,35 +22,30 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9"] - time-type: ["fractions", "gmpy2"] + python-version: ["3.10", "3.11", "3.12"] + numpy-version: [">=1.24,<2.0", ">=2.0"] env: INSTALL_EXTRAS: tests,plotting,zurich-instruments,tektronix,tabor-instruments steps: - - name: Prepare gmpy2 build dependencies - if: ${{ matrix.time-type }} == 'gmpy2' - run: | - sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev - echo "INSTALL_EXTRAS=${{ env.INSTALL_EXTRAS }},Faster-fractions" >> $GITHUB_ENV - - name: Checkout repository uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - # supported since 2.3 cache: pip - cache-dependency-path: setup.cfg - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install coverage coveralls + - name: Install numpy ${{ matrix.numpy-version }} + run: python -m pip install "numpy${{ matrix.numpy-version }}" + - name: Install package run: | python -m pip install .[${{ env.INSTALL_EXTRAS }}] @@ -59,18 +54,31 @@ jobs: run: | coverage run -m pytest --junit-xml pytest.xml + - name: Generate valid name + run: | + numpy_version="${{ matrix.numpy-version }}" + if [[ $numpy_version == *"<2"* ]]; then + numpy_version="1" + else + numpy_version="2" + fi + MATRIX_NAME="python-${{ matrix.python-version }}-numpy-"$numpy_version + echo "MATRIX_NAME=$MATRIX_NAME" >> $GITHUB_ENV + - name: Upload coverage data to coveralls.io run: coveralls --service=github env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_FLAG_NAME: python-${{ matrix.python-version }}-${{ matrix.time-type }} + COVERALLS_FLAG_NAME: ${{ env.MATRIX_NAME }} COVERALLS_PARALLEL: true + # this step can fail + continue-on-error: true - name: Upload Test Results if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: Unit Test Results ( ${{ matrix.python-version }}-${{ matrix.time-type }} ) + name: Unit Test Results ( ${{ env.MATRIX_NAME }} ) path: | pytest.xml @@ -86,13 +94,15 @@ jobs: coveralls --service=github --finish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # this step can fail + continue-on-error: true event_file: name: "Event File" runs-on: ubuntu-latest steps: - name: Upload - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Event File path: ${{ github.event_path }} diff --git a/.github/workflows/upload_to_repository.yml b/.github/workflows/upload_to_repository.yml new file mode 100644 index 000000000..d774d6c66 --- /dev/null +++ b/.github/workflows/upload_to_repository.yml @@ -0,0 +1,31 @@ +name: Upload artifacts + +on: + workflow_call: + inputs: + repository-url: + required: true + type: string + secrets: + pypi-token: + required: true + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: dist-files + path: dist/ + - name: Install Twine + run: python3 -m pip install --upgrade twine + - name: Upload + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.pypi-token }} + run: python -m twine upload --repository-url ${{ inputs.repository-url }} dist/* diff --git a/.gitignore b/.gitignore index 7124aaa3e..d7536efc2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,8 @@ dist/* doc/source/examples/.ipynb_checkpoints/* **.asv *.orig -MATLAB/+qc/personalPaths.mat /doc/source/_autosummary/* .idea/ .mypy_cache/* tests/hardware/WX2184C.exe +.vscode/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index df66b4e0b..000000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -language: python -python: - - 3.7 - - 3.8 -env: - - INSTALL_EXTRAS=[plotting,zurich-instruments,tektronix,tabor-instruments] - - INSTALL_EXTRAS=[plotting,zurich-instruments,tektronix,tabor-instruments,Faster-fractions,faster-sampling] - -#use container based infrastructure -sudo: false - -#these directories are persistent -cache: pip - -# install dependencies for gmpy2 -addons: - apt: - update: true - - sources: - # newer compiler for zhinst - - ubuntu-toolchain-r-test - - packages: - - libgmp-dev - - libmpfr-dev - - libmpc-dev - -before_install: - - eval "CC=gcc-8 && GXX=g++-8" - - pip install coverage coveralls -install: - - pip install .$INSTALL_EXTRAS -script: - - "coverage run --source=qupulse --rcfile=coverage.ini setup.py test" -after_success: - - coveralls - -notifications: - email: false diff --git a/.zenodo.json b/.zenodo.json new file mode 100644 index 000000000..69d6c7d28 --- /dev/null +++ b/.zenodo.json @@ -0,0 +1,74 @@ +{ + "creators": [ + { + "orcid": "0000-0002-9399-1055", + "affiliation": "RWTH Aachen University", + "name": "Humpohl, Simon" + }, + { + "orcid": "0000-0001-8678-961X", + "affiliation": "RWTH Aachen University", + "name": "Prediger, Lukas" + }, + { + "orcid": "0000-0002-8227-4018", + "affiliation": "RWTH Aachen University", + "name": "Cerfontaine, Pascal" + }, + { + "affiliation": "Forschungszentrum Jülich", + "name": "Papajewski, Benjamin" + }, + { + "orcid": "0000-0001-9927-3102", + "affiliation": "RWTH Aachen University", + "name": "Bethke, Patrick" + }, + { + "orcid": "0000-0003-2057-9913", + "affiliation": "Forschungszentrum Jülich", + "name": "Lankes, Lukas" + }, + { + "orcid": "0009-0006-9702-2979", + "affiliation": "Forschungszentrum Jülich", + "name": "Willmes, Alexander" + }, + { + "orcid": "0009-0000-3779-4711", + "affiliation": "Forschungszentrum Jülich", + "name": "Kammerloher, Eugen" + } + ], + + "contributors": [ + { + "orcid": "0000-0001-7018-1124", + "affiliation": "Netherlands Organisation for Applied Scientific Research TNO", + "name": "Eendebak, Pieter Thijs" + }, + { + "name": "Kreutz, Maike", + "affiliation": "RWTH Aachen University" + }, + { + "name": "Xue, Ran", + "affiliation": "RWTH Aachen University", + "orcid": "0000-0002-2009-6279" + } + ], + + "related_identifiers": [ + { + "identifier": "2128/24264", + "relation": "isDocumentedBy", + "resource_type": "publication-thesis" + } + ], + + "license": "GPL-3.0-or-later", + + "title": "qupulse: A Quantum compUting PULse parametrization and SEquencing framework", + + "keywords": ["quantum computing", "control pulse"] +} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a0b058a8e..000000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Quantum Technology Group and Chair of Software Engineering, RWTH Aachen University - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/LICENSES/LGPL-3.0-or-later.txt b/LICENSES/LGPL-3.0-or-later.txt new file mode 100644 index 000000000..65c5ca88a --- /dev/null +++ b/LICENSES/LGPL-3.0-or-later.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/MATLAB/+qc/AWGwatch.m b/MATLAB/+qc/AWGwatch.m deleted file mode 100644 index 79e7a80db..000000000 --- a/MATLAB/+qc/AWGwatch.m +++ /dev/null @@ -1,21 +0,0 @@ -function AWGwatch() -% starts a matlab (vers 2018a) app to DISPLAY SEQUENCER TABLES AND -% WAFEFORMS in qctoolkit and on the Tabor AWG simulatar -% ------------------------------------------------------------------------- -% - to edit the app open awgdisp_app.mlapp in the Matlab app designer -% - user preferences can be edited in the app private properties directly -% at the top in awgdisp_app.mlapp -% ------------------------------------------------------------------------- -% App written by Marcel Meyer 08|2018 marcel.meyer1@rwth-aachen.de - - disp('AWGwatch - app is started'); - - % the app is not on path +qc because then one has problems debugging it - pathOfApp = which('qc.AWGwatch'); - pathOfApp = pathOfApp(1:end-10); - pathOfApp = [pathOfApp 'AWGwatch\']; - addpath(pathOfApp); - - awgdisp_app(); - -end \ No newline at end of file diff --git a/MATLAB/+qc/AWGwatch/awgdisp_app.mlapp b/MATLAB/+qc/AWGwatch/awgdisp_app.mlapp deleted file mode 100644 index 25de9342c..000000000 Binary files a/MATLAB/+qc/AWGwatch/awgdisp_app.mlapp and /dev/null differ diff --git a/MATLAB/+qc/add_params_to_dict.m b/MATLAB/+qc/add_params_to_dict.m deleted file mode 100644 index 64d15b5c5..000000000 --- a/MATLAB/+qc/add_params_to_dict.m +++ /dev/null @@ -1,26 +0,0 @@ -function d = add_params_to_dict(d, parameters, pulse_name) - - if nargin < 3 - pulse_name= []; - end - - delim = '___'; - - fn = fieldnames(parameters)'; - - if ~isempty(fn) && util.str_contains(fn{1}, delim) - [parameters, extracted_pulse_name] = qc.params_rm_delim(parameters); - - if isempty(pulse_name) - pulse_name = extracted_pulse_name; - end - end - - if isempty(pulse_name) - error('Pulse name must not be empty'); - end - - d = qc.load_dict(d); - d.(pulse_name) = parameters; - - diff --git a/MATLAB/+qc/array2list.m b/MATLAB/+qc/array2list.m deleted file mode 100644 index 9865457fb..000000000 --- a/MATLAB/+qc/array2list.m +++ /dev/null @@ -1,9 +0,0 @@ -function sOut = array2list(sIn) - if isstruct(sIn) - sOut = structfun(@qc.array2list, sIn, 'UniformOutput', false); - elseif isnumeric(sIn) && ~isscalar(sIn) - sOut = py.list(sIn(:).'); - else - sOut = sIn; - end -end \ No newline at end of file diff --git a/MATLAB/+qc/array2row.m b/MATLAB/+qc/array2row.m deleted file mode 100644 index f82e19a7d..000000000 --- a/MATLAB/+qc/array2row.m +++ /dev/null @@ -1,9 +0,0 @@ -function sOut = array2row(sIn) - if isstruct(sIn) - sOut = structfun(@qc.array2row, sIn, 'UniformOutput', false); - elseif isnumeric(sIn) && ~isscalar(sIn) - sOut = sIn(:).'; - else - sOut = sIn; - end -end \ No newline at end of file diff --git a/MATLAB/+qc/awg_program.m b/MATLAB/+qc/awg_program.m deleted file mode 100644 index 91b06086c..000000000 --- a/MATLAB/+qc/awg_program.m +++ /dev/null @@ -1,320 +0,0 @@ -function [program, bool, msg] = awg_program(ctrl, varargin) - % pulse_template can also be a pulse name. In that case the pulse is - % automatically loaded. - - global plsdata - hws = plsdata.awg.hardwareSetup; - daq = plsdata.daq.inst; - - program = struct(); - msg = ''; - bool = false; - - default_args = struct(... - 'program_name', 'default_program', ... - 'pulse_template', 'default_pulse', ... - 'parameters_and_dicts', {plsdata.awg.defaultParametersAndDicts}, ... - 'channel_mapping', plsdata.awg.defaultChannelMapping, ... - 'window_mapping', plsdata.awg.defaultWindowMapping, ... - 'global_transformation', plsdata.awg.globalTransformation, ... - 'add_marker', {plsdata.awg.defaultAddMarker}, ... - 'force_update', false, ... - 'verbosity', 10 ... - ); - a = util.parse_varargin(varargin, default_args); - - % --- add --------------------------------------------------------------- - if strcmp(ctrl, 'add') - [~, bool, msg] = qc.awg_program('fresh', qc.change_field(a, 'verbosity', 0)); - if ~bool || a.force_update - plsdata.awg.currentProgam = ''; - - % Deleting old program should not be necessary. In practice however, - % updating an existing program seemed to crash Matlab sometimes. - % qc.awg_program('remove', qc.change_field(a, 'verbosity', 10)); - - a.pulse_template = pulse_to_python(a.pulse_template); - [a.pulse_template, a.channel_mapping] = add_marker_if_not_empty(a.pulse_template, a.add_marker, a.channel_mapping); - - program = qc.program_to_struct(a.program_name, a.pulse_template, a.parameters_and_dicts, a.channel_mapping, a.window_mapping, a.global_transformation); - plsdata.awg.registeredPrograms.(a.program_name) = program; - - % Save AWG amplitude at instantiation and upload time so that the - % amplitude at the sample can be reconstructed at a later time - if ~isfield(plsdata.awg.registeredPrograms.(a.program_name), 'amplitudes_at_upload') - % program not online yet - plsdata.awg.registeredPrograms.(a.program_name).amplitudes_at_upload = zeros(1, 4); - end - - for ii = int64(1:4) - % query actual amplitude from qupulse - plsdata.awg.registeredPrograms.(a.program_name).amplitudes_at_upload(ii) = plsdata.awg.inst.amplitude(ii); - end - - if a.verbosity > 9 - fprintf('Program ''%s'' is now being instantiated...', a.program_name); - tic; - end - instantiated_pulse = qc.instantiate_pulse(a.pulse_template, 'parameters', qc.join_params_and_dicts(program.parameters_and_dicts), 'channel_mapping', program.channel_mapping, 'window_mapping', program.window_mapping, 'global_transformation', program.global_transformation); - - if a.verbosity > 9 - fprintf('took %.0fs\n', toc); - fprintf('Program ''%s'' is now being uploaded...', a.program_name); - tic - end - util.py.call_with_interrupt_check(py.getattr(hws, 'register_program'), program.program_name, instantiated_pulse, pyargs('update', py.True)); - - if a.verbosity > 9 - fprintf('took %.0fs\n', toc); - end - - if bool && a.force_update - msg = ' since update forced'; - else - msg = ''; - end - msg = sprintf('Program ''%s'' added%s', a.program_name, msg); - - bool = true; - else - program = plsdata.awg.registeredPrograms.(a.program_name); - end - - % --- arm --------------------------------------------------------------- - elseif strcmp(ctrl, 'arm') - % Call directly before trigger comes, otherwise you might encounter a - % trigger timeout. Also, call after daq_operations('add')! - [~, bool, msg] = qc.awg_program('present', qc.change_field(a, 'verbosity', 0)); - if bool - % Wait for AWG to stop playing pulse, otherwise this might lead to a - % trigger timeout since the DAQ is not necessarily configured for the - % whole pulse time and can return data before the AWG stops playing - % the pulse. - if ~isempty(plsdata.awg.currentProgam) - waitingTime = min(max(plsdata.awg.registeredPrograms.(plsdata.awg.currentProgam).pulse_duration + plsdata.awg.registeredPrograms.(plsdata.awg.currentProgam).added_to_pulse_duration - (now() - plsdata.awg.triggerStartTime)*24*60*60, 0), plsdata.awg.maxPulseWait); - if waitingTime == plsdata.awg.maxPulseWait - warning('Maximum waiting time ''plsdata.awg.maxPulseWait'' = %g s reached.\nIncrease if you experience problems with the data acquistion.', plsdata.awg.maxPulseWait); - end - pause(waitingTime); - % fprintf('Waited for %.3fs for pulse to complete\n', waitingTime); - end - - % No longer needed since bug has been fixed - % qc.workaround_4chan_program_errors(a); - - hws.arm_program(a.program_name); - - plsdata.awg.currentProgam = a.program_name; - bool = true; - msg = sprintf('Program ''%s'' armed', a.program_name); - end - - % --- arm --------------------------------------------------------------- - elseif strcmp(ctrl, 'arm global') - if ischar(plsdata.awg.armGlobalProgram) - globalProgram = plsdata.awg.armGlobalProgram; - elseif iscell(plsdata.awg.armGlobalProgram) - globalProgram = plsdata.awg.armGlobalProgram{1}; - plsdata.awg.armGlobalProgram = circshift(plsdata.awg.armGlobalProgram, -1); - else - globalProgram = a.program_name; - warning('Not using global program since plsdata.awg.armGlobalProgram must contain a char or a cell.'); - end - - % Set scan axis labels here if the global program armament is called by - % a prefn in smrun. Only for charge scans - if startsWith(globalProgram, 'charge_4chan') - f = figure(a.fig_id); - - % always query the rf channels being swept so that they can be logged - % by a metafn. - if startsWith(globalProgram, 'charge_4chan_d12') - idx = [1 2]; - chans = {'A' 'B'}; - elseif startsWith(globalProgram, 'charge_4chan_d23') - idx = [2 3]; - chans = {'B' 'C'}; - elseif startsWith(globalProgram, 'charge_4chan_d34') - idx = [4 3]; - chans = {'D' 'C'}; - elseif startsWith(globalProgram, 'charge_4chan_d14') - idx = [1 4]; - chans = {'A' 'D'}; - end - plsdata.awg.currentChannels = chans; - - % compare current AWG channel amplitudes to those at instantiation - % time - currentAmplitudes = plsdata.awg.currentAmplitudesHV; - uploadAmplitudes = plsdata.awg.registeredPrograms.(globalProgram).amplitudes_at_upload; - - updateRFchans = ~strcmp(globalProgram, a.program_name); - updateRFamps = ~all(currentAmplitudes == uploadAmplitudes); - - if updateRFchans || updateRFamps - - if updateRFamps - % Calculate amplitude at sample from the current amplitude, the - % amplitude at pulse instantiation time, and the pulse parameters - rng = [(plsdata.awg.registeredPrograms.(globalProgram).parameters_and_dicts{2}.charge_4chan___stop_x - ... - plsdata.awg.registeredPrograms.(globalProgram).parameters_and_dicts{2}.charge_4chan___start_x) ... - (plsdata.awg.registeredPrograms.(globalProgram).parameters_and_dicts{2}.charge_4chan___stop_y - ... - plsdata.awg.registeredPrograms.(globalProgram).parameters_and_dicts{2}.charge_4chan___start_y)]; - amps = currentAmplitudes(idx)./uploadAmplitudes(idx).*rng*1e3; - end - for ax = f.Children(2:2:end)' - % Don't use xlabel(), ylabel() to stop matlab from updating the rest of the figure - if updateRFchans - ax.XLabel.String(3) = chans{1}; - ax.YLabel.String(3) = chans{2}; - end - if updateRFamps - ax.XLabel.String(6:9) = sprintf('%.1f', amps(1)); - ax.YLabel.String(6:9) = sprintf('%.1f', amps(2)); - ax.XTick = 0:10:100; - ax.YTick = 0:10:100; - ax.XTickLabel = sprintfc('%.1f', linspace(-amps(1)/2, amps(1)/2, 11)); - ax.YTickLabel = sprintfc('%.1f', linspace(-amps(2)/2, amps(2)/2, 11)); - end - end - end - end -% This code outputs the wrong pulses and isn't even faster -% - Then why is it still here? - TH -% registered_programs = util.py.py2mat(py.getattr(hws,'_registered_programs')); -% program = registered_programs.(globalProgram); -% awgs_to_upload_to = program{4}; -% dacs_to_arm = program{5}; -% for awgToUploadTo = awgs_to_upload_to -% awgToUploadTo{1}.arm(globalProgram); -% end -% for dacToArm = dacs_to_arm -% dacToArm{1}.arm_program(plsdata.awg.currentProgam); -% end - - qc.awg_program('arm', 'program_name', globalProgram, 'verbosity', a.verbosity, 'arm_global_for_workaround_4chan_program_errors', []); - - % --- remove ------------------------------------------------------------ - elseif strcmp(ctrl, 'remove') - % Arm the idle program so the program to be remove is not active by - % any chance (should not be needed - please test more thorougly whether it is needed) - plsdata.awg.inst.channel_pair_AB.arm(py.None); - plsdata.awg.inst.channel_pair_CD.arm(py.None); - - [~, bool, msg] = qc.awg_program('present', qc.change_field(a, 'verbosity', 0)); - - if bool - bool = false; - - if isfield(plsdata.awg.registeredPrograms, a.program_name) - plsdata.awg.registeredPrograms = rmfield(plsdata.awg.registeredPrograms, a.program_name); - end - - try - hws.remove_program(a.program_name); - bool = true; - catch err - warning('The following error was encountered when running hardware_setup.remove_program.\nPlease debug AWG commands.\nThis might have to do with removing the current program.\n.Trying to recover by deleting operations.\n%s', err.getReport()); - qc.daq_operations('remove', 'program_name', a.program_name, 'verbosity', 10); - end - - msg = sprintf('Program ''%s'' removed', a.program_name); - end - - % --- clear all --------------------------------------------------------- - elseif strcmp(ctrl, 'clear all') % might take a long time - plsdata.awg.registeredPrograms = struct(); - program_names = fieldnames(util.py.py2mat(py.getattr(hws, '_registered_programs'))); - - bool = true; - for program_name = program_names.' - [~, boolNew] = qc.awg_program('remove', 'program_name', program_name{1}, 'verbosity', 10); - bool = bool & boolNew; - end - - if bool - msg = 'All programs cleared'; - else - msg = 'Error when trying to clear all progams'; - end - - % --- clear all fast ---------------------------------------------------- - elseif strcmp(ctrl, 'clear all fast') % fast but need to clear awg manually - hws.registered_programs.clear(); - py.getattr(daq, '_registered_programs').clear(); - - % --- present ----------------------------------------------------------- - elseif strcmp(ctrl, 'present') % returns true if program is present - bool = py.list(hws.registered_programs.keys()).count(a.program_name) ~= 0; - if bool - msg = ''; - else - msg = 'not '; - end - msg = sprintf('Program ''%s'' %spresent', a.program_name, msg); - - % --- fresh ------------------------------------------------------------- - elseif strcmp(ctrl, 'fresh') % returns true if program is present and has not changed - [~, bool, msg] = qc.awg_program('present', qc.change_field(a, 'verbosity', 0)); - - if isfield(plsdata.awg.registeredPrograms, a.program_name) && bool - a.pulse_template = pulse_to_python(a.pulse_template); - [a.pulse_template, a.channel_mapping] = add_marker_if_not_empty(a.pulse_template, a.add_marker, a.channel_mapping); - - newProgram = qc.program_to_struct(a.program_name, a.pulse_template, a.parameters_and_dicts, a.channel_mapping, a.window_mapping, a.global_transformation); - newProgram = qc.get_minimal_program(newProgram); - - awgProgram = plsdata.awg.registeredPrograms.(a.program_name); - awgProgram = qc.get_minimal_program(awgProgram); - - bool = isequal(newProgram, awgProgram); - - if bool - msg = ''; - else - msg = 'not '; - end - msg = sprintf('Program ''%s'' is %sup to date (fresh)', a.program_name, msg); - end - % if ~bool - % util.comparedata(newProgram, awgProgram); - % end - - end - - if a.verbosity > 9 - fprintf([msg '\n']); - end - - - - -function pulse_template = pulse_to_python(pulse_template) - - if ischar(pulse_template) - pulse_template = qc.load_pulse(pulse_template); - end - - if isstruct(pulse_template) - pulse_template = qc.struct_to_pulse(pulse_template); - end - - -function [pulse_template, channel_mapping] = add_marker_if_not_empty(pulse_template, add_marker, channel_mapping) - - if ~iscell(add_marker) - add_marker = {add_marker}; - end - - if ~isempty(add_marker) - marker_pulse = py.qctoolkit.pulses.PointPT({{0, 1},... - {py.getattr(pulse_template, 'duration'), 1}}, add_marker); - pulse_template = py.qctoolkit.pulses.AtomicMultiChannelPT(pulse_template, marker_pulse); - - for ii = 1:numel(add_marker) - channel_mapping.(args.add_marker{ii}) = add_marker{ii}; - end - end - - - \ No newline at end of file diff --git a/MATLAB/+qc/awgdisp.m b/MATLAB/+qc/awgdisp.m deleted file mode 100644 index f92b16727..000000000 --- a/MATLAB/+qc/awgdisp.m +++ /dev/null @@ -1,20 +0,0 @@ -function awgdisp(source) - -if nargin < 1 - source = 'qctk'; -end - -% get AWG objects -switch source - case 'qctk' - disp('source = qctoolkit') - case 'sim' - disp('simulaotr') - otherwise - disp('no input') -end - - -% get sequence tables - -% create app \ No newline at end of file diff --git a/MATLAB/+qc/change_armed_program.m b/MATLAB/+qc/change_armed_program.m deleted file mode 100644 index df91085dd..000000000 --- a/MATLAB/+qc/change_armed_program.m +++ /dev/null @@ -1,32 +0,0 @@ -function change_armed_program(program_name, turn_awg_off) -% CHANGE_ARMED_PROGRAM Force arming of a program on Tabor AWG -% This function calls change_armed_program and each Tabor channel pair -% which contains the indicated program. The program needs to be already -% present on the AWG. -% --- Inputs -------------------------------------------------------------- -% program_name : Program name which is armed -% turn_awg_off : Turn AWG off after arming the program. -% Default is true. -% ------------------------------------------------------------------------- -% (c) 2018/06 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de) - -global plsdata -hws = plsdata.awg.hardwareSetup; - -if nargin < 2 || isempty(turn_awg_off) - turn_awg_off = true; -end - -known_awgs = util.py.py2mat(hws.known_awgs); - -for k = 1:length(known_awgs) - known_programs{k} = util.py.py2mat(py.getattr(known_awgs{k}, '_known_programs')); - - if isfield(known_programs{k}, program_name) - known_awgs{k}.change_armed_program(program_name); - end -end - -if turn_awg_off - awgctrl('off'); -end \ No newline at end of file diff --git a/MATLAB/+qc/change_field.m b/MATLAB/+qc/change_field.m deleted file mode 100644 index dd22675eb..000000000 --- a/MATLAB/+qc/change_field.m +++ /dev/null @@ -1,3 +0,0 @@ -function s = change_field(s, fieldName, value) - s.(fieldName) = value; -end \ No newline at end of file diff --git a/MATLAB/+qc/check_pulse_parameter_dependency.m b/MATLAB/+qc/check_pulse_parameter_dependency.m deleted file mode 100644 index e8d281dbf..000000000 --- a/MATLAB/+qc/check_pulse_parameter_dependency.m +++ /dev/null @@ -1,64 +0,0 @@ -function check_pulse_parameter_dependency(pulse, check_parameter, check_values, varargin) -% plot function to visualize the influence of one pulse parameter on the -% pulse shape: -% ---------------------------------------------------------------------- -% input: -% pulse : loaded qctoolkit pulse -% check_paramter : name of the paramter under investigation -% check_values : values the parameter is set to, array [] -% varargin : standard varargin that one also uses for -% qc.plot_pulse -% ---------------------------------------------------------------------- -% written by Marcel Meyer 08|2018 (marcel.meyer1@rwth-aachen.de) - -global plsdata - -defaultArgs = struct(... - 'sample_rate', plsdata.awg.sampleRate, ... % in 1/s, converted to 1/ns below - 'channel_mapping', py.None, ... - 'window_mapping' , py.None, ... - 'parameters', struct(), ... - 'removeTrigChans', true, ... - 'figID', 2018 ... - ); - -args = util.parse_varargin(varargin, defaultArgs); - -if isempty(args.channel_mapping) || args.channel_mapping == py.None - - args.channel_mapping = py.dict(py.zip(pulse.defined_channels, pulse.defined_channels)); -end - -args.sample_rate = args.sample_rate * 1e-9; % convert to 1/ns - -figure(args.figID); -clf; - -for k = 1:numel(check_values) - args.parameters.(check_parameter) = check_values(k); - - instantiatedPulse = qc.instantiate_pulse(pulse, 'parameters', args.parameters, 'channel_mapping', args.channel_mapping, 'window_mapping', args.window_mapping); - data = util.py.py2mat(py.qctoolkit.pulses.plotting.render(instantiatedPulse, pyargs('sample_rate', args.sample_rate, 'render_measurements', true))); - - subplot(1, numel(check_values), k); - - hold on; - - if args.removeTrigChans - data{2} = rmfield(data{2}, 'MTrig'); - data{2} = rmfield(data{2}, 'M1'); - data{2} = rmfield(data{2}, 'M2'); - end - - channelNames = fieldnames(data{2}); - - for channelInd = 1:numel(channelNames) - plot(data{1}*1e-9, data{2}.(channelNames{channelInd})); - end - hold off; - legend(channelNames); - xlabel('t(s)'); - title(sprintf('%s = %.2d', check_parameter, check_values(k)), 'interpreter', 'none'); -end - -end \ No newline at end of file diff --git a/MATLAB/+qc/cleanupfn_awg.m b/MATLAB/+qc/cleanupfn_awg.m deleted file mode 100644 index 3e3a8a438..000000000 --- a/MATLAB/+qc/cleanupfn_awg.m +++ /dev/null @@ -1,9 +0,0 @@ -function scan = cleanupfn_awg(scan) - - if nargin < 1 - scan = []; - end - - evalin('caller', 'cleanupFnAwg = onCleanup(@()({awgctrl(''off''), fprintf(''Executing cleanup function: Turned AWG outputs off\n'')}));'); - -end \ No newline at end of file diff --git a/MATLAB/+qc/cleanupfn_delete_getchans.m b/MATLAB/+qc/cleanupfn_delete_getchans.m deleted file mode 100644 index 67216b0d4..000000000 --- a/MATLAB/+qc/cleanupfn_delete_getchans.m +++ /dev/null @@ -1,7 +0,0 @@ -function scan = cleanupfn_delete_getchans(scan, getchans) - - for getchan = getchans - evalin('caller', sprintf('data{%i} = {};', getchan)); - end - -end \ No newline at end of file diff --git a/MATLAB/+qc/cleanupfn_rf_sources.m b/MATLAB/+qc/cleanupfn_rf_sources.m deleted file mode 100644 index 018ba0830..000000000 --- a/MATLAB/+qc/cleanupfn_rf_sources.m +++ /dev/null @@ -1,11 +0,0 @@ -function scan = cleanupfn_rf_sources(scan) - - if nargin < 1 - scan = []; - end - - evalin('caller', 'cleanupFnRfMsg = onCleanup(@()(fprintf(''Executing cleanup function: Turned RF sources off\n'')));'); - evalin('caller', 'cleanupFnRf1 = onCleanup(@()(smset(''RF1_on'', 0)));'); - evalin('caller', 'cleanupFnRf2 = onCleanup(@()(smset(''RF2_on'', 0)));'); - -end \ No newline at end of file diff --git a/MATLAB/+qc/compensate_channels.m b/MATLAB/+qc/compensate_channels.m deleted file mode 100644 index ec6252637..000000000 --- a/MATLAB/+qc/compensate_channels.m +++ /dev/null @@ -1,90 +0,0 @@ -function [W, X, Y, Z] = compensate_channels(t, W, X, Y, Z, interpolation, comp_param_name) -% ADD_CHANNELS Compensate linear crosstalk for two ST0 qubits -% This function adds W and X to Y and Z (and vice-versa) with individual -% multipliers. It is specifically designed for compensating linear control -% crosstalk two ST0 qubits but might be suited for other qubit -% implementations as well. -% -% --- Outputs ------------------------------------------------------------- -% W, X : Compensated qubit 1 channel values (cell) -% Y, Z : Compensated qubit 2 channel values (cell) -% -% --- Inputs -------------------------------------------------------------- -% t, W, X, Y, Z, interpolation, MTrig, M1, M2 are cells with the same -% number of entries -% -% t : Time indices of the channel values (cell) -% One row: Applied to all channels -% *Two rows: Row 1 applied to W, X and row 2 to Y, Z -% *Four rows: One row for each channel -% W, X : Qubit 1 channel values (cell) -% Y, Z : Qubit 2 channel values (cell) -% interpolation : Interpolation strategies, use ‘hold’ for default -% qupulse behaviour -% One row: Applied to all channels -% *Two rows: Row 1 applied to W, X and row 2 to Y, Z -% *Four rows: One row for each channel -% comp_param_name: Name of the compensation parameters -% -% * Currently disabled since compensation might not work if using -% different times -% -% ------------------------------------------------------------------------- -% (c) 2018/05 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de) - - assert(all(numel(t) == cellfun(@numel, {W, X, Y, Z, interpolation})), 'Cell input arguments must have the same number of elements'); - assert(size(t, 1) == 1 && size(interpolation, 1) == 1, 'Compensation of different times and interpolation strategies not currently supported'); - - if nargin < 7 || isempty(comp_param_name) - comp_param_name = 'globals___comp'; - end - - if ~strcmp(comp_param_name, 'compensation_off') - [W, X, Y, Z] = comp_channels(W, X, Y, Z, comp_param_name); - end - [W, X, Y, Z] = format_channels(t, interpolation, W, X, Y, Z); - -end - - -function [W, X, Y, Z] = comp_channels(W, X, Y, Z, comp_param_name) - for k = 1:numel(W) - Wk = W{k}; - Xk = X{k}; - - W{k} = [W{k} ' + ' comp_param_name '_w_y*( ' Y{k} ' ) + ' comp_param_name '_w_z*( ' Z{k} ' )']; - X{k} = [X{k} ' + ' comp_param_name '_x_y*( ' Y{k} ' ) + ' comp_param_name '_x_z*( ' Z{k} ' )']; - - Y{k} = [Y{k} ' + ' comp_param_name '_y_w*( ' Wk ' ) + ' comp_param_name '_y_x*( ' Xk ' )']; - Z{k} = [Z{k} ' + ' comp_param_name '_z_w*( ' Wk ' ) + ' comp_param_name '_z_x*( ' Xk ' )']; - end - -end - -function varargout = format_channels(t, interpolation, varargin) - - varargout = cell(numel(varargin), 1); - - if size(interpolation, 1) == 1 - interpolation = repmat(interpolation, 4, 1); - elseif size(interpolation, 1) == 2 - interpolation = [ repmat(interpolation(1, :), 2, 1) ; - repmat(interpolation(2, :), 2, 1) ]; - end - - if size(t, 1) == 1 - t = repmat(t, 4, 1); - elseif size(t, 1) == 2 - t = [ repmat(t(1, :), 2, 1) ; - repmat(t(2, :), 2, 1) ]; - end - - for k = 1:size(t, 2) - for v = 1:numel(varargin) - - varargout{v}{end+1} = { t{v, k}, varargin{v}{k}, interpolation{v, k} }; - - end - end - -end \ No newline at end of file diff --git a/MATLAB/+qc/conf_seq.m b/MATLAB/+qc/conf_seq.m deleted file mode 100644 index b58afab43..000000000 --- a/MATLAB/+qc/conf_seq.m +++ /dev/null @@ -1,326 +0,0 @@ -function scan = conf_seq(varargin) - % CONF_SEQ Create special-measure scans with inline qctoolkit pulses - % - % Only supports inline scans at the moment (could in principle arm a - % different program in each loop iteration using prefns but this is not - % implemented at the moment). - % - % Please only add aditional configfns directly before turning the AWG on - % since some other programs fetch information using configfn indices. - % - % This function gets only underscore arguments to be more consistend with - % qctoolkit. Other variables in this function are camel case. - % - % --- Outputs ------------------------------------------------------------- - % scan : special-measure scan - % - % --- Inputs -------------------------------------------------------------- - % varargin : name-value pairs or parameter struct. For a list of - % parameters see the struct defaultArgs below. - % - % ------------------------------------------------------------------------- - % (c) 2018/02 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de) - - global plsdata - - alazarName = plsdata.daq.instSmName; - - % None of the arguments except pulse_template should contain any python - % objects to avoid erroneous saving when the scan is executed. - defaultArgs = struct(... - ... Pulses - 'program_name', 'default_program', ... - 'pulse_template', 'default_pulse', ... - 'parameters_and_dicts', {plsdata.awg.defaultParametersAndDicts}, ... - 'channel_mapping', plsdata.awg.defaultChannelMapping, ... - 'window_mapping', plsdata.awg.defaultWindowMapping, ... - 'add_marker', {plsdata.awg.defaultAddMarker}, ... - 'force_update', false, ... - ... - ... Pulse modification - 'pulse_modifier_args', struct(), ... % Additional arguments passed to the pulse_modifier_fn - 'pulse_modifier', false, ... % Automatically change the variable a (all input arguments) below, can be used to dynamically modify the pulse - 'pulse_modifier_fn', @tune.add_dbz_fid, ... % Can specify a custom function here which modifies the variable a (all input arguments) below - ... - ... Saving variables - 'save_custom_var_fn', @tune.get_global_opts,... % Can specify a function which returns data to be saved in the scan - 'save_custom_var_args', {{'dnp', 'tune_gui'}}, ... - 'save_metadata_fns', {{@sm_scans.triton_200.metafn_get_configchanvals} ... % Can specify functions to log metadata during each loop - {@sm_scans.triton_200.metafn_get_rf_channels}}, ... - 'save_metadata_fields', {{'configchanvals'} {'rfChannels'}}, ... % Fieldnames of the metadata struct saved by smrun - ... - ... Measurements - 'operations', {plsdata.daq.defaultOperations}, ... - ... - ... Other - 'nrep', 10, ... % Numer of repetition of pulse - 'fig_id', 2000, ... - 'fig_position', [], ... - 'disp_ops', ' default', ... % Refers to operations: List of indices of operations to show - 'disp_dim', [1 2], ... % dimension of display - 'delete_getchans', [1], ... % Refers to getchans: Indices of getchans (including those generated by procfns) to delete after the scan is complete - 'procfn_ops', {{}}, ... % Refers to operations: One entry for each virtual channel, each cell entry has four or five element: fn, args, dim, operation index, (optional) identifier - 'saveloop', 0, ... % save every nth loop - 'useCustomCleanupFn', false, ... % If this flag is true - 'customCleanupFn', [], ... % clean up anything else you would like cleaned up - 'useCustomConfigFn', false, ... % If this flag is true - 'customConfigFn', [], ... % add a custom config function which is executed directly before the AWG is turned on - 'arm_global', false, ... % If true, set the program to be armed via tunedata.global_opts.conf_seq.arm_program_name. - ... % If you use this, all programs need to be uploaded manually before the scan and need to - ... % have the same Alazar configuration. - 'rf_sources', [true true], ... % turn RF sources on and off automatically - 'buffer_strategy', {plsdata.daq.defaultBufferStrategy},... % call qc.set_alazar_buffer_strategy with these arguments before pulse - 'verbosity', 10 ... % 0: display nothing, 10: display all except when arming program, 11: display all - ); - a = util.parse_varargin(varargin, defaultArgs); - aOriginal = a; - - if a.pulse_modifier - try - a = feval(a.pulse_modifier_fn, a); % Add any proprietary function here - catch err - warning('Could not run pulse_modifier_fn successfully. Continuing as if pulse_modifier was false:\n%s', err.getReport()); - a = aOriginal; - end - end - - if ~ischar(a.pulse_template) && ~isstruct(a.pulse_template) - a.pulse_template = qc.pulse_to_struct(a.pulse_template); - end - - if numel(a.rf_sources) == 1 - a.rf_sources = [a.rf_sources a.rf_sources]; - end - - scan = struct('configfn', [], 'cleanupfn', [], 'loops', struct('prefn', [], 'metafn', [])); - - % Save file and arguments with which scan was created (not stricly necessary) - try - if ischar(aOriginal.pulse_modifier_fn) - scan.data.pulse_modifier_fn = fileread(which(aOriginal.pulse_modifier_fn)); - else - scan.data.pulse_modifier_fn = fileread(which(func2str(aOriginal.pulse_modifier_fn))); - end - catch err - warning('Could not load pulse_modifier_fn for saving in scan for reproducibility:\n%s', err.getReport()); - end - scan.data.conf_seq_fn = fileread([mfilename('fullpath') '.m']); - scan.data.conf_seq_args = aOriginal; - - % Configure channels - scan.loops(1).getchan = {'ATSV', 'time'}; - scan.loops(1).setchan = {'count'}; - scan.loops(1).ramptime = []; - scan.loops(1).npoints = a.nrep; - scan.loops(1).rng = []; - - nGetChan = numel(scan.loops(1).getchan); - nOperations = numel(a.operations); - - % Turn AWG outputs off if scan stops (even if due to error) - scan.configfn(end+1).fn = @qc.cleanupfn_awg; - scan.configfn(end).args = {}; - - % Turn RF sources off if scan stops (even if due to error) - if any(a.rf_sources) - scan.configfn(end+1).fn = @qc.cleanupfn_rf_sources; - scan.configfn(end).args = {}; - end - - % Alazar buffer strategy. Can be used to mitigate buffer artifacts. - scan.configfn(end+1).fn = @smaconfigwrap; - scan.configfn(end).args = [{@qc.set_alazar_buffer_strategy}, a.buffer_strategy]; - - % Configure AWG - % * Calling qc.awg_program('add', ...) makes sure the pulse is uploaded - % again if any parameters changed. - % * If dictionaries were passed as strings, this will automatically - % reload the dictionaries and thus use any changes made in the - % dictionaries in the meantime. - % * The original parameters are saved in scan.data.awg_program. This - % includes the pulse_template in json format and all dictionary - % entries at the time when the scan was executed. - % * If a python pulse_template was passed, this will still save - % correctly since it was converted into a Matlab struct above. - scan.configfn(end+1).fn = @smaconfigwrap_save_data; - scan.configfn(end).args = {'awg_program', @qc.awg_program, 'add', a}; - - % Configure Alazar operations - % * alazar.update_settings = py.True is automatically set. This results - % in reconfiguration of the Alazar which takes a long time. Thus this - % should only be done before a scan is started (i.e. in a configfn). - % * qc.dac_operations('add', a) also resets the virtual channel in - % smdata.inst(sminstlookup(alazarName)).data.virtual_channel. - scan.configfn(end+1).fn = @smaconfigwrap_save_data; - scan.configfn(end).args = {'daq_operations', @qc.daq_operations, 'add', a}; - - % Configure Alazar virtual channel - % * Set datadim of instrument correctly - % * Save operation lengths in scan.data - scan.configfn(end+1).fn = @smaconfigwrap_save_data; - scan.configfn(end).args = {'daq_operations_length', @qc.daq_operations, 'set length', a}; - - % Extract operation data from first channel ('ATSV') - % * Add procfns to scan, one for each operation - % * The configfn qc.conf_seq_procfn sets args and dim of the first n - % procfns, where n is the number of operations. This ensures that start - % and stop always use the correct lengths even if they have changed due - % to changes in pulse dictionaries. qc.conf_seq_procfn assumes that the - % field scan.data.daq_operations_length has been set dynamically by a - % previous configfn. - nGetChan = numel(scan.loops(1).getchan); - for p = 1:numel(a.operations) - scan.loops(1).procfn(nGetChan + p).fn(1) = struct( ... - 'fn', @(x, startInd, stopInd)( x(startInd:stopInd) ), ... - 'args', {{nan, nan}}, ... - 'inchan', 1, ... - 'outchan', nGetChan + p ... - ); - scan.loops(1).procfn(nGetChan + p).dim = nan; - end - scan.configfn(end+1).fn = @qc.conf_seq_procfn; - scan.configfn(end).args = {}; - - if any(a.rf_sources) - % Turn RF switches on - scan.configfn(end+1).fn = @smaconfigwrap; - scan.configfn(end).args = {@smset, 'RF1_on', double(a.rf_sources(1))}; - scan.configfn(end+1).fn = @smaconfigwrap; - scan.configfn(end).args = {@smset, 'RF2_on', double(a.rf_sources(2))}; - scan.configfn(end+1).fn = @smaconfigwrap; - scan.configfn(end).args = {@pause, 0.05}; % So RF sources definitely on - - % Turn RF switches off - % -> already done by qc.cleanupfn_rf_sources called above - end - - % Add custom variables for documentation purposes - scan.configfn(end+1).fn = @smaconfigwrap_save_data; - scan.configfn(end).args = {'custom_var', a.save_custom_var_fn, a.save_custom_var_args}; - - % Add custom cleanup fn - if a.useCustomCleanupFn && ~isempty(a.customCleanupFn) - scan.configfn(end+1).fn = a.customCleanupFn; - scan.configfn(end).args = {}; - end - - % Add custom config fn - if a.useCustomConfigFn && ~isempty(a.customConfigFn) - scan.configfn(end+1).fn = a.customConfigFn; - scan.configfn(end).args = {}; - end - - % Delete unnecessary data - scan.cleanupfn(end+1).fn = @qc.cleanupfn_delete_getchans; - scan.cleanupfn(end).args = {a.delete_getchans}; - - % Allow time logging - % * Update dummy instrument with current time so can get the current time - % using a getchan - scan.loops(1).prefn(end+1).fn = @smaconfigwrap; - scan.loops(1).prefn(end).args = {@(chan)(smset('time', now()))}; - - % Allow logging metadata - for i = 1:length(a.save_metadata_fns) - scan.loops(1).metafn(end+1).fn = @smaconfigwrap_save_metadata; - scan.loops(1).metafn(end).args = {a.save_metadata_fields{i}, a.save_metadata_fns{i}}; - end - - % Turn AWG on - scan.configfn(end+1).fn = @smaconfigwrap; - scan.configfn(end).args = {@awgctrl, 'on'}; - - % Run AWG channel pair 1 - % * Arm the program - % * Trigger the Alazar - % * Will later also trigger the RF switches - % * Will run both channel pairs automatically if they are synced - % which they should be by default. - % * Should be the last prefn so no other channels changed when - % measurement starts (really necessary?) - scan.loops(1).prefn(end+1).fn = @smaconfigwrap; - if ~a.arm_global - scan.loops(1).prefn(end).args = {@qc.awg_program, 'arm', qc.change_field(a, 'verbosity', a.verbosity-1)}; - else - scan.loops(1).prefn(end).args = {@qc.awg_program, 'arm global', qc.change_field(a, 'verbosity', a.verbosity-1)}; - end - scan.loops(1).prefn(end+1).fn = @smaconfigwrap; - scan.loops(1).prefn(end).args = {@awgctrl, 'run', 1}; - - % Get AWG information (not needed at the moment) - % [analogNames, markerNames, channels] = qc.get_awg_channels(); - % [programNames, programs] = qc.get_awg_programs(); - - % Default display - if strcmp(a.disp_ops, 'default') - a.disp_ops = 1:min(4, nOperations); - end - - % Add user procfns - if isfield(scan.loops(1), 'procfn') - nProcFn = numel(scan.loops(1).procfn); - else - nProcFn = 0; - end - for opInd = 1:numel(a.procfn_ops) % count through operations - inchan = nGetChan + a.procfn_ops{opInd}{4}; - scan.loops(1).procfn(end+1).fn(1) = struct( ... - 'fn', a.procfn_ops{opInd}{1}, ... - 'args', {a.procfn_ops{opInd}{2}}, ... - 'inchan', inchan, ... - 'outchan', nProcFn + opInd ... - ); - scan.loops(1).procfn(end).dim = a.procfn_ops{opInd}{3}; - if numel(a.procfn_ops{opInd}) >= 5 - scan.loops(1).procfn(end).identifier = a.procfn_ops{opInd}{5}; - end - end - - % Configure display - scan.figure = a.fig_id; - if ~isempty(a.fig_position) - scan.figpos = a.fig_position; - end - scan.disp = []; - for l = 1:length(a.disp_ops) - for d = a.disp_dim - scan.disp(end+1).loop = 1; - scan.disp(end).channel = nGetChan + a.disp_ops(l); - scan.disp(end).dim = d; - - if a.disp_ops(l) <= nOperations - opInd = a.disp_ops(l); - else - opInd = a.procfn_ops{a.disp_ops(l)-nOperations}{4}; - end - - % added new condition "numel(opInd) == 1" to check for several - % inchans, later they should get a proper title (marcel) - if numel(opInd) == 1 && opInd <= numel(a.operations) - scan.disp(end).title = prepare_title(sprintf(['%s: '], a.operations{opInd}{:})); - elseif numel(opInd) == 1 && length(a.procfn_ops{opInd - nOperations}) > 4 - scan.disp(end).title = prepare_title(sprintf(['%s: '], a.procfn_ops{opInd - nOperations}{5})); - else - scan.disp(end).title = ''; - end - end - end - - if a.saveloop > 0 - scan.saveloop = [1, a.saveloop]; - end - -end - - - -function str = prepare_title(str) - - str = strrep(str, '_', ' '); - str = str(1:end-2); - - str = strrep(str, 'RepAverage', 'RSA'); - str = strrep(str, 'Downsample', 'DS'); - str = strrep(str, 'Qubit', 'Q'); - -end \ No newline at end of file diff --git a/MATLAB/+qc/conf_seq_procfn.m b/MATLAB/+qc/conf_seq_procfn.m deleted file mode 100644 index 8a884b2dd..000000000 --- a/MATLAB/+qc/conf_seq_procfn.m +++ /dev/null @@ -1,15 +0,0 @@ -function scan = conf_seq_procfn(scan) - % Dynamically changes the procfn arguments for each operation which - % extracts the data from the channel ATSV - % - % Assumes that the field scan.data.daq_operations_length has been set to - % the lengths of the operations. - - nGetChan = numel(scan.loops(1).getchan); - lengths = scan.data.daq_operations_length; - startInd = 1; - for p = 1:numel(lengths) - scan.loops(1).procfn(nGetChan + p).fn(1).args = {startInd, startInd+lengths(p)-1}; - scan.loops(1).procfn(nGetChan + p).dim = [lengths(p)]; - startInd = startInd + lengths(p); - end \ No newline at end of file diff --git a/MATLAB/+qc/daq_operations.m b/MATLAB/+qc/daq_operations.m deleted file mode 100644 index cb1bc51b5..000000000 --- a/MATLAB/+qc/daq_operations.m +++ /dev/null @@ -1,125 +0,0 @@ -function [output, bool, msg] = daq_operations(ctrl, varargin) - - global plsdata smdata - hws = plsdata.awg.hardwareSetup; - daq = plsdata.daq.inst; - instIndex = sminstlookup(plsdata.daq.instSmName); - - program = struct(); - msg = ''; - bool = false; - - default_args = struct(... - 'program_name', 'default_program', ... - 'operations', {plsdata.daq.defaultOperations}, ... - 'verbosity', 10 ... - ); - a = util.parse_varargin(varargin, default_args); - output = a.operations; - - % --- add --------------------------------------------------------------- - if strcmp(ctrl, 'add') % output is operations - % Call before qc.awg_program('arm')! - - smdata.inst(instIndex).data.virtual_channel = struct( ... - 'operations', {a.operations} ... - ); - - % alazar.update_settings = py.True is automatically set if - % register_operations is executed. This results in reconfiguration - % of the Alazar which takes a long time. Thus, we avoid registering - % operations if the last armed program is the same as the currently - % armed program. We know plsdata.awg.currentProgam contains the last - % armed program since qc.daq_operations should be called before - % qc.awg_program('arm'). - if plsdata.daq.reuseOperations && ~plsdata.daq.operationsExternallyModified && strcmp(plsdata.awg.currentProgam, a.program_name) - msg = sprintf('Operations from last armed program ''%s'' reused.\n If an error occurs, try executing another program\n first to update the operations.', plsdata.awg.currentProgam); - else - daq.register_operations(a.program_name, qc.operations_to_python(a.operations)); - msg = sprintf('Operations for program ''%s'' added', a.program_name); - - if plsdata.daq.operationsExternallyModified - plsdata.daq.inst.update_settings = py.True; - end - - plsdata.daq.operationsExternallyModified = false; - % qc.workaround_alazar_single_buffer_acquisition(); - end - bool = true; - - % --- set length -------------------------------------------------------- - elseif strcmp(ctrl, 'set length') % output is length - % Operations need to have been added beforehand - output = qc.daq_operations('get length', a); - smdata.inst(instIndex).cntrlfn([instIndex nan 999], output); - - % --- get length -------------------------------------------------------- - elseif strcmp(ctrl, 'get length') % output is length - % Operations need to have been added beforehand - mask_maker = py.getattr(daq, '_make_mask'); - masks = util.py.py2mat(py.getattr(daq, '_registered_programs')); - masks = util.py.py2mat(masks.(a.program_name)); - operations = masks.operations; - masks = util.py.py2mat(masks.masks(mask_maker)); - - - maskIdsFromOperations = cellfun(@(x)(char(x.maskID)), util.py.py2mat(operations), 'UniformOutput', false); - maskIdsFromMasks = cellfun(@(x)(char(x.identifier)), util.py.py2mat(masks), 'UniformOutput', false); - - output = []; - for k = 1:length(operations) - maskIndex = find( cellfun(@(x)(strcmp(x, maskIdsFromOperations{k})), maskIdsFromMasks) ); - if numel(maskIndex) ~= 1 - error('Found several masks with same identifier. Might be a problem in qctoolkit or in this function.'); - end - - if isa(operations{k}, 'py.atsaverage._atsaverage_release.ComputeDownsampleDefinition') - output(k) = util.py.py2mat(size(masks{maskIndex}.length)); - elseif isa(operations{k}, 'py.atsaverage._atsaverage_release.ComputeRepAverageDefinition') - n = util.py.py2mat(masks{maskIndex}.length.to_ndarray); - if any(n ~= n(1)) - error('daq_operations assumes that all masks should have the same length if using ComputeRepAverageDefinition.'); - end - output(k) = n(1); - else - error('Operation ''%s'' not yet implemented', class(operations{k})); - end - end - if isempty(output) - warning('No masks configured'); - end - - % --- get --------------------------------------------------------------- - elseif strcmp(ctrl, 'get programs') % output is registered programs - % Operations need to have been added beforehand - % masks = util.py.py2mat(daq.config.masks); % this worked sometimes but sometimes not - output = util.py.py2mat(py.getattr(daq, '_registered_programs')); - - % --- remove ------------------------------------------------------------ - elseif strcmp(ctrl, 'remove') % output is operations - % Should not call this usually. Call qc.awg_program('remove') instead. - smdata.inst(instIndex).data.virtual_channel = struct( ... - 'operations', {{}} ... - ); - programs = fieldnames(qc.daq_operations('get programs')); - if any(cellfun(@(x)(strcmp(x, a.program_name)), programs)) - daq.delete_program(a.program_name); - msg = sprintf('Operations for program ''%s'' deleted', a.program_name); - bool = true; - else - msg = sprintf('Operations for program ''%s'' were not registered', a.program_name); - bool = true; - end - - % --- clear all --------------------------------------------------------- - elseif strcmp(ctrl, 'clear all') - alazarPackage = py.importlib.import_module('qctoolkit.hardware.dacs.alazar'); - py.setattr(daq, '_registered_programs', py.collections.defaultdict(alazarPackage.AlazarProgram)); - bool = true; - msg = 'All programs cleared from DAQ'; - - end - - if a.verbosity > 9 - fprintf([msg '\n']); - end \ No newline at end of file diff --git a/MATLAB/+qc/dict.m b/MATLAB/+qc/dict.m deleted file mode 100644 index 9e8675ba6..000000000 --- a/MATLAB/+qc/dict.m +++ /dev/null @@ -1,10 +0,0 @@ -function d = dict(varargin) -% Wrapper for struct so do not need to have three curly braces when -% creating pulse templates -% -% varargin needs to the same as for struct(.) - -for k = 2:2:numel(varargin) - varargin{k} = {varargin{k}}; -end -d = struct(varargin{:}); \ No newline at end of file diff --git a/MATLAB/+qc/dict_apply_globals.m b/MATLAB/+qc/dict_apply_globals.m deleted file mode 100644 index 7fe8665bf..000000000 --- a/MATLAB/+qc/dict_apply_globals.m +++ /dev/null @@ -1,27 +0,0 @@ -function d = dict_apply_globals(d) - % Replace all parameters by their global values - if qc.is_dict(d) && isfield(d, 'global') - delim = '___'; - globals = fieldnames(d.global); - - for pulseName = fieldnames(d)' - if strcmp(pulseName{1}, strcat('dict', delim, 'name')) - continue - end - - % Only add global parameters which are defined in pulse parameters - % for paramName = fieldnames(d.(pulseName{1}))' - % bool = cellfun(@(x)(strcmp(paramName{1}, x)), globals, 'UniformOutput', true); - % if any(bool) - % d.(pulseName{1}).(paramName{1}) = d.global.(globals{bool}); - % end - % end - - % Add all global parameters to pulse irrespective of whether they are - % defined in pulse parameters - d.(pulseName{1}) = qc.join_structs(d.(pulseName{1}), d.global); - - end - d = rmfield(d, 'global'); - end -end \ No newline at end of file diff --git a/MATLAB/+qc/dict_to_parameter_struct.m b/MATLAB/+qc/dict_to_parameter_struct.m deleted file mode 100644 index 2d997c9bc..000000000 --- a/MATLAB/+qc/dict_to_parameter_struct.m +++ /dev/null @@ -1,18 +0,0 @@ -function p = dict_to_parameter_struct(d) - % Flatten dict into a parameter struct - if qc.is_dict(d) - delim = '___'; - d = rmfield(d, strcat('dict', delim, 'name')); - - p = {}; - for pulseName = fieldnames(d)' - for paramName = fieldnames(d.(pulseName{1}))' - p{end+1} = strcat(pulseName{1}, delim, paramName{1}); - p{end+1} = d.(pulseName{1}).(paramName{1}); - end - end - p = struct(p{:}); - else - p = d; - end -end \ No newline at end of file diff --git a/MATLAB/+qc/disp_awg_seq_table.m b/MATLAB/+qc/disp_awg_seq_table.m deleted file mode 100644 index 7dc7a2781..000000000 --- a/MATLAB/+qc/disp_awg_seq_table.m +++ /dev/null @@ -1,95 +0,0 @@ -% function to display the sequence table hold by qctoolkit Tabor instance -% or given in the varargins -% ------------------------------------------------------------------------- -% Notes: -% - if varargin.seq_table is empty the sequence table saved in the qctoolkit -% Tabor object is plotted -> function uses qc.get_sequence_table internaly -% ------------------------------------------------------------------------- -% written by Marcel Meyer 08|2018 - - -function disp_awg_seq_table(varargin) - - global plsdata - - defaultArgs = struct(... - 'seq_table', {{}}, ... - 'programName', plsdata.awg.currentProgam, ... - 'advancedSeqTableFlag', false ... - ); - args = util.parse_varargin(varargin, defaultArgs); - - - if isempty(args.seq_table) - seq_table = qc.get_sequence_table(args.programName, args.advancedSeqTableFlag); - else - assert(iscell(args.seq_table), 'wrong format sequence table') - seq_table = args.seq_table; - end - - disp(' '); - disp('[i] Table 1 is for channel pair AB and table 2 for channel pair CD.'); - disp(' '); - - counter = 0; - tmpEntry = ''; - - for k = 1:2 - if isempty(seq_table{k}) - warning('-- empty sequence table at channel nr %i -- \n', k); - else - if ~args.advancedSeqTableFlag - - fprintf('--- table %d -----------------\n', k); - for n = 1:length(seq_table{k}) - fprintf(' -- sub table %d ---------\n', n); - - tmpEntry = seq_table{k}{n}{1}; - counter = 0; - for i=1:length(seq_table{k}{n}) - if isequal(tmpEntry, seq_table{k}{n}{i}) - counter = counter+1; - else - - fprintf(' rep = %d', counter); - disp(tmpEntry); - - tmpEntry = seq_table{k}{n}{i}; - counter = 1; - end - end - fprintf(' rep = %d', counter); - disp(tmpEntry); - disp('-----------------------------') - end - - - - - else - - fprintf('--- table %d -----------------\n', k); - - tmpEntry = seq_table{k}{1}; - counter = 0; - for i=1:length(seq_table{k}) - if isequal(tmpEntry, seq_table{k}{i}) - counter = counter+1; - else - fprintf(' rep = %d', counter); - disp(tmpEntry); - - tmpEntry = seq_table{k}{i}; - counter = 0; - end - end - fprintf(' rep = %d', counter); - disp(tmpEntry); - disp('-----------------------------') - - end - - - end - end -end \ No newline at end of file diff --git a/MATLAB/+qc/disp_dict.m b/MATLAB/+qc/disp_dict.m deleted file mode 100644 index bdc50ac37..000000000 --- a/MATLAB/+qc/disp_dict.m +++ /dev/null @@ -1,31 +0,0 @@ -function text = disp_dict(dict_string_or_struct) - global plsdata - delim = '___'; - - text = ''; - - if isstruct(dict_string_or_struct) - if ~isfield(dict_string_or_struct, ['dict' delim 'name']) - error('Please pass a valid dictionary struct. The passed argument is missing the field ''%s''.\n', ['dict' delim 'name']); - end - text = py.json.dumps(dict_string_or_struct, pyargs('indent', int8(4), 'sort_keys', true)); - text = char(text); - dict_string_or_struct = dict_string_or_struct.(['dict' delim 'name']); - elseif ischar(dict_string_or_struct) - file_name = fullfile(plsdata.dict.path, [dict_string_or_struct '.json']); - if exist(file_name, 'file') - text = fileread(file_name); - else - error('Dictionary ''%s'' could not be loaded since file ''%s'' does not exist\n', dict_string_or_struct, file_name); - end - else - error('Please pass a valid dictonary struct or string\n'); - end - - if ~isempty(text) - util.disp_section(sprintf('Dictionary %s', dict_string_or_struct)); - fprintf('%s\n', text); - util.disp_section(); - end - - end \ No newline at end of file diff --git a/MATLAB/+qc/get_alazar_measurements.m b/MATLAB/+qc/get_alazar_measurements.m deleted file mode 100644 index a5d79e86c..000000000 --- a/MATLAB/+qc/get_alazar_measurements.m +++ /dev/null @@ -1,32 +0,0 @@ -function [mask_prototypes, measurement_map, txt] = get_alazar_measurements(varargin) - - global plsdata - hws = plsdata.awg.hardwareSetup; - daq = plsdata.daq.inst; - - - defaultArgs = struct( ... - 'disp', true ... - ); - args = util.parse_varargin(varargin, defaultArgs); - - mask_prototypes = util.py.py2mat(daq.mask_prototypes); - measurement_map = util.py.py2mat(py.getattr(hws,'_measurement_map')); - - txt = sprintf('%-30s %-30s %-30s\\n', 'Measurement', 'Mask', 'Hardware Channel'); - txt = strcat(txt, [ones(1,85)*'-' '\n']); - - measurement_map = orderfields(measurement_map); - for measName = fieldnames(measurement_map)' - masks = measurement_map.(measName{1}); - for k = 1:numel(masks) - maskName = char(masks{k}.mask_name); - txt = strcat(txt, sprintf('%-30s %-30s %-30i\\n', measName{1}, maskName, mask_prototypes.(maskName){1})); - end - end - - txt = strcat(txt, [ones(1,85)*'-' '\n']); - - if args.disp - fprintf(txt); - end \ No newline at end of file diff --git a/MATLAB/+qc/get_awg_channels.m b/MATLAB/+qc/get_awg_channels.m deleted file mode 100644 index 067b7dd4a..000000000 --- a/MATLAB/+qc/get_awg_channels.m +++ /dev/null @@ -1,16 +0,0 @@ -function [analogNames, markerNames, channels] = get_awg_channels() - - global plsdata - - % Get AWG analog channels and markers - channels = struct(plsdata.awg.hardwareSetup.registered_channels); - analogNames = {}; - markerNames = {}; - for chanName = fieldnames(channels)' - chan = util.py.py2mat(channels.(chanName{1})); - if isa(chan{1}, 'py.qctoolkit.hardware.setup.MarkerChannel') - markerNames{end+1} = chanName{1}; - elseif isa(chan{1}, 'py.qctoolkit.hardware.setup.PlaybackChannel') - analogNames{end+1} = chanName{1}; - end - end \ No newline at end of file diff --git a/MATLAB/+qc/get_awg_memory.m b/MATLAB/+qc/get_awg_memory.m deleted file mode 100644 index 7b830b479..000000000 --- a/MATLAB/+qc/get_awg_memory.m +++ /dev/null @@ -1,44 +0,0 @@ -% function to get waveforms and sequence tables from the AWG -% ------------------------------------------------------------------------- -% Notes: -% - the function only works with the Tabor AWG Simulator not on the real -% Tabor AWG -% - the function arms the program that is inspected -% ------------------------------------------------------------------------- -% written by Marcel Meyer 08|2018 - -function awg_memory_struct = get_awg_memory(program_name, awg_channel_pair_identifier) - - global plsdata - - assert(ischar(program_name), 'first argument of get_awg_memory must be string'); - - if nargin < 2 || isempty(awg_channel_pair_identifier) - awg_channel_pair_identifier = 'AB'; - else - assert(ischar(awg_channel_pair_identifier), 'second argument of get_awg_memory must be string'); - end - - % get AWG channelpair python object - hws = plsdata.awg.hardwareSetup; - known_awgs = util.py.py2mat(hws.known_awgs); - sort_indices = cellfun(@(x)(~isempty(strfind(char(x.identifier), awg_channel_pair_identifier))), known_awgs); - channelpair = known_awgs(find(sort_indices)); - channelpair = channelpair{1}; - - % arm program at AWG - try - channelpair.arm(program_name); - catch err - warning('program seems not to be on AWG, upload it first, returning without returning memory'); - warning(err.message); - return - end - - % get a plottable program object -> qctoolkit Tabor driver gets sequence - % tables and waveforms from the simulator - plottableProgram = channelpair.read_complete_program(); - - awg_memory_struct = util.py.py2mat(plottableProgram.to_builtin()); - -end \ No newline at end of file diff --git a/MATLAB/+qc/get_awg_programs.m b/MATLAB/+qc/get_awg_programs.m deleted file mode 100644 index 3d764b8e4..000000000 --- a/MATLAB/+qc/get_awg_programs.m +++ /dev/null @@ -1,10 +0,0 @@ -function [programNames, programs] = get_awg_programs() - - global plsdata - - programs = util.py.py2mat(plsdata.awg.hardwareSetup.registered_programs); - programNames = fieldnames(programs); - - if ~isempty(setdiff(fieldnames(rmfield(plsdata.awg.registeredPrograms, 'currentProgam')), programNames)) - warning('''plsdata.awg.registeredPrograms'' out of sync with ''plsdata.awg.hardwareSetup.registered_programs''. Clear all programs by executing qc.awg_program(''clear all'') to remedy.'); - end \ No newline at end of file diff --git a/MATLAB/+qc/get_awg_seq_table.m b/MATLAB/+qc/get_awg_seq_table.m deleted file mode 100644 index 36fb340fc..000000000 --- a/MATLAB/+qc/get_awg_seq_table.m +++ /dev/null @@ -1,13 +0,0 @@ -function seq_table = get_awg_seq_table(varargin) - - global plsdata - - defaultArgs = struct(... - 'programName', plsdata.awg.currentProgam, ... - 'advancedSeqTableFlag', false ... - ); - args = util.parse_varargin(varargin, defaultArgs); - - seq_table = qc.get_sequence_table(args.programName, args.advancedSeqTableFlag); - -end \ No newline at end of file diff --git a/MATLAB/+qc/get_dnp_pulse_duration.m b/MATLAB/+qc/get_dnp_pulse_duration.m deleted file mode 100644 index 5e2188ea8..000000000 --- a/MATLAB/+qc/get_dnp_pulse_duration.m +++ /dev/null @@ -1,55 +0,0 @@ -function currentPulseDurationOffset = get_dnp_pulse_duration_offset() - - global tunedata - - t = tunedata.run{tunedata.runIndex}.global_opts.dnp.durations; - -% qc.get_pulse_duration(... -% qc.struct_to_pulse(tunedata.run{tunedata.runIndex}.global_opts.dnp.scan.configfn(4).args{end}.pulse_template), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); - -% t_pumpingPart = qc.get_pulse_duration(... -% qc.load_pulse('dnp_ABCD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% -% t_s_AB = qc.get_pulse_duration(... -% qc.load_pulse('s_pumping_AB_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_cs_AB = qc.get_pulse_duration(... -% qc.load_pulse('t_pumping_AB_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_t_AB = qc.get_pulse_duration(... -% qc.load_pulse('cs_pumping_AB_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% -% t_s_CD = qc.get_pulse_duration(... -% qc.load_pulse('s_pumping_CD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_t_CD = qc.get_pulse_duration(... -% qc.load_pulse('t_pumping_CD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_cs_CD = qc.get_pulse_duration(... -% qc.load_pulse('cs_pumping_CD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); - - pumpConf = tunedata.run{1}.global_opts.dnp.pumpingConfigArgs.currentConfig; - - t.current_dnp_pulse = ... - t.s_AB * double(pumpConf.n_s_AB) + ... - t.t_AB * double(pumpConf.n_t_AB) + ... - t.cs_AB * double(pumpConf.n_cs_AB) + ... - t.s_CD * double(pumpConf.n_s_CD) + ... - t.t_CD * double(pumpConf.n_t_CD) + ... - t.cs_CD * double(pumpConf.n_cs_CD); - - currentPulseDurationOffset = t.current_dnp_pulse - t.dict_dnp_pulse; - -end \ No newline at end of file diff --git a/MATLAB/+qc/get_dnp_pulse_duration_offset.m b/MATLAB/+qc/get_dnp_pulse_duration_offset.m deleted file mode 100644 index 5e2188ea8..000000000 --- a/MATLAB/+qc/get_dnp_pulse_duration_offset.m +++ /dev/null @@ -1,55 +0,0 @@ -function currentPulseDurationOffset = get_dnp_pulse_duration_offset() - - global tunedata - - t = tunedata.run{tunedata.runIndex}.global_opts.dnp.durations; - -% qc.get_pulse_duration(... -% qc.struct_to_pulse(tunedata.run{tunedata.runIndex}.global_opts.dnp.scan.configfn(4).args{end}.pulse_template), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); - -% t_pumpingPart = qc.get_pulse_duration(... -% qc.load_pulse('dnp_ABCD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% -% t_s_AB = qc.get_pulse_duration(... -% qc.load_pulse('s_pumping_AB_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_cs_AB = qc.get_pulse_duration(... -% qc.load_pulse('t_pumping_AB_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_t_AB = qc.get_pulse_duration(... -% qc.load_pulse('cs_pumping_AB_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% -% t_s_CD = qc.get_pulse_duration(... -% qc.load_pulse('s_pumping_CD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_t_CD = qc.get_pulse_duration(... -% qc.load_pulse('t_pumping_CD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); -% t_cs_CD = qc.get_pulse_duration(... -% qc.load_pulse('cs_pumping_CD_4chan'), ... -% qc.join_params_and_dicts('common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34').... -% ); - - pumpConf = tunedata.run{1}.global_opts.dnp.pumpingConfigArgs.currentConfig; - - t.current_dnp_pulse = ... - t.s_AB * double(pumpConf.n_s_AB) + ... - t.t_AB * double(pumpConf.n_t_AB) + ... - t.cs_AB * double(pumpConf.n_cs_AB) + ... - t.s_CD * double(pumpConf.n_s_CD) + ... - t.t_CD * double(pumpConf.n_t_CD) + ... - t.cs_CD * double(pumpConf.n_cs_CD); - - currentPulseDurationOffset = t.current_dnp_pulse - t.dict_dnp_pulse; - -end \ No newline at end of file diff --git a/MATLAB/+qc/get_minimal_program.m b/MATLAB/+qc/get_minimal_program.m deleted file mode 100644 index 43c6c8241..000000000 --- a/MATLAB/+qc/get_minimal_program.m +++ /dev/null @@ -1,24 +0,0 @@ -function reduced_program = get_minimal_program(program) - % Return program with all parameters not needed by its pulse template - % removed - - pulse_template = qc.struct_to_pulse(program.pulse_template); - parameter_names = util.py.py2mat(pulse_template.parameter_names); - - program.parameters_and_dicts = qc.join_params_and_dicts(program.parameters_and_dicts); - reduced_program = program; - - % amplitude_at_upload is only used to keep track of the AWG amplitude if - % it was dynamically changed. - if isfield(reduced_program, 'amplitudes_at_upload') - reduced_program = rmfield(reduced_program, 'amplitudes_at_upload'); - end - - reduced_program.parameters_and_dicts = struct(); - % Remove all fields in parameters_and_dicts not needed by pulse_template - for p = parameter_names - reduced_program.parameters_and_dicts.(p{1}) = program.parameters_and_dicts.(p{1}); - end - - - \ No newline at end of file diff --git a/MATLAB/+qc/get_optimal_awg_time.m b/MATLAB/+qc/get_optimal_awg_time.m deleted file mode 100644 index 858a277d5..000000000 --- a/MATLAB/+qc/get_optimal_awg_time.m +++ /dev/null @@ -1,24 +0,0 @@ -function [optimalTime, addTime, optimalNsamp] = get_optimal_awg_time(desiredTime, sampleRate) - % Tabor AWG closest optimal number of samples: sampleQuantum + n*sampleQuantum - % Time is in s, sampleRate is in Sa/s - - global plsdata - - sampleQuantum = plsdata.awg.sampleQuantum; - minSamples = plsdata.awg.minSamples; - - global plsdata - if nargin < 2 || isempty(sampleRate) - sampleRate = plsdata.awg.sampleRate; - end - - desiredNsamp = desiredTime*sampleRate; - - if desiredNsamp <= minSamples - optimalNsamp = minSamples; - else - optimalNsamp = minSamples + sampleQuantum*round((desiredNsamp-minSamples)/sampleQuantum); - end - - optimalTime = optimalNsamp / sampleRate; - addTime = optimalTime - desiredTime; \ No newline at end of file diff --git a/MATLAB/+qc/get_optimal_pulse_time.m b/MATLAB/+qc/get_optimal_pulse_time.m deleted file mode 100644 index f11d48c4b..000000000 --- a/MATLAB/+qc/get_optimal_pulse_time.m +++ /dev/null @@ -1,10 +0,0 @@ -function [optimalTime, addTime, optimalNsamp, actualTime] = get_optimal_pulse_time(pulse, varargin) - - if ischar(pulse) - pulse = qc.load_pulse(pulse); - end - - actualTime = qc.get_pulse_duration(pulse, qc.join_params_and_dicts(varargin{:})); - [optimalTime, addTime, optimalNsamp] = qc.get_optimal_awg_time(actualTime); - - \ No newline at end of file diff --git a/MATLAB/+qc/get_program.m b/MATLAB/+qc/get_program.m deleted file mode 100644 index f5d0a79c8..000000000 --- a/MATLAB/+qc/get_program.m +++ /dev/null @@ -1,12 +0,0 @@ -function [program, channels] = get_program(pulse, varargin) - - if ischar(pulse) - pulse = qc.load_pulse(pulse); - end - - instantiated_pulse = qc.instantiate_pulse(pulse, 'parameters', qc.join_params_and_dicts(varargin{:})); - - tmp = py.qctoolkit.hardware.program.MultiChannelProgram(instantiated_pulse); - program = py.next(py.iter(tmp.programs.values())); - channels = py.next(py.iter(tmp.programs.keys())); - \ No newline at end of file diff --git a/MATLAB/+qc/get_pulse_duration.m b/MATLAB/+qc/get_pulse_duration.m deleted file mode 100644 index 50aaaa154..000000000 --- a/MATLAB/+qc/get_pulse_duration.m +++ /dev/null @@ -1,15 +0,0 @@ -function pulse_length = get_pulse_duration(pulse_template, parameters) - % Return pulse length in s - - kwargs = cell2namevalpairs(fieldnames(parameters), struct2cell(parameters)); - pulse_length = py.getattr(pulse_template, 'duration').evaluate_numeric(pyargs(kwargs{:}))*1e-9; - - -function cellarr = cell2namevalpairs(field_names, values) - cellarr={}; - for k = 1:numel(field_names) - cellarr{end+1}=field_names{k}; - cellarr{end+1}=values{k}; - end - - \ No newline at end of file diff --git a/MATLAB/+qc/get_pulse_params.m b/MATLAB/+qc/get_pulse_params.m deleted file mode 100644 index 210a67ada..000000000 --- a/MATLAB/+qc/get_pulse_params.m +++ /dev/null @@ -1,9 +0,0 @@ -function pulseParameters = get_pulse_params(pulse_name_or_template) - - if ischar(pulse_name_or_template) - pulse_template = qc.load_pulse(pulse_name_or_template); - else - pulse_template = pulse_name_or_template; - end - pulseParameters = sort(util.py.py2mat(pulse_template.parameter_names)); - \ No newline at end of file diff --git a/MATLAB/+qc/get_pumping_from_awg.m b/MATLAB/+qc/get_pumping_from_awg.m deleted file mode 100644 index 605c7b81b..000000000 --- a/MATLAB/+qc/get_pumping_from_awg.m +++ /dev/null @@ -1,68 +0,0 @@ -function pumpingConfig = get_pumping_from_awg(varargin) - -global plsdata - -defaultArgs = struct(... - 'programName', plsdata.awg.currentProgam ... - ); -args = util.parse_varargin(varargin, defaultArgs); - -pumpingConfig = struct(); - -seqTable = qc.get_sequence_table(args.programName, false); -seqTableCheck = true; -report = ''; -pumpSubTab = seqTable{1}{end}; - - - - - -%---------------- some checks --------------------------------------------- - -%check if there are six entries for the three pumping types for each qubit -if length(pumpSubTab) < 6 - seqTableCheck = false; - report = ' -- There are not six waveforms at the end of the sequence table! They might be put together or not uploaded or not at the end of the sequence table. -- '; -end - -%test if every waveform is different/has a different -if seqTableCheck - for i = 0:5 - for j = 0:5 - if (i~=j) && (pumpSubTab{end-i}{2} == pumpSubTab{end-j}{2}) - report = ' -- Not all waveforms for pumping (that are assumed to be different) are different to each other! -- '; - seqTableCheck = false; - end - end - end -end - -%test if both channel pairs have the same pumping sequence table part -for i = 1:6 - if seqTableCheck && ~isequal(seqTable{1}{end}{end-i+1}, seqTable{2}{end}{end-i+1}) - report = ' -- Not the same pumping configuration on both channel pairs of the AWG! -- '; - seqTableCheck = false; - end -end - - - - -%------------- reading out the pumping configuration ---------------------- - -if ~seqTableCheck - warning(report); -else - pumpingConfig.n_s_AB = pumpSubTab{end-5}{1}; - pumpingConfig.n_t_AB = pumpSubTab{end-4}{1}; - pumpingConfig.n_cs_AB = pumpSubTab{end-3}{1}; - pumpingConfig.n_s_CD = pumpSubTab{end-2}{1}; - pumpingConfig.n_t_CD = pumpSubTab{end-1}{1}; - pumpingConfig.n_cs_CD = pumpSubTab{end-0}{1}; -end - - - - -end \ No newline at end of file diff --git a/MATLAB/+qc/get_segment_waveform.m b/MATLAB/+qc/get_segment_waveform.m deleted file mode 100644 index 8526e4906..000000000 --- a/MATLAB/+qc/get_segment_waveform.m +++ /dev/null @@ -1,53 +0,0 @@ -function [wf1, wf2] = get_segment_waveform(program_name, channel_pair_index, memory_index, awg_channel_pair_identifiers) -% Get Wafeform of Sequencer Table Element -% PLEASE NOTE: works only for the Tabor AWG SIMULATOR -% PLEASE NOTE: program gets armed by calling this function -% -% --- Outputs ------------------------------------------------------------- -% wf1 : first channel y-values of AWG channelpair -% wf2 : second channel y-values of AWG channelpair -% -% --- Inputs -------------------------------------------------------------- -% program_name : Program name for which wafeform is -% returned -% channel_pair_index : 1 for channelpair AB and 2 for channelpair -% CD. Also see awg_channel_pair_identifier -% input -% memory_index : identifier number of element at the Tabor -% AWG (corresponds to second column in -% Sequencer Table -% awg_channel_pair_identifiers : Some substring in the channel pair -% identifiers to be matched. Sequence tables -% are sorted in the same order as channel -% pair identifiers substrings passed in this -% variable. Default is {'AB', 'CD'}. -% -% ------------------------------------------------------------------------- -% 2018/08 Marcel Meyer -% (marcel.meyer1@rwth-aachen.de) - -global plsdata - hws = plsdata.awg.hardwareSetup; - - if nargin < 4 || isempty(awg_channel_pair_identifiers) - awg_channel_pair_identifiers = {'AB', 'CD'}; - end - - known_awgs = util.py.py2mat(hws.known_awgs); - sort_indices = cellfun(@(x)(find( cellfun(@(y)(~isempty(strfind(char(x.identifier), y))), awg_channel_pair_identifiers) )), known_awgs); - known_awgs = known_awgs(sort_indices); - - %one has to arm the program to access the plottableProgram object of the - %program - known_awgs{channel_pair_index}.arm(program_name); - - plottableProgram = known_awgs{channel_pair_index}.read_complete_program(); - - wf1 = plottableProgram.get_segment_waveform(uint8(0), uint8(memory_index)); - wf2 = plottableProgram.get_segment_waveform(uint8(1), uint8(memory_index)); - - wf1 = util.py.py2mat(wf1); - wf2 = util.py.py2mat(wf2); - - wf1 = cell2mat(wf1); - wf2 = cell2mat(wf2); \ No newline at end of file diff --git a/MATLAB/+qc/get_sequence_table.m b/MATLAB/+qc/get_sequence_table.m deleted file mode 100644 index 489c6e835..000000000 --- a/MATLAB/+qc/get_sequence_table.m +++ /dev/null @@ -1,91 +0,0 @@ -function seq_table = get_sequence_table(program_name, advanced_seq_table_flag, awg_channel_pair_identifiers, verbosity, return_python_list) -% GET_SEQUENCE_TABLE Get sequence table of program on Tabor AWG -% (not actually from AWG but from the qctoolkit Tabor Driver instance) -% -% --- Outputs ------------------------------------------------------------- -% seq_table : Cell of sequence tables for each Tabor -% channel pair -% -% --- Inputs -------------------------------------------------------------- -% program_name : Program name for which sequence table is -% returned -% advanced_seq_table_flag : Get advanced sequence table if true. -% Default is false. -% awg_channel_pair_identifiers : Some substring in the channel pair -% identifiers to be matched. Sequence tables -% are sorted in the same order as channel -% pair identifiers substrings passed in this -% variable. Default is {'AB', 'CD'}. -% verbosity : Print sequence table to command line. -% Default is 0. -% return_python_list : Returns a python list object instead of a -% matlab cell. This makes the function -% faster as the conversion is slow. -% Dafault is false. -% -% ------------------------------------------------------------------------- -% (c) 2018/06 Pascal Cerfontaine and Marcel Meyer -% (cerfontaine@physik.rwth-aachen.de) - -global plsdata -hws = plsdata.awg.hardwareSetup; - -if nargin < 2 || isempty(advanced_seq_table_flag) - advanced_seq_table_flag = false; -end -if nargin < 3 || isempty(awg_channel_pair_identifiers) - awg_channel_pair_identifiers = {'AB', 'CD'}; -end -if nargin < 4 || isempty(verbosity) - verbosity = 0; -end -if nargin < 5 || isempty(return_python_list) - return_python_list = false; -end -if advanced_seq_table_flag - seq_txt = 'A'; -else - seq_txt = ''; -end - -known_awgs = util.py.py2mat(hws.known_awgs); -sort_indices = cellfun(@(x)(find( cellfun(@(y)(~isempty(strfind(char(x.identifier), y))), awg_channel_pair_identifiers) )), known_awgs); -known_awgs = known_awgs(sort_indices); - -for k = 1:length(known_awgs) - known_programs{k} = util.py.py2mat(py.getattr(known_awgs{k}, '_known_programs')); - - if verbosity > 0 - util.disp_section(sprintf('%s %sST: %s', awg_channel_pair_identifiers{k}, seq_txt, program_name)); - end - - if isfield(known_programs{k}, program_name) - tabor_program{k} = known_programs{k}.(program_name){2}; - - if advanced_seq_table_flag - seq_table{k} = py.getattr(tabor_program{k}, '_advanced_sequencer_table'); - else - seq_table{k} = py.getattr(tabor_program{k}, '_sequencer_tables'); - end - - if verbosity > 0 - disp(seq_table{k}); - end - - if ~return_python_list - seq_table{k} = util.py.py2mat(seq_table{k}); - end - else - tabor_program{k} = {}; - seq_table{k} = {}; - - if verbosity > 0 - disp(' Program not present'); - end - end -end - -if verbosity > 0 - fprintf('\n'); - util.disp_section(); -end diff --git a/MATLAB/+qc/get_sequence_table_from_simulator.m b/MATLAB/+qc/get_sequence_table_from_simulator.m deleted file mode 100644 index 776584024..000000000 --- a/MATLAB/+qc/get_sequence_table_from_simulator.m +++ /dev/null @@ -1,99 +0,0 @@ -function seq_table = get_sequence_table_from_simulator(program_name, advanced_seq_table_flag, awg_channel_pair_identifiers, verbosity, return_python_list) -% GET_SEQUENCE_TABLE Get sequence table of program on Tabor AWG Simulator -% PLEASE NOTE: the program gets armed by the function -% -% --- Outputs ------------------------------------------------------------- -% seq_table : Cell of sequence tables for each Tabor -% channel pair -% -% --- Inputs -------------------------------------------------------------- -% program_name : Program name for which sequence table is -% returned -% advanced_seq_table_flag : Get advanced sequence table if true. -% Default is false. -% awg_channel_pair_identifiers : Some substring in the channel pair -% identifiers to be matched. Sequence tables -% are sorted in the same order as channel -% pair identifiers substrings passed in this -% variable. Default is {'AB', 'CD'}. -% verbosity : Print sequence table to command line. -% Default is 0. -% return_python_list : Returns a python list object instead of a -% matlab cell. This makes the function -% faster as the conversion is slow. -% Dafault is false. -% -% ------------------------------------------------------------------------- -% 2018/08 Marcel Meyer -% based on qc.get_sequence_table by Pascal Cerfontaine and Marcel Meyer -% (marcel.meyer1@rwth-aachen.de) - - global plsdata - hws = plsdata.awg.hardwareSetup; - - if nargin < 2 || isempty(advanced_seq_table_flag) - advanced_seq_table_flag = false; - end - if nargin < 3 || isempty(awg_channel_pair_identifiers) - awg_channel_pair_identifiers = {'AB', 'CD'}; - end - if nargin < 4 || isempty(verbosity) - verbosity = 0; - end - - if nargin < 5 || isempty(return_python_list) - return_python_list = false; - end - - if advanced_seq_table_flag - seq_txt = 'A'; - else - seq_txt = ''; - end - - known_awgs = util.py.py2mat(hws.known_awgs); - sort_indices = cellfun(@(x)(find( cellfun(@(y)(~isempty(strfind(char(x.identifier), y))), awg_channel_pair_identifiers) )), known_awgs); - known_awgs = known_awgs(sort_indices); - - for k = 1:length(known_awgs) - known_programs{k} = util.py.py2mat(py.getattr(known_awgs{k}, '_known_programs')); - - if verbosity > 0 - util.disp_section(sprintf('%s %sST: %s', awg_channel_pair_identifiers{k}, seq_txt, program_name)); - end - - if isfield(known_programs{k}, program_name) - - % one has to arm the program before accessing its plottableProgram - % object - known_awgs{k}.arm(program_name); - plottableProgram = known_awgs{k}.read_complete_program(); - - if advanced_seq_table_flag - seq_table{k} = py.getattr(plottableProgram, '_advanced_sequence_table'); - else - seq_table{k} = py.getattr(plottableProgram, '_sequence_tables'); - end - - if verbosity > 0 - disp(seq_table{k}); - end - - if ~return_python_list - seq_table{k} = util.py.py2mat(seq_table{k}); - end - - else - tabor_program{k} = {}; - seq_table{k} = {}; - - if verbosity > 0 - disp(' Program not present'); - end - end - end - -if verbosity > 0 - fprintf('\n'); - util.disp_section(); -end \ No newline at end of file diff --git a/MATLAB/+qc/instantiate_pulse.m b/MATLAB/+qc/instantiate_pulse.m deleted file mode 100644 index 9e91c397c..000000000 --- a/MATLAB/+qc/instantiate_pulse.m +++ /dev/null @@ -1,44 +0,0 @@ -function instantiated_pulse = instantiate_pulse(pulse, varargin) - % Plug in parameters - - if qc.is_instantiated_pulse(pulse) - instantiated_pulse = pulse; - - else - default_args = struct(... - 'parameters', py.None, ... - 'channel_mapping', py.None, ... - 'window_mapping' , py.None, ... - 'global_transformation', [], ... - 'to_single_waveform', py.set() ... - ); - - args = util.parse_varargin(varargin, default_args); - - args.channel_mapping = replace_empty_with_pynone(args.channel_mapping); - args.window_mapping = replace_empty_with_pynone(args.window_mapping); - args.global_transformation = qc.to_transformation(args.global_transformation); - - kwargs = pyargs( ... - 'parameters' , args.parameters, ... - 'channel_mapping', args.channel_mapping, ... - 'measurement_mapping' , args.window_mapping, ... - 'global_transformation', args.global_transformation, ... - 'to_single_waveform', args.to_single_waveform ... - ); - - instantiated_pulse = util.py.call_with_interrupt_check(py.getattr(pulse, 'create_program'), kwargs); - end -end - - -function mappingStruct = replace_empty_with_pynone(mappingStruct) - - for fn = fieldnames(mappingStruct)' - if isempty(mappingStruct.(fn{1})) - mappingStruct.(fn{1}) = py.None; - end - end - -end - diff --git a/MATLAB/+qc/is_dict.m b/MATLAB/+qc/is_dict.m deleted file mode 100644 index 4e37478c7..000000000 --- a/MATLAB/+qc/is_dict.m +++ /dev/null @@ -1,4 +0,0 @@ -function bool = is_dict(dp) - delim = '___'; - bool = ischar(dp) || (isstruct(dp) && isfield(dp, strcat('dict', delim, 'name'))); -end \ No newline at end of file diff --git a/MATLAB/+qc/is_instantiated_pulse.m b/MATLAB/+qc/is_instantiated_pulse.m deleted file mode 100644 index 6d4d394e3..000000000 --- a/MATLAB/+qc/is_instantiated_pulse.m +++ /dev/null @@ -1,3 +0,0 @@ -function bool = is_instantiated_pulse(pulse) - bool = strcmp(class(pulse), 'py.qctoolkit._program.instructions.ImmutableInstructionBlock'); - bool = bool || strcmp(class(pulse), 'py.qctoolkit._program._loop.Loop'); diff --git a/MATLAB/+qc/join_params_and_dicts.m b/MATLAB/+qc/join_params_and_dicts.m deleted file mode 100644 index a80f58d6e..000000000 --- a/MATLAB/+qc/join_params_and_dicts.m +++ /dev/null @@ -1,62 +0,0 @@ -function parameters = join_params_and_dicts(varargin) - % Each argument is either a dictionary name as a string, a dictionary - % struct or a parameter struct. This function joins all input arguments to - % a single parameters struct. If conflicts occur, the field of the rightmost - % argument takes precedence. - % - % Dictionaries are saved as json files in the repository qctoolkit-dicts. - % Each dictionary is a struct with a field for each pulse. The field names - % are the same as the pulse names (as pulse names are unique identifiers). - % Each field has subfields which store pulse parameters for that pulse. - % - % When defining pulses in qctoolkit, prefix each parameter name with the - % pulsename followed by three underscores. I.e. for a pules 'meas' the - % parameter 'waiting_time' should be called 'meas___waiting_time'. The - % dictionary however should only have the parameter field 'waiting_time', - % i.e struct('meas', struct('waiting_time', 1)). - % - % Each dictionary also has a global field which also contains a struct. The - % field names of this struct refer to parameters which can be set to the - % same value across different pulses in the same dictionary. For example - % struct('global', struct('waiting_time', 1)) will set the parameter - % 'waiting_time' to 1 for all pulses which have the parameter - % 'waiting_time' in the dictionary where the global is defined. - % - % Globals do not take precedence over parameters passed in more to the - % right. - % - % Each dictionary also has a field 'dict___name' which specifies - % the dictionary name - - if numel(varargin) == 1 && iscell(varargin{1}) - p = varargin{1}; - else - p = varargin; - end - p = cellfun(@qc.load_dict, p, 'UniformOutput', false); - p = cellfun(@qc.dict_apply_globals, p, 'UniformOutput', false); - p = cellfun(@qc.dict_to_parameter_struct, p, 'UniformOutput', false); - - parameters = struct(); - for k = 1:numel(p) - parameters = join(parameters, p{k}); - end - - parameters = qc.array2row(parameters); - parameters = orderfields(parameters); - -end - - -function p = join(p1, p2) - % Join two parameter structs. This process is additive, fields in p2 take - % precedence - p = p1; - - for paramName = fieldnames(p2)' - p.(paramName{1}) = p2.(paramName{1}); - end -end - - - diff --git a/MATLAB/+qc/join_structs.m b/MATLAB/+qc/join_structs.m deleted file mode 100644 index fd8e8ab2d..000000000 --- a/MATLAB/+qc/join_structs.m +++ /dev/null @@ -1,17 +0,0 @@ -function S = join_structs(varargin) - % Fields of arguments passed in more on the left get overwritten by - % arguments passed in more to the right - - S = struct(); - for v = varargin - S = join_2_structs(S, v{1}); - end - -end - -function A = join_2_structs(A, B) - % Fields in B are added to A, fields in A with same name get overwritten - for f = fieldnames(B).' - A.(f{1}) = B.(f{1}); - end -end \ No newline at end of file diff --git a/MATLAB/+qc/load_dict.m b/MATLAB/+qc/load_dict.m deleted file mode 100644 index 100bcf164..000000000 --- a/MATLAB/+qc/load_dict.m +++ /dev/null @@ -1,56 +0,0 @@ -function dict_string_or_struct = load_dict(dict_string_or_struct, create_dict) - % Load dict if d is a string. Otherwise leave d untouched. - % - % Important: this does not (re)load a dict if the passed in variable is - % already a struct. - % - % You can specifiy a suffix to be appended to all pulse names in the - % dictionary separated by a space, i.e. if the dictionary name is - % 'common' you can pass 'common d12' and '_d12' will be appended to each - % pulse name. - - global plsdata - delim = '___'; - - if nargin < 2 || isempty(create_dict) - create_dict = false; - end - create_dict = create_dict || isempty(dict_string_or_struct); - - if ischar(dict_string_or_struct) - dict_string_or_struct = strsplit(dict_string_or_struct, ' '); - - if numel(dict_string_or_struct) > 1 - suffix = ['_' dict_string_or_struct{2}]; - else - suffix = ''; - end - dict_string_or_struct = dict_string_or_struct{1}; - - file_name = fullfile(plsdata.dict.path, [dict_string_or_struct '.json']); - if exist(file_name, 'file') - text = fileread(file_name); - dict_string_or_struct = jsondecode(text); - dict_string_or_struct = qc.array2row(dict_string_or_struct); - elseif create_dict - if strcmp(suffix, '') - dict_string_or_struct = struct(strcat('dict', delim, 'name'), dict_string_or_struct, 'global', struct()); - else - error('Cannot create dictionary ''%s %s'' since it contains a space', dict_string_or_struct, suffix(2:end)); - end - else - error('Dictionary ''%s'' does not exist', dict_string_or_struct); - end - - if ~strcmp(suffix, '') - for fn = fieldnames(dict_string_or_struct)' - if ~strcmp(fn{1}, strcat('dict', delim, 'name')) && ~strcmp(fn{1}, 'global') - dict_string_or_struct.([fn{1} suffix]) = dict_string_or_struct.(fn{1}); - dict_string_or_struct = rmfield(dict_string_or_struct, fn{1}); - end - end - end - - end - -end \ No newline at end of file diff --git a/MATLAB/+qc/load_pulse.m b/MATLAB/+qc/load_pulse.m deleted file mode 100644 index 4c651bb92..000000000 --- a/MATLAB/+qc/load_pulse.m +++ /dev/null @@ -1,4 +0,0 @@ -function pulse = load_pulse(pulse_name) - - global plsdata - pulse = plsdata.qc.pulse_storage{pulse_name}; \ No newline at end of file diff --git a/MATLAB/+qc/operations_to_python.m b/MATLAB/+qc/operations_to_python.m deleted file mode 100644 index 5790f0b5d..000000000 --- a/MATLAB/+qc/operations_to_python.m +++ /dev/null @@ -1,34 +0,0 @@ -function pyOperations = operations_to_python(operations) - % Convert operations struct from matlab to python - - pyOperations = {}; - - for k = 1:numel(operations) - - if numel(operations{k}) > 1 - args = operations{k}(2:end); - else - args = {}; - end - switch(operations{k}{1}) - case 'AlgebraicMoment' - pyOp = py.atsaverage.operations.AlgebraicMoment(args{:}); - case 'Downsample' - pyOp = py.atsaverage.operations.Downsample(args{:}); - case 'Histogram' - pyOp = py.atsaverage.operations.Histogram(args{:}); - case 'RepAverage' - pyOp = py.atsaverage.operations.RepAverage(args{:}); - case 'RepeatedDownsample' - pyOp = py.atsaverage.operations.RepeatedDownsample(args{:}); - otherwise - error('Operation %s not recognized', operations{k}{1}); - end - pyOperations{end+1} = pyOp; - - end - - pyOperations = py.list(pyOperations); - - - diff --git a/MATLAB/+qc/params_add_delim.m b/MATLAB/+qc/params_add_delim.m deleted file mode 100644 index dca1ed276..000000000 --- a/MATLAB/+qc/params_add_delim.m +++ /dev/null @@ -1,9 +0,0 @@ -function parameters = params_add_delim(parameters, pulse_name) - % Prefix all parameters in pulseTemplate with the pulse name followed by - % three underscores (needed for dictionaries). - - delim = '___'; - for fn = fieldnames(parameters)' - parameters.(strcat(pulse_name, delim, fn{1})) = parameters.(fn{1}); - parameters = rmfield(parameters, fn{1}); - end \ No newline at end of file diff --git a/MATLAB/+qc/params_rm_delim.m b/MATLAB/+qc/params_rm_delim.m deleted file mode 100644 index 6a498e4af..000000000 --- a/MATLAB/+qc/params_rm_delim.m +++ /dev/null @@ -1,13 +0,0 @@ -function [parameters, pulse_name] = params_rm_delim(parameters) - % Remove prefix from parameters identified by three underscores - % (needed for dictionaries). - - delim = '___'; - fn = fieldnames(parameters)'; - [i1, i2] = regexp(fn{1}, '^.+___'); - pulse_name = fn{1}(i1:i2-numel(delim)); - - for fn = fieldnames(parameters)' - parameters.(fn{1}(i2+1:end)) = parameters.(fn{1}); - parameters = rmfield(parameters, fn{1}); - end \ No newline at end of file diff --git a/MATLAB/+qc/personalPaths_README.txt b/MATLAB/+qc/personalPaths_README.txt deleted file mode 100644 index ee36d7590..000000000 --- a/MATLAB/+qc/personalPaths_README.txt +++ /dev/null @@ -1,22 +0,0 @@ -README path file for qc.qctoolkitTestSetup ------------------------------------------- -written by M. Meyer 10|2018 - - -Run the following code after inserting paths to create a path file. The generated file should be on the git ignore list. - - -%% ---------------------------- -a = struct(); -a.pulses_repo = ''; -a.dicts_repo = ''; -a.loadPath = ''; -a.tunePath = ''; -a.loadFile = ''; -a.taborDriverPath = ''; - -quPulsePath = '...\qc-toolkit\MATLAB\+qc'; - -personalPathsStruct = a; -save([pathFile_save_path '\personalPaths'], personalPathsStruct); -%% ----------------------------- \ No newline at end of file diff --git a/MATLAB/+qc/plot_program_tree.m b/MATLAB/+qc/plot_program_tree.m deleted file mode 100644 index 960e12358..000000000 --- a/MATLAB/+qc/plot_program_tree.m +++ /dev/null @@ -1,60 +0,0 @@ -function plot_program_tree(program, maxElements, figId) - % Modified from Wolfie at - % https://stackoverflow.com/questions/45666560/ploting-a-nested-cell-as-a-tree-using-treeplot-matlab/45676012 - - if nargin < 2 || isempty(maxElements) - maxElements = 10; - end - if nargin < 3 || isempty(figId) - figId = 120; - end - - [treearray, nodeVals] = getTreeArray(program, maxElements); - - figure(figId); clf; - treeplot(treearray); - title(sprintf(['Duration %g' 10 'Showing first %g entries'], double(program.duration.numerator/program.duration.denominator), maxElements)) - - % Get the position of each node on the plot - [x, y] = treelayout(treearray); - - % Get the indices of the nodes which have values stored - nodeIndices = cell2mat(nodeVals(1,:)); - - % Get the labels (values) corresponding to those nodes. Must be strings in cell array - labels = cellfun(@(x)(double(x.repetition_count)), nodeVals(2,:), 'uniformoutput', 0); - - % Add labels, with a vertical offset to the y coords so that labels don't sit on nodes - text(x(nodeIndices), y(nodeIndices) - 0.03, labels); - -end - -function [treearray, nodeVals] = getTreeArray(program, maxElements) - % Initialise the array construction from node 0 - - children = program.children(1:min(maxElements, end)); - - [nodes, ~, nodeVals] = treebuilder(children, 1); - treearray = [0, nodes]; - nodeVals(:, end+1) = {1; program}; - - % Recursive tree building function - function [nodes, currentNode, nodeVals] = treebuilder(children, rootNode) - % Set up variables to be populated whilst looping - nodes = []; nodeVals = {}; - - % Start node off at root node - currentNode = rootNode; - - % Loop over array elements, either recurse or add node - for ii = 1:min(size(children, 2)) - currentNode = currentNode + 1; - try - nodeVals = [nodeVals, {currentNode; children{ii}}]; - [subtreeNodes, currentNode, newNodeVals] = treebuilder(children{ii}.children, currentNode); - nodes = [nodes, rootNode, subtreeNodes]; - nodeVals = [nodeVals, newNodeVals]; - end - end - end -end \ No newline at end of file diff --git a/MATLAB/+qc/plot_pulse.m b/MATLAB/+qc/plot_pulse.m deleted file mode 100644 index f63c67b42..000000000 --- a/MATLAB/+qc/plot_pulse.m +++ /dev/null @@ -1,178 +0,0 @@ -function [t, channels, measurements, instantiatedPulse] = plot_pulse(pulse, varargin) - - global plsdata - - defaultArgs = struct(... - 'sample_rate', plsdata.awg.sampleRate, ... % in 1/s, converted to 1/ns below - 'channel_names', {{}}, ... % names of channels to plot, all if empty - 'parameters', struct(), ... - 'channel_mapping', [], ... - 'window_mapping' , py.None, ... - 'fig_id', plsdata.qc.figId, ... - 'subplots', [121 122], ... - 'charge_diagram_data', {{}}, ... % inputs to imagesc - 'clear_fig', true, ... - 'charge_diagram', {{'X', 'Y'}}, ... - 'plot_charge_diagram', true, ... - 'lead_points', 1e-3*[-4 -1; -1 -2; 0 -4; 4 0; 2 1; 1 4], ... - 'special_points', struct('M', [0 0], 'R1', [-2.5e-3 -3.75e-3], 'R2', [-2e-3 1e-3], 'S', [-2e-3 -1e-3], 'Tp', [1.75e-3 0], 'STp', [1e-3 -1e-3]), ... - 'plot_range', [-8e-3 8e-3], ... - 'max_n_points', 1e5,... - 'dont_plot', false ... - ); - - args = util.parse_varargin(varargin, defaultArgs); - - if isempty(args.channel_mapping) - args.channel_mapping = py.dict(py.zip(pulse.defined_channels, pulse.defined_channels)); - end - - args.sample_rate = args.sample_rate * 1e-9; % convert to 1/ns - instantiatedPulse = qc.instantiate_pulse(pulse, 'parameters', args.parameters, 'channel_mapping', args.channel_mapping, 'window_mapping', args.window_mapping); - - if ~qc.is_instantiated_pulse(pulse) - nPoints = qc.get_pulse_duration(pulse, args.parameters) * args.sample_rate * 1e9; - if nPoints > args.max_n_points - warning('Number of points %g > %g (maximum number of points). Aborting.\n', ceil(nPoints), args.max_n_points); - return - end - end - - try - data = util.py.py2mat(py.qctoolkit.pulses.plotting.render(instantiatedPulse, pyargs('sample_rate', args.sample_rate, 'render_measurements', true))); - catch err - warning('The following error occurred when plotting. This might have to do with Python dicts not being convertable to Matlab because of illegal struct field name:\n%s', err.getReport()) - end - - t = data{1}*1e-9; - - channels = data{2}; - if ~isempty(args.plot_range) - for chan_name = fieldnames(channels)' - channels.(chan_name{1}) = util.clamp(channels.(chan_name{1}), args.plot_range); - end - end - measurements = struct(); - for m = data{3} - if ~isfield(measurements, m{1}{1}) - measurements.(m{1}{1}) = []; - end - if strcmp(class(m{1}{2}), 'py.fractions.Fraction') - m{1}{2} = m{1}{2}.numerator/m{1}{2}.denominator; - end - if strcmp(class(m{1}{3}), 'py.fractions.Fraction') - m{1}{3} = m{1}{3}.numerator/m{1}{3}.denominator; - end - measurements.(m{1}{1})(end+1, 1:2) = [m{1}{2} m{1}{2}+m{1}{3}] * 1e-9; - end - - if args.dont_plot - return; - end - - plotChargeDiagram = args.plot_charge_diagram && ~isempty(args.charge_diagram) && all(cellfun(@(x)(isfield(channels, x)), args.charge_diagram)); - - hFig = figure(args.fig_id); - if ~qc.is_instantiated_pulse(pulse) - pulseName = sprintf('Pulse: %s', char(pulse.identifier)); - else - pulseName = 'Pulse'; - end - set(hFig, 'Name', pulseName); - if args.clear_fig - clf - end - if plotChargeDiagram || numel(args.subplots) == 1 - subplot(args.subplots(1)); - end - hold on - - legendEntries = {}; - legendHandles = []; - - for meas_name = fieldnames(measurements)' - hLines = plot(measurements.(meas_name{1}).', measurements.(meas_name{1}).'*0, 'lineWidth', 100, 'displayName', ['Meas: ' meas_name{1}]); - for h = hLines(:)' - color = rgb2hsv(h.Color); - h.Color = hsv2rgb([color(1) 0.1 1]); - end - legendHandles(end+1) = h(1); - legendEntries{end+1} = ['Meas: ' meas_name{1}]; - end - - for chan_name = fieldnames(channels)' - if isempty(args.channel_names) || any(cellfun(@(x)(strcmp(x, chan_name{1})), args.channel_names)) - h = util.rectplot(t, channels.(chan_name{1}), '.-'); - legendHandles(end+1) = h(1); - legendEntries{end+1} = ['Chan: ' chan_name{1}]; - end - end - - if ~isempty(args.plot_range) - title(['Plot range: ' sprintf('%g ', args.plot_range)]); - end - xlabel('t(s)'); - [~, hObj] = legend(legendHandles, legendEntries); - hObj = findobj(hObj, 'type', 'line'); - set(hObj, 'lineWidth', 2); - - if plotChargeDiagram - subplot(args.subplots(2)); - hold on - ax = gca; - userData = get(ax, 'userData'); - if ~isempty(args.plot_range) - title(['Plot range: ' sprintf('%g ', args.plot_range)]); - end - - if ~isempty(args.charge_diagram_data) - if numel(size(squeeze(args.charge_diagram_data{3}))) == 3 - args.charge_diagram_data{3} = squeeze(nanmean(args.charge_diagram_data{3},1)); - end - imagesc(args.charge_diagram_data{:}); - end - - if isempty(userData) || ~isstruct(userData) || ~isfield(userData, 'leadsPlotted') || ~userData.leadsPlotted - color = [0 0 0 0.1]; - lineWidth = 3; - - if ~isempty(args.lead_points) - plot(args.lead_points(1:3,1), args.lead_points(1:3,2), '-', 'lineWidth', lineWidth, 'color', color); - plot(args.lead_points(4:6,1), args.lead_points(4:6,2), '-', 'lineWidth', lineWidth, 'color', color); - plot(args.lead_points([2 5],1), args.lead_points([2 5],2), '--', 'lineWidth', lineWidth, 'color', color); - - offset = abs(max(args.lead_points(:))-min(args.lead_points(:)))*0.05; - else - offset = 4e-4; - end - - for name = fieldnames(args.special_points)' - xy = args.special_points.(name{1}); - plot(xy(1), xy(2), 'g.', 'markerSize', 24, 'color', color); - text(xy(1), xy(2)+offset, name{1}, 'horizontalAlignment', 'center', 'color', color); - end - - set(gca, 'UserData', struct('leadsPlotted', true)); - end - - x = channels.(args.charge_diagram{1}); - y = channels.(args.charge_diagram{2}); - - ax.ColorOrderIndex = 1; - lineWidth = 1; - h = plot(x, y, '.-', 'markerSize', 8, 'lineWidth', lineWidth); - plot(x(1), y(1), 's', 'markerSize', 12, 'color', h.Color, 'lineWidth', lineWidth); - - dx = diff(x); - dy = diff(y); - r = sqrt(dx.^2 + dy.^2); - - nArrows = min(numel(r), floor(sum(r)/0.5e-3)); - [~, ind] = sort(r); - ind = ind(end-nArrows+1:end); - ind = sort(ind); - - quiver(x(ind), y(ind), dx(ind), dy(ind), 0, 'color', h.Color, 'lineWidth', lineWidth); - end - -end \ No newline at end of file diff --git a/MATLAB/+qc/plot_pulse_4chan.m b/MATLAB/+qc/plot_pulse_4chan.m deleted file mode 100644 index 61680fb99..000000000 --- a/MATLAB/+qc/plot_pulse_4chan.m +++ /dev/null @@ -1,80 +0,0 @@ -function [t, channels, measurements, instantiatedPulse] = plot_pulse_4chan(pulse, varargin) -% PLOT_PULSE_4CHAN Wrapper for plot_pulse specific for plotting pulses for -% two qubits with two control channels each -% -% (c) 2018/06 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de) - -defaultArgs = struct(... - 'charge_diagram_data_structs', {{}}, ... Should contain 2 structs in a cell array with fields x, y - ... and data, where data{1} contains the charge diagram data - 'plot_charge_diagram', true, ... - 'lead_points_cell', {{}}, ... Should contain a cell with a lead_points entry for each qubit - 'special_points_cell', {{}}, ... Should contain a cell with a special_points entry for each qubit - 'channels', {{'W', 'X', 'Y', 'Z'}}, ... - 'measurements', {{'A', 'A', 'B', 'B'}}, ... - 'markerChannels', {{'M1', '', 'M2', ''}} ... - ); -args = util.parse_varargin(varargin, defaultArgs); - - - for chrgInd = 1:2 - k = chrgInd + double(chrgInd==2); - q = 4 - k; - - if numel(args.charge_diagram_data_structs) >= chrgInd - args.charge_diagram_data = args.charge_diagram_data_structs{chrgInd}; - args.charge_diagram_data = {args.charge_diagram_data.x, args.charge_diagram_data.y, args.charge_diagram_data.data{1}}; - else - args.charge_diagram_data = {}; - end - - if numel(args.lead_points_cell) >= chrgInd - args.lead_points = args.lead_points_cell{chrgInd}; - else - args.lead_points = {}; - end - - if numel(args.special_points_cell) >= chrgInd - args.special_points = args.special_points_cell{chrgInd}; - else - args.special_points = {}; - end - - args.charge_diagram = args.channels(k:k+1); - if args.plot_charge_diagram - args.subplots = [220+k 220+k+1]; - else - args.subplots = [210+chrgInd]; - end - args.clear_fig = k==1; - [t, channels, measurements, instantiatedPulse] = qc.plot_pulse(pulse, args); - xlabel(args.channels(k)); - ylabel(args.channels(k+1)); - - if args.plot_charge_diagram - subplot(args.subplots(1)); - end - set(findall(gca, 'DisplayName', sprintf('Chan: %s', args.channels{q})), 'Visible', 'off'); - set(findall(gca, 'DisplayName', sprintf('Chan: %s', args.channels{q+1})), 'Visible', 'off'); - set(findall(gca, 'DisplayName', sprintf('Chan: %s', args.markerChannels{q})), 'Visible', 'off'); - set(findall(gca, 'DisplayName', sprintf('Chan: %s', args.markerChannels{q+1})), 'Visible', 'off'); - set(findall(gca, 'DisplayName', sprintf('Meas: %s', args.measurements{q})), 'Visible', 'off'); - set(findall(gca, 'DisplayName', sprintf('Meas: %s', args.measurements{q+1})), 'Visible', 'off'); - - [hLeg, hObj] = legend(gca); - for l = 1:numel(hLeg.String) - if strcmp(hLeg.String{l}, sprintf('Chan: %s', args.channels{q})) || ... - strcmp(hLeg.String{l}, sprintf('Chan: %s', args.channels{q+1})) || ... - strcmp(hLeg.String{l}, sprintf('Chan: %s', args.markerChannels{q})) || ... - strcmp(hLeg.String{l}, sprintf('Chan: %s', args.markerChannels{q+1})) || ... - strcmp(hLeg.String{l}, sprintf('Meas: %s', args.measurements{q})) || ... - strcmp(hLeg.String{l}, sprintf('Meas: %s', args.measurements{q+1})) - hLeg.String{l} = ''; - end - findobj(hObj, 'type', 'line'); - set(hObj, 'lineWidth', 2); - end - - - -end \ No newline at end of file diff --git a/MATLAB/+qc/plot_tabor_pulse.m b/MATLAB/+qc/plot_tabor_pulse.m deleted file mode 100644 index c6355d39e..000000000 --- a/MATLAB/+qc/plot_tabor_pulse.m +++ /dev/null @@ -1,23 +0,0 @@ -function plot_tabor_pulse(awg) - -program = awg.read_complete_program(); - -wfs = util.py.py2mat(program.get_waveforms()); -reps = util.py.py2mat(program.get_repetitions()); -n_wfs = numel(wfs); - -f = figure; - - - -tabgroup = uitabgroup(mainfig, 'Position', [.05 .1 .9 .8]); - -for k = 1:n_wfs - tab(k)=uitab(tabgroup,'Title', sprintf('Wf_%i', k)); - - axes('parent',tab(k)) - - plot(wfs{k}); - - legend(sprintf('%i times', reps(k))); -end \ No newline at end of file diff --git a/MATLAB/+qc/program_to_struct.m b/MATLAB/+qc/program_to_struct.m deleted file mode 100644 index dfa327195..000000000 --- a/MATLAB/+qc/program_to_struct.m +++ /dev/null @@ -1,36 +0,0 @@ -function program = program_to_struct(program_name, pulse_template, parameters_and_dicts, channel_mapping, window_mapping, global_transformation) - - if ischar(pulse_template) - error('Variable ''pulse_template'' must not be of type char to make sure the correct pulse is saved. Please pass a pulse template.') - end - - % Make sure all dictionaries are loaded so not just saving strings - if ~iscell(parameters_and_dicts) - parameters_and_dicts = {parameters_and_dicts}; - end - parameters_and_dicts = cellfun(@qc.load_dict, parameters_and_dicts, 'UniformOutput', false); - - program = struct( ... - 'program_name', program_name, ... - 'pulse_template', qc.pulse_to_struct(pulse_template), ... - 'parameters_and_dicts', {parameters_and_dicts}, ... - 'channel_mapping', channel_mapping, ... - 'global_transformation', global_transformation, ... - 'window_mapping', window_mapping ... - ); - program.pulse_duration = qc.get_pulse_duration(pulse_template, qc.join_params_and_dicts(program.parameters_and_dicts)); - program.added_to_pulse_duration = 0; - - for name = fieldnames(program.channel_mapping)' - if strcmp(class(program.channel_mapping.(name{1})), 'py.NoneType') - program.channel_mapping.(name{1}) = py.None; - end - end - - for name = fieldnames(program.window_mapping)' - if strcmp(class(program.window_mapping.(name{1})), 'py.NoneType') - program.window_mapping.(name{1}) = py.None; - end - end - - \ No newline at end of file diff --git a/MATLAB/+qc/pulse_add_delim.m b/MATLAB/+qc/pulse_add_delim.m deleted file mode 100644 index a36e82d79..000000000 --- a/MATLAB/+qc/pulse_add_delim.m +++ /dev/null @@ -1,35 +0,0 @@ -function mapped_pulse_template = pulse_add_delim(pulse_template, pulse_name, set_pulse_identifier) - % Prefix all parameters in pulseTemplate with the pulse name followed by - % three underscores (needed for dictionaries). - - if nargin < 3 || isempty(set_pulse_identifier) - set_pulse_identifier = true; - end - - delim = '___'; - parameters = qc.get_pulse_params(pulse_template); - parameter_mapping = cell(1, 2*numel(parameters)); - for k = 1:numel(parameters) - parameter_mapping{1, 2*k-1} = parameters{k}; - parameter_mapping{1, 2*k} = strcat(pulse_name, delim, parameters{k}); - end - parameter_mapping = struct(parameter_mapping{:}); - - if set_pulse_identifier - mapped_pulse_template = py.qctoolkit.pulses.MappingPT( ... - pyargs( ... - 'template', pulse_template, ... - 'identifier', pulse_name, ... - 'parameter_mapping', parameter_mapping, ... - 'allow_partial_parameter_mapping', true ... - ) ... - ); - else - mapped_pulse_template = py.qctoolkit.pulses.MappingPT( ... - pyargs( ... - 'template', pulse_template, ... - 'parameter_mapping', parameter_mapping, ... - 'allow_partial_parameter_mapping', true ... - ) ... - ); - end \ No newline at end of file diff --git a/MATLAB/+qc/pulse_seq.m b/MATLAB/+qc/pulse_seq.m deleted file mode 100644 index d5b206af2..000000000 --- a/MATLAB/+qc/pulse_seq.m +++ /dev/null @@ -1,142 +0,0 @@ -function [pulse, args] = pulse_seq(pulses, varargin) -% PULSE_SEQ Summary -% Dynamically sequence qctoolkit pulses -% -% Note: All SequencePTs in this function are wrapped in a RepetitionPT -% if wrap_in_repetition_pt is true since this might lead to a more efficien -% efficient upload on the Tabor AWG according to Simon Humpohl. However, if -% the upload aborts with the error -% "The algorithm is not smart enough to make sequence tables shorter" -% you can set wrap_in_repetition_pt to false to possibly reduce the -% sequence table length. This will increase the AWG memory requirement. -% -% --- Outputs ------------------------------------------------------------- -% pulse : Sequenced pulse template -% args : Struct of all input arguments, including pulses -% -% --- Inputs -------------------------------------------------------------- -% pulses : Cell of pulse identifiers or pulse templates in sequence order -% varargin : Name-value pairs or struct -% -% ------------------------------------------------------------------------- -% (c) 2018/06 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de) - global plsdata - - defaultArgs = struct( ... - 'repetitions', {num2cell(ones(1, numel(pulses)))}, ... % Repetition for each pulse - 'wrap_in_repetition_pt', true, ... % Wrap each SequencePT in a RepetitionPT with counter 1 - 'outerRepetition', 1, ... % Repetition for entire pulse, set to NaN to use a RepetitionPT with on repetition. - 'fill_time_min', NaN, ... % If not NaN, add fill_time = py.sympy.Max(fill_time, args.fill_time_min). - 'fill_param', '', ... % Not empty: Automatically add fill_pulse to achieve total time given by this parameter. - ... % 'auto': Determine fill time automatically for efficient upload on Tabor AWG - 'fill_pulse_param', 'wait___t', ... % Name of pulse parameter to use for total fill time - 'fill_pulse', 'wait', ... % Pulse template or identifier of pulse to use for filling (added to beginning of pulse sequence) - 'measurements', [], ... % Empty: Do not define any additional readout. - ... % Otherwise: Argument #1 to pyargs('measurements', #1) of SequencePT without fill - 'prefix', '' , ... % Prefix to add to each pulse parameters - 'identifier', '' , ... % Empty: Do not add an identifier - ... % Otherwise: Name of the final pulse - 'sampleRate', plsdata.awg.sampleRate, ... % In SI units (Sa/s), - 'minSamples', plsdata.awg.minSamples, ... % Minimum number of samples for fill pulse - 'sampleQuantum', plsdata.awg.sampleQuantum ... % Sample increments for fill pulse - ); - args = util.parse_varargin(varargin, defaultArgs); - args.pulses = pulses; - args.sampleRate = args.sampleRate/1e9; % in GSa/s - - wrap_in_repetition_pt = args.wrap_in_repetition_pt; - function pt = wrap(pt) - if wrap_in_repetition_pt - pt = py.qctoolkit.pulses.RepetitionPT(pt, 1); - end - end - - % Load and repeat pulses - for k = 1:numel(pulses) - if ischar(pulses{k}) - pulses{k} = qc.load_pulse(pulses{k}); - end - - if any(args.repetitions{k} ~= 1) - pulses{k} = py.qctoolkit.pulses.RepetitionPT(pulses{k}, args.repetitions{k}); - else - pulses{k} = wrap(pulses{k}); - end - end - - % Sequence pulses - if ~isempty(args.measurements) - pulse = wrap(py.qctoolkit.pulses.SequencePT(pulses{:}, pyargs('measurements', args.measurements))); - else - pulse = wrap(py.qctoolkit.pulses.SequencePT(pulses{:})); - end - - % Add fill if fill_param not empty - if ~isempty(args.fill_param) - duration = py.getattr(pulse, 'duration'); - if qc.is_instantiated_pulse(args.fill_pulse) - fill_pulse = args.fill_pulse; - else - fill_pulse = qc.load_pulse(args.fill_pulse); - end - - minDuration = py.sympy.sympify(args.minSamples/args.sampleRate, pyargs('rational', py.True)); - durationQuantum = py.sympy.sympify(args.sampleQuantum/args.sampleRate, pyargs('rational', py.True)); - if strcmp(args.fill_param, 'auto') - fill_time = ... - py.sympy.Max( py.sympy.ceiling(duration.sympified_expression/durationQuantum)*durationQuantum, minDuration ) ... - - duration.sympified_expression; - else - fill_time = py.sympy.Add(py.sympy.sympify(args.fill_param), -duration.sympified_expression); - end - - if ~any(isnan(args.fill_time_min)) - fill_time = py.sympy.Max(fill_time, args.fill_time_min); - end - - fill_pulse = py.qctoolkit.pulses.MappingPT( ... - pyargs( ... - 'template', fill_pulse, ... - 'parameter_mapping', qc.dict(args.fill_pulse_param, fill_time), ... - 'allow_partial_parameter_mapping', true ... - ) ... - ); - pulse = wrap(py.qctoolkit.pulses.SequencePT(fill_pulse, pulse)); - end - - % Add prefix to all pulse parameters (if not empty) - if ~isempty(args.prefix) - parameters = qc.get_pulse_params(pulse); - parameter_mapping = cell(1, 2*numel(parameters)); - for k = 1:numel(parameters) - parameter_mapping{1, 2*k-1} = parameters{k}; - parameter_mapping{1, 2*k} = strcat(args.prefix, parameters{k}); - end - - pulse = py.qctoolkit.pulses.MappingPT( ... - pyargs( ... - 'template', pulse, ... - 'parameter_mapping', qc.dict(parameter_mapping{:}), ... - 'allow_partial_parameter_mapping', true ... - ) ... - ); - end - - if any(isnan(args.outerRepetition)) - outerRepetition = 1; - else - outerRepetition = args.outerRepetition; - end - - % Add pulse identifier if identifier not empty - if ~isempty(args.identifier) - pulse = py.qctoolkit.pulses.RepetitionPT( ... - pulse, outerRepetition, ... - pyargs('identifier', args.identifier) ... - ); - elseif args.outerRepetition > 1 - pulse = py.qctoolkit.pulses.RepetitionPT( ... - pulse, args.outerRepetition); - end - -end \ No newline at end of file diff --git a/MATLAB/+qc/pulse_to_struct.m b/MATLAB/+qc/pulse_to_struct.m deleted file mode 100644 index 6d952fd61..000000000 --- a/MATLAB/+qc/pulse_to_struct.m +++ /dev/null @@ -1,15 +0,0 @@ -function pulseStruct = pulse_to_struct(pulseTemplate) - - backend = py.qctoolkit.serialization.DictBackend(); - serializer = py.qctoolkit.serialization.Serializer(backend); - - serializer.serialize(pulseTemplate); - pulseStruct = util.py.py2mat(backend.storage); - - if ~isfield(pulseStruct, 'main') - pulseStruct.main = char(pulseTemplate.identifier); - end - - - - \ No newline at end of file diff --git a/MATLAB/+qc/qcToolkitTestSetupUploadProgram.m b/MATLAB/+qc/qcToolkitTestSetupUploadProgram.m deleted file mode 100644 index 44b3a34b1..000000000 --- a/MATLAB/+qc/qcToolkitTestSetupUploadProgram.m +++ /dev/null @@ -1,67 +0,0 @@ -% set upload pulse -% upload_pulse = 'dnp_wait_dbz_4chan'; -% upload_pulse = 'decay_j_fid_4chan'; -% upload_pulse = 's_pumping_AB_4chan'; -% upload_pulse = 'pumping_s_stp'; -% upload_pulse = 'pumping_s'; -upload_scan = 'dnp_decay_dbz_fid_4chan'; -% upload_scan = 'line'; -% upload_scan = 'lead'; -% upload_scan = 'tl'; - - - - -%% Just an example with the Tabor AWG simulator -% awgctrl('default except offsets') -plsdata.awg.inst.send_cmd(':OUTP:COUP:ALL HV'); -args = tunedata.run{1}.(upload_scan).opts(1).scan.configfn(4).args; -args{end}.window_mapping.A = py.None; -args{end}.window_mapping.B = py.None; -args{end}.window_mapping.DBZFID_A = py.None; -args{end}.window_mapping.DBZFID_B = py.None; -args{end}.operations = {}; -feval(args{2:end}); - - -%% test scan to test if why one can not upload pump pulses created with qctk concatenate -myname = 'dnp_ABCD_4chan' - - -window_mapping = struct('A', py.None, 'B', py.None); - -myargs = struct('program_name', myname, ... - 'pulse_template', myname, ... - 'channel_mapping', struct('W', 'TABOR_A', 'X', 'TABOR_B', 'Y', 'TABOR_C', 'Z', 'TABOR_D', 'MTrig', 'TABOR_A_MARKER', 'M1', 'TABOR_B_MARKER', 'M2', 'TABOR_C_MARKER'), ... - 'parameters_and_dicts', {{'common', 'common_d12', 'common_d34', 'common_d12 d12', 'common_d34 d34'}}, ... - 'window_mapping', window_mapping ... - ); - -plsdata.awg.inst.send_cmd(':OUTP:COUP:ALL HV'); -myinput = {'awg_program', @qc.awg_program, 'add', myargs}; -feval(myinput{2:end}); - - -%% reset AWG -awgctrl('default except offsets'); - -%% check out sequ table wait_4chan -entries = qc.get_sequence_table('wait_4chan', false) -entries{1}{end} -entries{1}{end-1} -entries{1}{end-2} -entries{1}{end-5} - - -%% check seq table j_fid_4chan -entries = qc.get_sequence_table('j_fid_4chan', false) -entries{1}{end} -entries{1}{end-1} -entries{1}{end-2} -entries{1}{end-5} - -%% -entries = qc.get_sequence_table('wait_4chan', true) -disp(entries{1}{1}); -disp(entries{2}{1}); -% disp(entries{3}{1}); \ No newline at end of file diff --git a/MATLAB/+qc/qctoolkitTestSetup.m b/MATLAB/+qc/qctoolkitTestSetup.m deleted file mode 100644 index 32226a141..000000000 --- a/MATLAB/+qc/qctoolkitTestSetup.m +++ /dev/null @@ -1,94 +0,0 @@ -%% --- Test setup without AWG and Alazar (only qctoolkit) ----------------- -quPulsePath = fileparts(which('qc.qctoolkitTestSetup')); -load([quPulsePath '\personalPaths.mat']); -global plsdata -plsdata = struct( ... - 'path', personalPathsStruct.pulses_repo, ... - 'awg', struct('inst', [], 'hardwareSetup', [], 'sampleRate', 2e9, 'currentProgam', '', 'registeredPrograms', struct(), 'defaultChannelMapping', struct(), 'defaultWindowMapping', struct(), 'defaultParametersAndDicts', {{}}, 'defaultAddMarker', {{}}), ... - 'dict', struct('cache', [], 'path', personalPathsStruct.dicts_repo), ... - 'qc', struct('figId', 801), ... - 'daq', struct('inst', [], 'defaultOperations', {{}}, 'reuseOperations', false, 'operationsExternallyModified', false) ... - ); -plsdata.daq.instSmName = 'ATS9440Python'; -plsdata.qc.backend = py.qctoolkit.serialization.FilesystemBackend(plsdata.path); -plsdata.qc.serializer = py.qctoolkit.serialization.Serializer(plsdata.qc.backend); -% ------------------------------------------------------------------------- - -%% --- Test setup replicating the Triton 200 measurement setup ------------ -% Does not replicate Alazar functionality as there is no simulator -% Need the triton_200 repo on the path (for awgctrl) - -% Path for Triton 200 backups -loadPath = personalPathsStruct.loadPath; -pulsePath = plsdata.path; -dictPath = plsdata.dict.path; -tunePath = personalPathsStruct.tunePath; - -% Loading -try - copyfile(fullfile(loadPath, 'smdata_recent.mat'), fullfile(tunePath, 'smdata_recent.mat')); -catch err - warning(err.getReport()); -end -load(fullfile(tunePath, 'smdata_recent.mat')); -info = dir(fullfile(tunePath, 'smdata_recent.mat')); -fprintf('Loaded smdata from %s\n', datestr(info.datenum)); -try - copyfile(fullfile(loadPath, 'tunedata_recent.mat'), fullfile(tunePath, 'tunedata_recent.mat')); -% copyfile(fullfile(loadPath, 'tunedata_2018_06_25_21_08.mat'), fullfile(tunePath, 'tunedata_recent.mat')); -catch err - warning(err.getReport()); -end -load(fullfile(tunePath, 'tunedata_recent.mat')); -info = dir(fullfile(tunePath, 'tunedata_recent.mat')); -fprintf('Loaded tunedata from %s\n', datestr(info.datenum)); - -try - copyfile(fullfile(loadPath, 'plsdata_recent.mat'), fullfile(tunePath, 'plsdata_recent.mat')); -catch err - warning(err.getReport()); -end -load(fullfile(tunePath, 'plsdata_recent.mat')); -info = dir(fullfile(tunePath, 'plsdata_recent.mat')); -fprintf('Loaded plsdata from %s\n', datestr(info.datenum)); - -global tunedata -global plsdata -tunedata.run{tunedata.runIndex}.opts.loadFile = personalPathsStruct.loadPath; -import tune.tune - -plsdata.path = pulsePath; - -% Alazar dummy instrument (simulator not implemented yet) -smdata.inst(sminstlookup(plsdata.daq.instSmName)).data.address = 'simulator'; -plsdata.daq.inst = py.qctoolkit.hardware.dacs.alazar.AlazarCard([]); - -% Setup AWG -% Turns on AWG for short time but turns it off again -% Initializes hardware setup -% Can also be used for deleting all programs/resetting but then also need to setup Alazar again, i.e. the cell above and the three cells below ) -plsdata.awg.hardwareSetup = []; -qc.setup_tabor_awg('realAWG', false, 'simulateAWG', true, 'taborDriverPath', personalPathsStruct.taborDriverPath); - -% AWG default settings -awgctrl('default'); -plsdata.awg.inst.send_cmd(':OUTP:COUP:ALL HV'); - -% Alazar -% Execute after setting up the AWG since needs hardware setup initialized -% Need to test whether need to restart Matlab if execute -% qc.setup_alazar_measurements twice -qc.setup_alazar_measurements('nQubits', 2, 'nMeasPerQubit', 4, 'disp', true); - -% Qctoolkit -plsdata.qc.backend = py.qctoolkit.serialization.FilesystemBackend(pulsePath); -plsdata.qc.serializer = py.qctoolkit.serialization.Serializer(plsdata.qc.backend); -plsdata.dict.path = dictPath; - -% Tune -tunedata.run{tunedata.runIndex}.opts.path = tunePath; - - -import tune.tune -disp('done'); -% ------------------------------------------------------------------------- \ No newline at end of file diff --git a/MATLAB/+qc/qctoolkit_programs.m b/MATLAB/+qc/qctoolkit_programs.m deleted file mode 100644 index fe6b634fc..000000000 --- a/MATLAB/+qc/qctoolkit_programs.m +++ /dev/null @@ -1,55 +0,0 @@ -%% Charge scan - -%% 4 CHANs -pulseLocation = 'C:\Users\lablocal\Documents\PYTHON\qc-toolkit-pulses'; -charge_scan_pulse = qctoolkit.load_pulse('general_charge_scan', pulseLocation); - -charge_scan_pulse_params = struct( ... - 'N_y', 10, ... - 't_wait', 0, ... % ns - 'y_stop', 1, ... - 'x_stop', 1, ... - 'x_start', -1, ... - 'N_x', 10, ... - 't_meas', 192, ... - 'y_start', -1, ... - 'W_fast', 0, ... - 'W_slow', 1, ... - 'X_fast', 1, ... - 'X_slow', 0, ... - 'Y_fast', 0, ... - 'Y_slow', 1, ... - 'Z_fast', 0, ... - 'Z_slow', 1, ... - 'rep_count', 1 ... - ); -plsdata.daq.inst.config.totalRecordSize = int64(0); % needed -plsdata.daq.inst.config.aimedBufferSize = int64(2^24); -plsdata.daq.inst.card.reset -plsdata.daq.inst.update_settings = py.True; - -%% -qc.plot_pulse(charge_scan_pulse, charge_scan_pulse_params) - -%% 4 CHANs -operations = {... - py.atsaverage.operations.Downsample('DS_A', 'A'),... - py.atsaverage.operations.Downsample('DS_B', 'B')... - ...py.atsaverage.operations.Downsample('DS_C', 'alazarC'),... - ...py.atsaverage.operations.Downsample('DS_D', 'alazarD'),... - }; - -plsdata.daq.inst.register_operations('general_charge_scan', py.list(operations)) - -%% 4 CHANs upload and arm -qc.arm_program('general_charge_scan', chargeScanPulseParams, ... - 'channel_mapping', struct('W', 'TABOR_A','X', 'TABOR_B','Y', 'TABOR_C', 'Z', 'TABOR_D', 'marker', 'TABOR_A_MARKER'), ... - 'window_mapping', struct('A', 'A', 'B', 'B'),... - 'update', true) - -%% Same as above if program already uploaded -qc.arm_program('general_charge_scan'); - -%% Start program -awgctrl('run'); - diff --git a/MATLAB/+qc/readme.txt b/MATLAB/+qc/readme.txt deleted file mode 100644 index 10dddd2d3..000000000 --- a/MATLAB/+qc/readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -Test setup ------------------------------------------------------------------------------ -Use qctoolkitTestSetup - - -Naming convention ------------------------------------------------------------------------------ -Since qctoolkit uses underscores in variable names (instead of camel case) this package uses underscores. Some functions also use camel case for all variables which do not map directly to qctoolkit variables (otherwise it uses the qctoolkit variable and thus underscores). diff --git a/MATLAB/+qc/save_dict.m b/MATLAB/+qc/save_dict.m deleted file mode 100644 index 771c8751b..000000000 --- a/MATLAB/+qc/save_dict.m +++ /dev/null @@ -1,18 +0,0 @@ -function save_dict(dict_struct) - global plsdata - delim = '___'; - - if isstruct(dict_struct) - if ~isfield(dict_struct, 'global') - dict_struct.global = struct(); - end - dict_struct = qc.array2list(dict_struct); - text = py.json.dumps(dict_struct, pyargs('indent', int8(4), 'sort_keys', true)); - text = char(text); - fileId = fopen(fullfile(plsdata.dict.path, [dict_struct.(strcat('dict', delim, 'name')) '.json']), 'w'); - fprintf(fileId, '%s', text); - fclose(fileId); - else - error('Saving of dictionary failed since no struct was passed\n'); - end -end \ No newline at end of file diff --git a/MATLAB/+qc/save_pulse.m b/MATLAB/+qc/save_pulse.m deleted file mode 100644 index 4cafdd4ef..000000000 --- a/MATLAB/+qc/save_pulse.m +++ /dev/null @@ -1,30 +0,0 @@ -function [ file_written ] = save_pulse( pulse_template, overwrite ) - - global plsdata - - if nargin < 2 || isempty(overwrite) - overwrite = true; - end - - file_written = false; - - if py.operator.contains(plsdata.qc.pulse_storage, pulse_template.identifier) - if overwrite - py.operator.delitem(plsdata.qc.pulse_storage, pulse_template.identifier); - else - warning('Did not write file as it exists and overwrite == false'); - return; - end - end - - try - plsdata.qc.pulse_storage{pulse_template.identifier} = pulse_template; - file_written = true; -% fprintf('File(s) written\n'); - catch err - warning(err.getReport()); - end -end - - - diff --git a/MATLAB/+qc/set_alazar_buffer_strategy.m b/MATLAB/+qc/set_alazar_buffer_strategy.m deleted file mode 100644 index 921275e62..000000000 --- a/MATLAB/+qc/set_alazar_buffer_strategy.m +++ /dev/null @@ -1,58 +0,0 @@ -function set_alazar_buffer_strategy(strategy, varargin) - % SET_ALAZAR_BUFFER_STRATEGY sets the strategy to determine the buffer - % size the alazar card uses. - % strategy = - % {'force_buffer_size'|'avoid_single_buffer'|'one_buffer_per_window'|'none'} - % - % strategy = 'none' - % Uses default from python - % - % strategy = 'force_buffer_size' - % Requires the argument 'target_size' - % - % strategy = 'avoid_single_buffer' - % Optional argument 'target_size' - % - % strategy = 'one_buffer_per_window' - % Uses the gcd of all measurement window periods. Usefull for charge - % scans with lots of averaging - - import py.qupulse.hardware.dacs.alazar.AvoidSingleBufferAcquisition - import py.qupulse.hardware.dacs.alazar.OneBufferPerWindow - import py.qupulse.hardware.dacs.alazar.ForceBufferSize - - - global plsdata - - switch lower(strategy) - case 'none' - py_strategy = py.None; - - case 'force_buffer_size' - args = util.parse_varargin(varargin{:}); - if ~isfield(args, 'target_size') - error('qc:set_alazar_buffer_strategy:missing','The buffer strategy "force_buffer_size" requires "target_size".') - end - py_strategy = ForceBufferSize(struct2pyargs(args)); - - - case 'avoid_single_buffer' - default_args = struct('target_size', py.int(2^22)); - args = util.parse_varargin(default_args, varargin{:}); - py_strategy = AvoidSingleBufferAcquisition(ForceBufferSize(struct2pyargs(args))); - - case 'one_buffer_per_window' - py_strategy = py.qupulse.hardware.dacs.alazar.OneBufferPerWindow(); - - otherwise - error('qc:set_alazar_buffer_strategy:unknown', 'Unknown buffer strategy "%s"', strategy); - end - - plsdata.daq.inst.buffer_strategy = py_strategy; - fprintf('Set buffer strategy to %s.\n', char(py.repr(py_strategy))); -end - -function py_args = struct2pyargs(s) - c = [fieldnames(s), struct2cell(s)]'; - py_args = pyargs(c{:}); -end \ No newline at end of file diff --git a/MATLAB/+qc/set_pumping_at_awg.m b/MATLAB/+qc/set_pumping_at_awg.m deleted file mode 100644 index 5d8e7674b..000000000 --- a/MATLAB/+qc/set_pumping_at_awg.m +++ /dev/null @@ -1,108 +0,0 @@ -function set_pumping_at_awg(pumpingConfig, varargin) - -global plsdata - -defaultArgs = struct(... - 'programName', plsdata.awg.currentProgam, ... - 'turnOffAWG', true, ... - 'speedUp', false ... - ); -args = util.parse_varargin(varargin, defaultArgs); - -if ~args.speedUp - seqTable = qc.get_sequence_table(args.programName, false); -else - seqTable = qc.get_sequence_table(args.programName, false, {'AB', 'CD'}, false, true); -end -seqTableCheck = true; -report = ''; -pumpSubTab = seqTable{1}{end}; - - - - - -%---------------- some checks --------------------------------------------- -if ~args.speedUp - - %check if there are six entries for the three pumping types for each qubit - if length(pumpSubTab) < 6 - seqTableCheck = false; - report = ' -- There are not six waveforms at the end of the sequence table! They might be put together or not uploaded or not at the end of the sequence table. -- '; - end - - %test if every waveform is different/has a different - if seqTableCheck - for i = 0:5 - for j = 0:5 - if (i~=j) && (pumpSubTab{end-i}{2} == pumpSubTab{end-j}{2}) - report = ' -- Not all waveforms for pumping (that are assumed to be different) are different to each other! -- '; - seqTableCheck = false; - end - end - end - end - - %test if both channel pairs have the same pumping sequence table part - for i = 1:6 - if seqTableCheck && ~isequal(seqTable{1}{end}{end-i+1}, seqTable{2}{end}{end-i+1}) - report = ' -- Not the same pumping configuration on both channel pairs of the AWG! -- '; - seqTableCheck = false; - end - end - -end - - -%------------- reading out the pumping configuration ---------------------- - -if ~seqTableCheck - warning(report); -else - if ~args.speedUp - seqTable{1}{end}{end-5}{1} = pumpingConfig.n_s_AB; - seqTable{1}{end}{end-4}{1} = pumpingConfig.n_t_AB; - seqTable{1}{end}{end-3}{1} = pumpingConfig.n_cs_AB; - seqTable{1}{end}{end-2}{1} = pumpingConfig.n_s_CD; - seqTable{1}{end}{end-1}{1} = pumpingConfig.n_t_CD; - seqTable{1}{end}{end-0}{1} = pumpingConfig.n_cs_CD; - seqTable{2}{end}{end-5}{1} = pumpingConfig.n_s_AB; - seqTable{2}{end}{end-4}{1} = pumpingConfig.n_t_AB; - seqTable{2}{end}{end-3}{1} = pumpingConfig.n_cs_AB; - seqTable{2}{end}{end-2}{1} = pumpingConfig.n_s_CD; - seqTable{2}{end}{end-1}{1} = pumpingConfig.n_t_CD; - seqTable{2}{end}{end-0}{1} = pumpingConfig.n_cs_CD; - else - seqTable{1}{end} = py.list(seqTable{1}{end}); - seqTable{2}{end} = py.list(seqTable{1}{end}); - for i = 0:5 - seqTable{1}{end}{end-i} = py.list(seqTable{1}{end}{end-i}); - seqTable{2}{end}{end-i} = py.list(seqTable{2}{end}{end-i}); - end - seqTable{1}{end}{end-5}{1} = py.int(pumpingConfig.n_s_AB); - seqTable{1}{end}{end-4}{1} = py.int(pumpingConfig.n_t_AB); - seqTable{1}{end}{end-3}{1} = py.int(pumpingConfig.n_cs_AB); - seqTable{1}{end}{end-2}{1} = py.int(pumpingConfig.n_s_CD); - seqTable{1}{end}{end-1}{1} = py.int(pumpingConfig.n_t_CD); - seqTable{1}{end}{end-0}{1} = py.int(pumpingConfig.n_cs_CD); - seqTable{2}{end}{end-5}{1} = py.int(pumpingConfig.n_s_AB); - seqTable{2}{end}{end-4}{1} = py.int(pumpingConfig.n_t_AB); - seqTable{2}{end}{end-3}{1} = py.int(pumpingConfig.n_cs_AB); - seqTable{2}{end}{end-2}{1} = py.int(pumpingConfig.n_s_CD); - seqTable{2}{end}{end-1}{1} = py.int(pumpingConfig.n_t_CD); - seqTable{2}{end}{end-0}{1} = py.int(pumpingConfig.n_cs_CD); - end -end - -if args.speedUp - qc.set_sequence_table(args.programName, seqTable, false, {'AB', 'CD'}, false, true); -else - qc.set_sequence_table(args.programName, seqTable, false); -end -qc.change_armed_program(args.programName, args.turnOffAWG); - -if args.turnOffAWG - disp('turned AWG off'); -end - -end \ No newline at end of file diff --git a/MATLAB/+qc/set_sequence_table.m b/MATLAB/+qc/set_sequence_table.m deleted file mode 100644 index 2b064cc18..000000000 --- a/MATLAB/+qc/set_sequence_table.m +++ /dev/null @@ -1,96 +0,0 @@ -function set_sequence_table(program_name, seq_table, advanced_seq_table_flag, awg_channel_pair_identifiers, verbosity, input_python_list) -% SET_SEQUENCE_TABLE Manually override sequence table of program on Tabor AWG -% -% This only changes the sequence table in the associated Tabor channel -% pairs in qctoolkit. In order to actually update the sequence table on the -% AWG, you still need to run qc.change_armed_program(program_name, ...). -% -% --- Inputs -------------------------------------------------------------- -% program_name : Program name for which sequence table is set -% seq_table : Cell of sequence table to set on each -% Tabor channel pair. Empty elements will -% not be set. -% advanced_seq_table_flag : Set advanced sequence table if true. -% Default is false. -% awg_channel_pair_identifiers : Some substring in the channel pair -% identifiers to be matched. Sequence tables -% are sorted in the same order as channel -% pair identifiers substrings passed in this -% variable. Default is {'AB', 'CD'}. -% verbosity : Print sequence table to command line. -% Default is 0. -% ------------------------------------------------------------------------- -% (c) 2018/06 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de) - - global plsdata - hws = plsdata.awg.hardwareSetup; - - - if nargin < 3 || isempty(advanced_seq_table_flag) - advanced_seq_table_flag = false; - end - if nargin < 4 || isempty(awg_channel_pair_identifiers) - awg_channel_pair_identifiers = {'AB', 'CD'}; - end - if nargin < 5 || isempty(verbosity) - verbosity = 0; - end - if nargin <6 || isempty(input_python_list) - input_python_list = false; - end - - if ~input_python_list - seq_table = int_typecast(seq_table); - end - - known_awgs = util.py.py2mat(hws.known_awgs); - sort_indices = cellfun(@(x)(find( cellfun(@(y)(~isempty(strfind(char(x.identifier), y))), awg_channel_pair_identifiers) )), known_awgs); - known_awgs = known_awgs(sort_indices); - - assert(numel(seq_table) == length(known_awgs), 'Sequence table needs to be a cell with an element for each of the %i channel pairs.', length(known_awgs)); - - for k = 1:numel(seq_table) - known_programs{k} = util.py.py2mat(py.getattr(known_awgs{k}, '_known_programs')); - - if isfield(known_programs{k}, program_name) && ~isempty(seq_table{k}) - if input_python_list - if advanced_seq_table_flag - known_awgs{k}.set_program_advanced_sequence_table(program_name, seq_table{k}); - % known_awgs{k}.set_program_advanced_sequence_table(program_name, seq_table{k}); - else - known_awgs{k}.set_program_sequence_table(program_name, seq_table{k}); % Since it has to be a list inside a list, but this list if list is only trivial if advanced seq table is trivial, otherwiese each entry can be called by advanced seq table - % known_awgs{k}.set_program_sequence_table(program_name,seq_table{k}); - end - else - if advanced_seq_table_flag - known_awgs{k}.set_program_advanced_sequence_table(program_name, py.list(seq_table{k})); - % known_awgs{k}.set_program_advanced_sequence_table(program_name, seq_table{k}); - else - known_awgs{k}.set_program_sequence_table(program_name, py.list(seq_table{k})); % Since it has to be a list inside a list, but this list if list is only trivial if advanced seq table is trivial, otherwiese each entry can be called by advanced seq table - % known_awgs{k}.set_program_sequence_table(program_name,seq_table{k}); - end - end - - end - end - - if verbosity > 0 - qc.get_sequence_table(program_name, advanced_seq_table_flag, awg_channel_pair_identifiers, verbosity); - end - -end - - -function out = int_typecast(in) - - if iscell(in) - out = {}; - for k = 1:numel(in) - out{k} = int_typecast(in{k}); - end - elseif ~isempty(in) - out = int64(in); - end - -end - \ No newline at end of file diff --git a/MATLAB/+qc/setup_alazar_measurements.m b/MATLAB/+qc/setup_alazar_measurements.m deleted file mode 100644 index 1642a72b9..000000000 --- a/MATLAB/+qc/setup_alazar_measurements.m +++ /dev/null @@ -1,140 +0,0 @@ -function [mask_prototypes, measurement_map, txt] = setup_alazar_measurements(varargin) % - % This function assumes the the first nQubits Alazar channels are hooked - % up to qubits, the rest are auxiliary channels. - % - % Overview over mapping of measurements - % ----------------------------------------------------------------------- - % measurement name defined in pulse - % >>> window mapping >>> - % measurement name defined in hardware setup (1st argument of set_measurement) - % >>> set_measurement >>> - % measurement mask (2nd argument of set_measurement, 1st argument of register_mask_for_channel) - % >>> register_mask_for_channel >>> - % alazar harware channel (2nd argument of register_mask_for_channel - % ----------------------------------------------------------------------- - % - % Example manual configuration - % ----------------------------------------------------------------------- - % import py.qctoolkit.hardware.setup.MeasurementMask - % hws = plsdata.awg.hardwareSetup; - % daq = plsdata.daq.inst; - % any name, give as 2nd arg in window_mapping alazar mask name - % hws.set_measurement('A', MeasurementMask(plsdata.daq.inst, 'A')); - % hws.set_measurement('B', MeasurementMask(plsdata.daq.inst, 'B')); - % hws.set_measurement('C', MeasurementMask(plsdata.daq.inst, 'C')); - % hws.set_measurement('D', MeasurementMask(plsdata.daq.inst, 'D')); - % hws.set_measurement('A_B', MeasurementMask(plsdata.daq.inst, 'A')); - % hws.set_measurement('A_B', MeasurementMask(plsdata.daq.inst, 'B')); - % - % alazar mask name, real alazar hardware channel - % daq.register_mask_for_channel('A', uint64(0)); - % daq.register_mask_for_channel('B', uint64(1)); - % daq.register_mask_for_channel('C', uint64(2)); - % daq.register_mask_for_channel('D', uint64(3)); - % ----------------------------------------------------------------------- - - global plsdata - hws = plsdata.awg.hardwareSetup; - daq = plsdata.daq.inst; - - defaultArgs = struct( ... - 'disp', true, ... - 'nMeasPerQubit', 2, ... - 'nQubits', 2 ... - ); - args = util.parse_varargin(varargin, defaultArgs); - nAlazarChannels = 4; - nQubits = args.nQubits; - nMeasPerQubit = args.nMeasPerQubit; - - py.setattr(hws, '_measurement_map', py.dict); - py.setattr(daq, '_mask_prototypes', py.dict); - warning('Removing measurement_map and measurement_map might break stuff if previously set. Needs testing.'); - - for q = 1:nQubits - for m = 1:nMeasPerQubit - % qubitIndex, measIndex, hwChannel, auxFlag1 - add_meas_and_mask(q, m, q+nQubits-1, false); - end - end - - for a = 1:(nAlazarChannels-nQubits) - for m = 1:nMeasPerQubit - % qubitIndex, measIndex, hwChannel, auxFlag1 - add_meas_and_mask(a, m, a-1, true); - end - end - - if args.nQubits > nAlazarChannels - warning('More than %i qubits not implemented at the moment since Alazar has only %i channels.', nAlazarChannels, nAlazarChannels); - end - - if args.nQubits > 2 - warning('Simultaneous measurements for more than 2 qubits not implemented at the moment.'); - end - if q == 2 - for m = 1:nMeasPerQubit - % Q1 Q2 qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2 - add_meas_and_mask(1, m, 2, false, 2, 3 , false); - % A1 A2 qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2 - add_meas_and_mask(1, m, 0, true, 2, 1 , true); - - % Q1 A1 qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2 - add_meas_and_mask(1, m, 2, false, 1, 0 , true); - % Q1 A2 qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2 - add_meas_and_mask(1, m, 2, false, 2, 1 , true); - - % Q2 A1 qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2 - add_meas_and_mask(2, m, 3, false, 1, 0 , true); - % Q2 A2 qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2 - add_meas_and_mask(2, m, 3, false, 2, 1 , true); - end - end - - [mask_prototypes, measurement_map, txt] = qc.get_alazar_measurements('disp', args.disp); - -end - - -function add_meas_and_mask(qubitIndex, measIndex, hwChannel, auxFlag1, secondQubitIndex, secondHwChannel, auxFlag2) - global plsdata - - if nargin < 5 - secondQubitIndex = []; - end - - if nargin < 7 - auxFlag2 = false; - end - - if auxFlag1 - name = 'Aux'; - else - name = 'Qubit'; - end - - if auxFlag2 - name2 = 'Aux'; - else - name2 = 'Qubit'; - end - - if ~isempty(secondQubitIndex) - measName = sprintf('%s_%i_%s_%i_Meas_%i', name, qubitIndex, name2, secondQubitIndex, measIndex); - maskName = sprintf('%s_%i_%s_%i_Meas_%i_Mask_%i', name, qubitIndex, name2, secondQubitIndex, measIndex, 1); - maskName2 = sprintf('%s_%i_%s_%i_Meas_%i_Mask_%i', name, qubitIndex, name2, secondQubitIndex, measIndex, 2); - else - measName = sprintf('%s_%i_Meas_%i', name, qubitIndex, measIndex); - maskName = sprintf('%s_%i_Meas_%i_Mask_%i', name, qubitIndex, measIndex, 1); - end - - plsdata.awg.hardwareSetup.set_measurement(measName, py.qctoolkit.hardware.setup.MeasurementMask(plsdata.daq.inst, maskName), ~isempty(secondQubitIndex)); - plsdata.daq.inst.register_mask_for_channel(maskName, uint64(hwChannel)); - - if ~isempty(secondQubitIndex) - plsdata.awg.hardwareSetup.set_measurement(measName, py.qctoolkit.hardware.setup.MeasurementMask(plsdata.daq.inst, maskName2), true); - plsdata.daq.inst.register_mask_for_channel(maskName2, uint64(secondHwChannel)); - end -end - - diff --git a/MATLAB/+qc/setup_tabor_awg.m b/MATLAB/+qc/setup_tabor_awg.m deleted file mode 100644 index 7fb498f2c..000000000 --- a/MATLAB/+qc/setup_tabor_awg.m +++ /dev/null @@ -1,129 +0,0 @@ -function setup_tabor_awg(varargin) - - global smdata - global plsdata - - defaultArgs = struct( ... - 'realAWG', true, ... - 'sampleVoltPerAwgVolt', [util.db('dB2F',-48)*2 util.db('dB2F',-48)*2 util.db('dB2F',-44)*2 util.db('dB2F',-48)*2], ... % 10^(-dB/20)*ImpedanceMismatch - 'simulateAWG', true, ... - 'smChannels', {{'RFA', 'RFB', 'RFC', 'RFD'}}, ... - 'taborName', 'TaborAWG2184C', ... - 'globalTransformation', [], ... - 'ip', '169.254.40.2', ... %IP's: Triton 200: 169.254.40.2 Triton 400: 169.254.40.55 - 'dcMode', false, ... - 'maxPulseWait', 60, ... % Maximum waiting time in s in qc.awg_program before arming DAQ again - 'taborDriverPath', 'C:\Users\lablocal\Documents\PYTHON\TaborDriver\' ... - ); - args = util.parse_varargin(varargin, defaultArgs); - plsdata.awg.sampleVoltPerAwgVolt = args.sampleVoltPerAwgVolt; - plsdata.awg.dcMode = args.dcMode; - plsdata.awg.triggerStartTime = 0; - plsdata.awg.maxPulseWait = args.maxPulseWait; - plsdata.awg.minSamples = 192; - plsdata.awg.sampleQuantum = 16; - plsdata.awg.globalTransformation = args.globalTransformation; - - for k = 1:numel(args.smChannels) - smChannel = args.smChannels(k); - if ~(smdata.channels(smchanlookup(smChannel)).instchan(1) == sminstlookup(args.taborName)) - error('Channel %s does not belong to %s\n', smChannel, args.taborName); - end - smdata.channels(smchanlookup(smChannel)).rangeramp(end) = 1/args.sampleVoltPerAwgVolt(k); - end - - % Reload qctoolkit tabor AWG integration - qctoolkit_tabor = py.importlib.reload(py.importlib.import_module('qctoolkit.hardware.awgs.tabor')); - - % Start simulator - if args.simulateAWG - if py.pytabor.open_session('127.0.0.1') == py.None - dos([fullfile(args.taborDriverPath, 'WX2184C.exe') ' /switch-on /gui-in-tray&']) - - while py.pytabor.open_session('127.0.0.1') == py.None - pause(1); - disp('Waiting for Simulator to start...'); - end - disp('Simulator started'); - end - end - - if args.realAWG && ~args.simulateAWG - % Only real instrument - smdata.inst(sminstlookup(args.taborName)).data.tawg = qctoolkit_tabor.TaborAWGRepresentation(['TCPIP::' args.ip '::5025::SOCKET'], pyargs('reset', py.True)); - smdata.inst(sminstlookup(args.taborName)).data.tawg.paranoia_level = int64(2); - elseif args.realAWG && args.simulateAWG - % Simulator and real instrument - smdata.inst(sminstlookup(args.taborName)).data.tawg = qctoolkit_tabor.TaborAWGRepresentation(['TCPIP::' args.ip '::5025::SOCKET'], pyargs('reset', py.True, 'mirror_addresses', {'127.0.0.1'})); - elseif ~args.realAWG && args.simulateAWG - % Just simulator - smdata.inst(sminstlookup(args.taborName)).data.tawg = qctoolkit_tabor.TaborAWGRepresentation('TCPIP::127.0.0.1::5025::SOCKET', pyargs('reset', py.True)); - end - - plsdata.awg.inst = smdata.inst(sminstlookup(args.taborName)).data.tawg; - if args.realAWG && exist('awgctrl.m', 'file') - awgctrl('off'); - end - - % Create hardware setup for qctoolkit integration - plsdata.awg.hardwareSetup = py.qctoolkit.hardware.setup.HardwareSetup(); - - % Create python lambda function in Matlab - numpy = py.importlib.import_module('numpy'); - for k = 1:numel(args.sampleVoltPerAwgVolt) - multiply{k} = py.functools.partial(numpy.multiply, double(1./(args.sampleVoltPerAwgVolt(k)))); - end - - if args.realAWG || args.simulateAWG - % PlaybackChannels can take more than two values (analog channels) - plsdata.awg.hardwareSetup.set_channel('TABOR_A', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(0), multiply{1})); - plsdata.awg.hardwareSetup.set_channel('TABOR_B', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(1), multiply{2})); - plsdata.awg.hardwareSetup.set_channel('TABOR_C', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(0), multiply{3})); - plsdata.awg.hardwareSetup.set_channel('TABOR_D', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(1), multiply{4})); - - plsdata.awg.hardwareSetup.set_channel('TABOR_AB', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(0), multiply{1}), py.True); - plsdata.awg.hardwareSetup.set_channel('TABOR_AB', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(1), multiply{2}), py.True); - - - plsdata.awg.hardwareSetup.set_channel('TABOR_AC', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(0), multiply{1}), py.True); - plsdata.awg.hardwareSetup.set_channel('TABOR_AC', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(0), multiply{3}), py.True); - - plsdata.awg.hardwareSetup.set_channel('TABOR_AD', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(0), multiply{1}), py.True); - plsdata.awg.hardwareSetup.set_channel('TABOR_AD', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(1), multiply{4}), py.True); - - plsdata.awg.hardwareSetup.set_channel('TABOR_BC', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(1), multiply{2}), py.True); - plsdata.awg.hardwareSetup.set_channel('TABOR_BC', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(0), multiply{3}), py.True); - - plsdata.awg.hardwareSetup.set_channel('TABOR_BD', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_AB, int64(1), multiply{2}), py.True); - plsdata.awg.hardwareSetup.set_channel('TABOR_BD', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(1), multiply{4}), py.True); - - plsdata.awg.hardwareSetup.set_channel('TABOR_CD', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(0), multiply{3}), py.True); - plsdata.awg.hardwareSetup.set_channel('TABOR_CD', ... - py.qctoolkit.hardware.setup.PlaybackChannel(plsdata.awg.inst.channel_pair_CD, int64(1), multiply{4}), py.True); - - - % MarkerChannel can only take on two values (digital channels) - plsdata.awg.hardwareSetup.set_channel('TABOR_A_MARKER', ... - py.qctoolkit.hardware.setup.MarkerChannel(plsdata.awg.inst.channel_pair_AB, int64(0))); - plsdata.awg.hardwareSetup.set_channel('TABOR_B_MARKER', ... - py.qctoolkit.hardware.setup.MarkerChannel(plsdata.awg.inst.channel_pair_AB, int64(1))); - plsdata.awg.hardwareSetup.set_channel('TABOR_C_MARKER', ... - py.qctoolkit.hardware.setup.MarkerChannel(plsdata.awg.inst.channel_pair_CD, int64(0))); - plsdata.awg.hardwareSetup.set_channel('TABOR_D_MARKER', ... - py.qctoolkit.hardware.setup.MarkerChannel(plsdata.awg.inst.channel_pair_CD, int64(1))); - end \ No newline at end of file diff --git a/MATLAB/+qc/strrep.m b/MATLAB/+qc/strrep.m deleted file mode 100644 index 318f3d6f9..000000000 --- a/MATLAB/+qc/strrep.m +++ /dev/null @@ -1,15 +0,0 @@ -function varargout = strrep(varargin) - % Multiple string replacements: - % varargin{k} is a cell which should look like - % {cell of original strings, search string, replacement string, search string, replacement string, ...} - % - % If n arguments are received, n outputs are returned. - - for k = 1:numel(varargin) - varargout{k} = varargin{k}{1}; - for l = 2:2:numel(varargin{k}) - varargout{k} = cellfun(@(x)(strrep(x, varargin{k}{l}, varargin{k}{l+1})), varargout{k}, 'UniformOutput', false); - end - end - -end \ No newline at end of file diff --git a/MATLAB/+qc/struct_to_pulse.m b/MATLAB/+qc/struct_to_pulse.m deleted file mode 100644 index 9214f766a..000000000 --- a/MATLAB/+qc/struct_to_pulse.m +++ /dev/null @@ -1,15 +0,0 @@ -function pulseTemplate = struct_to_pulse(pulseStruct) - - backend = py.qctoolkit.serialization.DictBackend(); - serializer = py.qctoolkit.serialization.Serializer(backend); - - if startsWith(pulseStruct.main, '{') - pulseName = 'main'; - else - pulseName = pulseStruct.main; - end - - backend.storage.update(pulseStruct) - - pulseTemplate = serializer.deserialize(pulseName); - % plsStruct = util.py.py2mat(backend.storage) \ No newline at end of file diff --git a/MATLAB/+qc/to_transformation.m b/MATLAB/+qc/to_transformation.m deleted file mode 100644 index 3f694146a..000000000 --- a/MATLAB/+qc/to_transformation.m +++ /dev/null @@ -1,18 +0,0 @@ -function transformation = to_transformation(mat_trafo) - - trafo_module = py.importlib.import_module('qctoolkit._program.transformation'); - - if istable(mat_trafo) - assert(size(mat_trafo, 1) == size(mat_trafo, 2)); - if isempty(mat_trafo.Properties.RowNames) - mat_trafo.Properties.RowNames = mat_trafo.Properties.VariableNames; - end - - data = util.py.mat2py(mat_trafo{:,:}); - - transformation = trafo_module.LinearTransformation(data, mat_trafo.Properties.RowNames', mat_trafo.Properties.VariableNames); - elseif isempty(mat_trafo) - transformation = py.None; - else - error('invalid trafo type'); - end \ No newline at end of file diff --git a/MATLAB/+qc/workaround_4chan_program_errors.m b/MATLAB/+qc/workaround_4chan_program_errors.m deleted file mode 100644 index d2907b2f3..000000000 --- a/MATLAB/+qc/workaround_4chan_program_errors.m +++ /dev/null @@ -1,51 +0,0 @@ -function workaround_4chan_program_errors(a) - % For some 4 channel programs, running another 2 channel program which - % has marker channels on both AWGs beforehand, leads to erroneous voltage - % outputs, even though the (advanced) sequence tables stored by qctoolkit - % do not change. This is true even if qctoolkit is forced to reupload - % the sequence tables of the 4 channel program. - % - % To repdroduce this error reset the AWG, then run - % EITHER - % 1) tune('resp'): correct output - % 2) tune('lead', 2): correct output - % 3) tune('resp'): erroneous output - if omitted, 5) gives erroneous output - % 4) tune('line', 1): correct output - % 5) tune('resp'): correct output - % OR - % 1) tune('lead', 2): correct output - % 2) tune('comp'): correct output - % 3) tune('resp'): erroneous output - % - % I (Pascal) found out this can be circumvented by arming the erroneous - % program and then arming the idle program manually. Next, the erroneous - % program can be run and now yields the correct result. - % - % This bug has been fixed now by adding the following lines in tabor.py - % self.device.send_cmd('SEQ:DEL:ALL') - % self._sequencer_tables = [] - % self.device.send_cmd('ASEQ:DEL') - % self._advanced_sequence_table = [] - - warning('No longer needed since bug has been fixed'); - - % global plsdata - % - % if ~strcmp(plsdata.awg.currentProgam, a.program_name) && (~isfield(a, 'arm_global_for_workaround_4chan_program_errors')) - % tic - % - % hws = plsdata.awg.hardwareSetup; - % known_awgs = util.py.py2mat(hws.known_awgs); - % - % for k = 1:numel(known_awgs) - % if any(cellfun(@(x)(strcmp(x, a.program_name)), fieldnames(util.py.py2mat(py.getattr(known_awgs{k}, '_known_programs'))))) - % known_awgs{k}.change_armed_program(a.program_name); - % end - % end - % - % for k = 1:numel(known_awgs) - % known_awgs{k}.change_armed_program(py.None); - % end - % - % fprintf('qc.workaround_4chan_program_errors executed...took %.0fs\n', toc); - % end \ No newline at end of file diff --git a/MATLAB/+qc/workaround_alazar_single_buffer_acquisition.m b/MATLAB/+qc/workaround_alazar_single_buffer_acquisition.m deleted file mode 100644 index 0f9aaa2bb..000000000 --- a/MATLAB/+qc/workaround_alazar_single_buffer_acquisition.m +++ /dev/null @@ -1,23 +0,0 @@ -function workaround_alazar_single_buffer_acquisition() - % the alazar acquisition might fail if there is just a single buffer - % the functionality to work around that was moved to the attribute - % 'buffer_strategy' of the qupulse driver object - - % Some workaround for a workaround - ask Simon - global plsdata - plsdata.daq.inst.config.totalRecordSize = int64(0); -% plsdata.daq.inst.config.aimedBufferSize = int64(2^24); - - -if true - fprintf('qc.workaround_alazar_single_buffer_acquisition decidete to try one buffer per measurement window\n'); - plsdata.daq.inst.buffer_strategy = py.qupulse.hardware.dacs.alazar.OneBufferPerWindow(); -else - % use default behaviour - plsdata.daq.inst.buffer_strategy = py.None; -end - - plsdata.daq.inst.card.reset - plsdata.daq.inst.update_settings = py.True; - - fprintf('qc.workaround_alazar_single_buffer_acquisition executed\n'); \ No newline at end of file diff --git a/MATLAB/+qctoolkit/arm_pulse.m b/MATLAB/+qctoolkit/arm_pulse.m deleted file mode 100644 index 8c7e94af5..000000000 --- a/MATLAB/+qctoolkit/arm_pulse.m +++ /dev/null @@ -1,60 +0,0 @@ -function arm_pulse(pulse_name, hardware_setup, parameters, pulse_location, varargin) - -default_args = struct('channel_mapping', py.None, ... - 'window_mapping', py.None,... - 'update', false,... - 'add_marker', {{}}); - -args = util.parse_varargin(varargin, default_args); -if ~iscell(args.add_marker) - args.add_marker = {args.add_marker}; -end - -if py.list(hardware_setup.registered_programs.keys()).count(pulse_name) == 0 || args.update - -%% LOAD PULSE - -backend = py.qctoolkit.serialization.FilesystemBackend(pulse_location); - -serializer = py.qctoolkit.serialization.Serializer(backend); - -pulse_template = serializer.deserialize(pulse_name); - -%% ADD MARKER -if ~isempty(args.add_marker) - - marker_pulse = py.qctoolkit.pulses.PointPT({{0, 1},... - {pulse_template.duration, 1}}, args.add_marker); - pulse_template = py.qctoolkit.pulses.AtomicMultiChannelPT(pulse_template, marker_pulse); - - for ii = 1:numel(args.add_marker) - args.channel_mapping.(args.add_marker{ii}) = args.add_marker{ii}; - end - -end - - -%% INSTANTIATE PULSE (plug in parameters) - -sequencer = py.qctoolkit.pulses.Sequencer(); - -kwargs = pyargs('parameters', parameters,... - 'channel_mapping', args.channel_mapping,... - 'window_mapping', args.window_mapping); - -sequencer.push(pulse_template, kwargs) - -instantiated_pulse = sequencer.build(); - -%% LOAD PROGRAM TO AWG -hardware_setup.register_program(pulse_name, instantiated_pulse, pyargs('update', args.update)); - -end - -hardware_setup.arm_program(pulse_name); - -%% debug -% alazar = util.py.py2mat(py.getattr(hardware_setup, '_measurement_map')).A{1}.dac -% prog = util.py.py2mat(py.getattr(alazar, '_registered_programs')).charge_scan -% - diff --git a/MATLAB/+qctoolkit/convert_qctoolkit.m b/MATLAB/+qctoolkit/convert_qctoolkit.m deleted file mode 100644 index 2af5787a5..000000000 --- a/MATLAB/+qctoolkit/convert_qctoolkit.m +++ /dev/null @@ -1,34 +0,0 @@ -function pulse_group = convert_qctoolkit(qct_output) -% pulse_group = convert_qctoolkit(qct_output) -% -% Registers pulses and converts pulse group data obtained from qupulse. -% -% qct_output: The output tuple of the -% PulseControlInterface.create_pulse_group() method. - -qct_pulses = qct_output{2}; - -% Convert Python dicts of pulses to pulse control waveform pulse structs -% and register them using plsreg. Remember index in pulse database. -pulse_indices = zeros(size(qct_pulses, 2)); -for i = 1:size(qct_pulses, 2) - pulse = struct(qct_pulses{i}); - pulse.name = arrayfun(@char, pulse.name); - pulse.data = struct(pulse.data); - pulse.data.marker = cell2mat(cell(pulse.data.marker)); - pulse.data.wf = cell2mat(cell(pulse.data.wf)); - pulse_indices(i) = plsreg(pulse); -end - -% Convert Python dict of pulse group to pulse control struct. -% Replace pulse indices in pulse_group.pulses with the indices of the -% pulses in the pulse database (plsdata). -pulse_group = struct(qct_output{1}); -pulse_group.chan = double(pulse_group.chan); -pulse_group.name = arrayfun(@char, pulse_group.name); -pulse_group.ctrl = arrayfun(@char, pulse_group.ctrl); -pulse_group.nrep = cellfun(@double, cell(pulse_group.nrep)); -pulse_group.pulses = cellfun(@double, cell(pulse_group.pulses)); -for i = 1:size(pulse_group.pulses, 2) - pulse_group.pulses(i) = pulse_indices(pulse_group.pulses(i) + 1); -end \ No newline at end of file diff --git a/MATLAB/+qctoolkit/example_scan_no_alazar.m b/MATLAB/+qctoolkit/example_scan_no_alazar.m deleted file mode 100644 index 695577a45..000000000 --- a/MATLAB/+qctoolkit/example_scan_no_alazar.m +++ /dev/null @@ -1,128 +0,0 @@ -% The alazar card in THIS example is not controled with qctoolkit and all -% measurement windows defined in the pulses are ignored -function scan = example_scan_no_alazar(hardware_setup, tawg) - -global smdata; - -%tawg.send_cmd(':INST:SEL 1'); -%tawg.send_cmd(':SOUR:MARK:SEL 1; :SOUR:MARK:VOLT:HIGH 1.2'); -%tawg.send_cmd(':SOUR:MARK:SEL 1; :SOUR:MARK:STAT OFF'); - - -%set_marker = @() tawg.send_cmd(':ENAB; :TRIG; :SOUR:MARK:SOUR WAVE; :SOUR:MARK:SEL 1; :SOUR:MARK:STAT ON'); -%reset_marker = @() tawg.send_cmd(':SOUR:MARK:SEL 1; :SOUR:MARK:STAT OFF'); - - -% use pulse from example files -qctoolkit_location = what('+qctoolkit'); -pulse_name = 'table_template'; -pulse_location = fullfile(qctoolkit_location.path,... - '..', '..', 'doc', 'source', 'examples', 'serialized_pulses'); - - -% create struct with parameters -parameters.va = 0; -parameters.vb = 0.5; -parameters.ta = 192; -parameters.tb = 4*19200 - 192; -parameters.tend = parameters.tb + 192; - -pulse_length = parameters.tend / tawg.sample_rate(uint64(1)); - -% we want to play the channel 'A' of the pulse on the channel 'TABOR_A' of -% the hardware_setup. -channel_mapping.A = 'TABOR_A'; - -% For a pulse with measurement windows we can rename them here -% window_mapping.meas_in_pulse = 'meas_name' - - -%% Configure data acquisition with alazar card -sm_alazar_channel = 'ATS1'; -sm_alazar_instrument = smchaninst(sm_alazar_channel); -sm_alazar_instrument = sm_alazar_instrument(1); - - -alazar_config = sm_setups.common.AlazarDefaultSettings(); - -trigger_range = 1; -trigger_level = 0.01; - -alazar_config.trigger_settings.source_1 = 'A'; -alazar_config.trigger_settings.level_1 = uint8(128 + 127* (trigger_level / trigger_range)); -alazar_config.trigger_settings.slope_1 = 'positive'; - -switch alazar_config.clock_settings.samplerate - case 'rate_100MSPS' - alazar_sample_rate = 100e6; - otherwise - error('invalid sample rate (changing the sample rate possibly breaks clock sync)'); -end - -alazar_downsampling = 1; - -masks = {}; -masks{1}.type = 'Periodic Mask'; -masks{1}.begin = 0; -masks{1}.end = alazar_downsampling; -masks{1}.period = alazar_downsampling; -masks{1}.channel = 'A'; - -alazar_config.total_record_size = pulse_length * alazar_sample_rate; -if abs(alazar_config.total_record_size - round(alazar_config.total_record_size)) > 1e-10 - error('total record size is no integer'); -end -alazar_config.total_record_size = int64(round(alazar_config.total_record_size)); -data_points_per_pulse = alazar_config.total_record_size / alazar_downsampling; - -operations = {}; -operations{1}.type = 'DS';% downsampling -operations{1}.mask = 1; - -alazar_config.masks = masks; -alazar_config.operations = operations; - - -scan.configfn(1).fn = @smaconfigwrap; -scan.configfn(1).args = {smdata.inst(sm_alazar_instrument).cntrlfn [sm_alazar_instrument 0 99] [] [] alazar_config}; % upload config ? - -scan.configfn(2).fn = @smaconfigwrap; -scan.configfn(2).args = {smdata.inst(sm_alazar_instrument).cntrlfn,[sm_alazar_instrument 0 5]}; % write/commit config - -% upload pulse to AWG -scan.configfn(3).fn = @smaconfigwrap; -scan.configfn(3).args = {@qctoolkit.arm_pulse,... - pulse_name, hardware_setup, parameters, pulse_location... - 'channel_mapping', channel_mapping,... - 'update', true}; - -scan.loops(1).setchan = []; -scan.loops(1).npoints = data_points_per_pulse; -scan.loops(1).rng = []; -scan.loops(1).ramptime = 0; % = sample rate * mask.period - -scan.loops(1).trigfn.fn = @(awg) awg.send_cmd(':TRIG'); -scan.loops(1).trigfn.args = {tawg}; - -scan.loops(2).setchan = []; -scan.loops(2).getchan = {sm_alazar_channel}; % read out buffer -scan.loops(2).npoints = 2; -scan.loops(2).ramptime = []; -scan.loops(2).rng = 1:2; - -scan.disp(1).loop = 2; -scan.disp(1).channel = 1; -scan.disp(1).dim = 1; -scan.disp(2).loop = 2; -scan.disp(2).channel = 1; -scan.disp(2).dim = 2; - - -% arm Alazar before each scan loop(1) -scan.loops(2).prefn(1).fn = @smaconfigwrap; -scan.loops(2).prefn(1).args = {smdata.inst(sm_alazar_instrument).cntrlfn,[sm_alazar_instrument 0 4]}; - -% arm AWG before each scan loop(1) (not really necessary) -scan.loops(2).prefn(2).fn = @smaconfigwrap; -scan.loops(2).prefn(2).args = {@qctoolkit.arm_pulse, pulse_name, hardware_setup}; - diff --git a/MATLAB/+qctoolkit/get_pulse_duration.m b/MATLAB/+qctoolkit/get_pulse_duration.m deleted file mode 100644 index 4568f4b7c..000000000 --- a/MATLAB/+qctoolkit/get_pulse_duration.m +++ /dev/null @@ -1,17 +0,0 @@ -function pulse_length = get_pulse_duration(pulse, parameters) - -parameter_kwargs = cell2namevalpairs(fieldnames(parameters), struct2cell(parameters)); -pulse_length = pulse.duration.evaluate_numeric(pyargs(parameter_kwargs{:}))*1e-9; - - - - -% delete.. -function cellarr = cell2namevalpairs(fieldnames, values) - cellarr={}; - for ii = 1:numel(fieldnames) - cellarr{end+1}=fieldnames{ii}; - cellarr{end+1}=values{ii}; - end - - \ No newline at end of file diff --git a/MATLAB/+qctoolkit/get_pulse_parameters.m b/MATLAB/+qctoolkit/get_pulse_parameters.m deleted file mode 100644 index 31bd17713..000000000 --- a/MATLAB/+qctoolkit/get_pulse_parameters.m +++ /dev/null @@ -1,6 +0,0 @@ -function pulse_parameters = get_pulse_parameters(varargin) - - pulse_template = qctoolkit.load_pulse(varargin{:}); - - pulse_parameters = util.py.py2mat(pulse_template.parameter_names); - \ No newline at end of file diff --git a/MATLAB/+qctoolkit/instantiate_pulse.m b/MATLAB/+qctoolkit/instantiate_pulse.m deleted file mode 100644 index 5d1c25240..000000000 --- a/MATLAB/+qctoolkit/instantiate_pulse.m +++ /dev/null @@ -1,18 +0,0 @@ -%% INSTANTIATE PULSE (plug in parameters) -function instantiated_pulse = instantiate_pulse(pulse_template, parameters, varargin) - -default_args = struct(... - 'channel_mapping', py.None,... - 'window_mapping', py.None); - -args = util.parse_varargin(varargin, default_args); - -sequencer = py.qctoolkit.pulses.Sequencer(); - -kwargs = pyargs('parameters', parameters,... - 'channel_mapping', args.channel_mapping,... - 'window_mapping', args.window_mapping); - -sequencer.push(pulse_template, kwargs) - -instantiated_pulse = sequencer.build(); \ No newline at end of file diff --git a/MATLAB/+qctoolkit/load_pulse.m b/MATLAB/+qctoolkit/load_pulse.m deleted file mode 100644 index 4beb2f7e4..000000000 --- a/MATLAB/+qctoolkit/load_pulse.m +++ /dev/null @@ -1,7 +0,0 @@ -function pulse_template = load_pulse(pulse_name, pulse_location) - -backend = py.qctoolkit.serialization.FilesystemBackend(pulse_location); - -serializer = py.qctoolkit.serialization.Serializer(backend); - -pulse_template = serializer.deserialize(pulse_name); \ No newline at end of file diff --git a/MATLAB/+qctoolkit/plot_pulse.m b/MATLAB/+qctoolkit/plot_pulse.m deleted file mode 100644 index 296aea689..000000000 --- a/MATLAB/+qctoolkit/plot_pulse.m +++ /dev/null @@ -1,30 +0,0 @@ -function plot_pulse(pulse, parameters, npoints) - %% -sequencer = py.qctoolkit.pulses.Sequencer(); - -kwargs = pyargs('parameters', parameters); - -sequencer.push(pulse, kwargs); - -instantiated_pulse = sequencer.build(); - -pulse_duration_in_s = qctoolkit.get_pulse_duration(pulse, parameters); -pulse_duration_in_ns = pulse_duration_in_s * 1e9; -%% -if nargin < 3 - npoints = 100; -end -%% -sample_rate = npoints / pulse_duration_in_ns; -%% -data = util.py.py2mat(py.qctoolkit.pulses.plotting.render(instantiated_pulse, pyargs('sample_rate', sample_rate))); - -t = data{1}; -figure; -hold on - -for chan_name=fieldnames(data{2})' - plot(t, data{2}.(chan_name{1})); -end - -legend(fieldnames(data{2})'); \ No newline at end of file diff --git a/MATLAB/+qctoolkit/plot_tabor_pulse.m b/MATLAB/+qctoolkit/plot_tabor_pulse.m deleted file mode 100644 index 20da1dd53..000000000 --- a/MATLAB/+qctoolkit/plot_tabor_pulse.m +++ /dev/null @@ -1,23 +0,0 @@ -function plot_current_pulse(awg) - -program = awg.read_complete_program(); - -wfs = util.py.py2mat(program.get_waveforms()); -reps = util.py.py2mat(program.get_repetitions()); -n_wfs = numel(wfs); - -f = figure; - - - -tabgroup = uitabgroup(mainfig, 'Position', [.05 .1 .9 .8]); - -for k = 1:n_wfs - tab(k)=uitab(tabgroup,'Title', sprintf('Wf_%i', k)); - - axes('parent',tab(k)) - - plot(wfs{k}); - - legend(sprintf('%i times', reps(k))); -end \ No newline at end of file diff --git a/MATLAB/+qctoolkit/qctoolkitTestSetup.m b/MATLAB/+qctoolkit/qctoolkitTestSetup.m deleted file mode 100644 index 1ba8ab65d..000000000 --- a/MATLAB/+qctoolkit/qctoolkitTestSetup.m +++ /dev/null @@ -1,86 +0,0 @@ -%% Setup -global plsdata -plsdata = struct( ... - 'path', 'Y:\Cerfontaine\Code\qc-tookit-pulses', ... - 'awg', struct('inst', [], 'hardwareSetup', []), ... - 'daq', struct('inst', []) ... - ); - - -%% Repetition 4 Channel charge pulse -% Wwritten by F. Wangelik and P. Cerfontaine, 23.02.2018 - - -% Define table template for each iteration/step/measurement -part_pulse = py.qctoolkit.pulses.TablePT( ... - struct( ... - 'W', py.list({ {'(t_wait+t_meas)/sample_rate', 'W_fast*(x_start + i_x*x_step) + W_slow*(y_start + i_y*y_step)'} }), ... - 'X', py.list({ {'(t_wait+t_meas)/sample_rate', 'X_fast*(x_start + i_x*x_step) + X_slow*(y_start + i_y*y_step)'} }), ... - 'Y', py.list({ {'(t_wait+t_meas)/sample_rate', 'Y_fast*(x_start + i_x*x_step) + Y_slow*(y_start + i_y*y_step)'} }), ... - 'Z', py.list({ {'(t_wait+t_meas)/sample_rate', 'Z_fast*(x_start + i_x*x_step) + Z_slow*(y_start + i_y*y_step)'} }), ... - 'marker', py.list({ {'(t_wait+t_meas)/sample_rate', 1} }) ... - ) ... - ); - -first_pulse = py.qctoolkit.pulses.TablePT( ... - pyargs( ... - 'entries', ... - struct( ... - 'W', py.list({ {'(t_wait+t_meas)/sample_rate', 'W_fast*(x_start + i_x*x_step) + W_slow*(y_start + i_y*y_step)'} }), ... - 'X', py.list({ {'(t_wait+t_meas)/sample_rate', 'X_fast*(x_start + i_x*x_step) + X_slow*(y_start + i_y*y_step)'} }), ... - 'Y', py.list({ {'(t_wait+t_meas)/sample_rate', 'Y_fast*(x_start + i_x*x_step) + Y_slow*(y_start + i_y*y_step)'} }), ... - 'Z', py.list({ {'(t_wait+t_meas)/sample_rate', 'Z_fast*(x_start + i_x*x_step) + Z_slow*(y_start + i_y*y_step)'} }), ... - 'marker', py.list({ {'(t_wait+t_meas)/sample_rate', 1} }) ... - ), ... - 'measurements', ... - py.list({ {'A', 't_wait/sample_rate', '(t_meas/sample_rate)*meas_time_multiplier'}, ... - {'B', 't_wait/sample_rate', '(t_meas/sample_rate)*meas_time_multiplier'} } ... - ) ... - ) ... - ); - -rep_pulse = py.qctoolkit.pulses.repetition_pulse_template.RepetitionPulseTemplate(part_pulse, 'meas_time_multiplier-1'); -meas_pulse = py.qctoolkit.pulses.SequencePT(first_pulse, rep_pulse); - -% Create loop templates for both iterations -x_loop = py.qctoolkit.pulses.loop_pulse_template.ForLoopPulseTemplate(meas_pulse, 'i_x', 'N_x'); -y_loop = py.qctoolkit.pulses.loop_pulse_template.ForLoopPulseTemplate(x_loop, 'i_y', 'N_y'); - -% Start parameter mapping via mapping template -general_charge_scan = py.qctoolkit.pulses.MappingPT( ... - pyargs( ... - 'template', y_loop, ... - 'identifier', 'charge_scan', ... - 'parameter_mapping', struct('x_step', '(x_stop-x_start)/N_x', ... - 'y_step', '(y_stop-y_start)/N_y'), ... - 'allow_partial_parameter_mapping', true ... - ) ... - ); - -general_charge_scan = py.qctoolkit.pulses.repetition_pulse_template.RepetitionPulseTemplate( ... - pyargs( ... - 'body', general_charge_scan, ... - 'repetition_count', 'rep_count', ... - 'identifier', 'general_charge_scan' ... - ) ... - ); - -%% -qctoolkit.plot_pulse(general_charge_scan, struct('x_start', -1, 'x_stop', 1, 'N_x', 10, 't_meas', 1, ... - 'W_fast', 1, 'W_slow', 0, ... - 'X_fast', 1, 'X_slow', 0, ... - 'Y_fast', 0, 'Y_slow', 1, ... - 'Z_fast', 0, 'Z_slow', 1, ... - 'y_start', -1, 'y_stop', 1, 'N_y', 10, 't_wait', 0, 'sample_rate', 2.3, 'meas_time_multiplier', 2, ... - 'rep_count', 2), 100) - - -% from qctoolkit.serialization import FilesystemBackend, Serializer - -%% -backend = py.qctoolkit.serialization.FilesystemBackend(plsdata.path); -serializer = py.qctoolkit.serialization.Serializer(backend); - - -serializer.serialize(pyargs('serializable', general_charge_scan, 'overwrite', true)) - diff --git a/README.md b/README.md index 38509803a..317fb38be 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,13 @@ The current feature list is as follows: - Hardware model representation - High-level pulse to hardware configuration and waveform translation routines - Hardware drivers for Tabor Electronics, Tektronix and Zurich Instruments AWGs and AlazarTech Digitizers -- MATLAB interface to access qupulse functionality Pending changes are tracked in the `changes.d` subdirectory and published in [`RELEASE_NOTES.rst`](RELEASE_NOTES.rst) on release using the tool `towncrier`. +### Removed features + +The previous name of this package was qctoolkit. It was renamed in 2017 to highlight the pulse focus. The backward compatible alias was removed after the 0.9 release. Furthermore, this repository had a MATLAB interface for a longer time which was removed at the same time. + ## Installation qupulse is available on [PyPi](https://pypi.org/project/qupulse/) and the latest release can be installed by executing: ```sh @@ -38,28 +41,42 @@ Alternatively, the current development version of qupulse can be installed by ex ```sh python -m pip install -e git+https://github.com/qutech/qupulse.git#egg=qupulse[default] ``` -which will clone the github repository to `./src/qupulse` and do an editable/development install. +which will clone the github repository to `./src/qupulse` and do an editable/development install. ### Requirements and dependencies -qupulse requires at least Python 3.7 and is tested on 3.7, 3.8 and 3.9. It relies on some external Python packages as dependencies. +qupulse requires at least Python 3.10 and is tested on 3.10, 3.11 and 3.12. It relies on some external Python packages as dependencies. We intentionally did not restrict versions of dependencies in the install scripts to not unnecessarily prevent usage of newer releases of dependencies that might be compatible. However, if qupulse does encounter problems with a particular dependency version please file an issue. -The backend for TaborAWGs requires packages that can be found [here](https://git.rwth-aachen.de/qutech/python-TaborDriver). As a shortcut you can install it from the python interpreter via `qupulse.hardware.awgs.install_requirements('tabor')`. +The backend for TaborAWGs requires packages that can be found [here](https://git.rwth-aachen.de/qutech/python-TaborDriver). The data acquisition backend for AlazarTech cards needs a package that unfortunately is not open source (yet). If you need it or have questions contact . ## Documentation -You can find documentation on how to use this library on [readthedocs](https://qupulse.readthedocs.io/en/latest/) and [IPython notebooks with examples in this repo](doc/source/examples). You can build it locally with `python setup.py build_sphinx`. +You can find documentation on how to use this library on [readthedocs](https://qupulse.readthedocs.io/en/latest/) and [IPython notebooks with examples in this repo](doc/source/examples). You can build it locally with `hatch run docs:html` if you have pandoc installed. ### Folder Structure -The repository primarily consists of the folders `qupulse` (toolkit core code) and `tests` (toolkit core tests). Additional parts of the project reside in `MATLAB` (MATLAB interface) and `doc` (configuration and source files to build documentation) +The repository primarily consists of the folders `qupulse` (source code), `tests` and `doc`. -`qupulse` contains the entire Python source code of the project and is further partitioned the following packages of related modules +`qupulse` contains the entire Python source code of the project and is further partitioned the following packages of related packages - `pulses` which contains all modules related to pulse representation. - `hardware` containing classes for hardware representation as well as hardware drivers - `utils` containing miscellaneous utility modules or wrapping code for external libraries -- `_program` contains general and hardware specific representations of instantiated (parameter free) pulses. It is private because there is no stability guarantee. +- `program` contains general and hardware specific representations of instantiated (parameter free) pulses. +- `expression` contains the expression interface used by qupulse. Contents of `tests` mirror the structure of `qupulse`. For every `` somewhere in `qupulse` there should exist a `Tests.py` in the corresponding subdirectory of `tests`. +## Development + +`qupulse` uses `hatch` as development tool which provides a convenient interface for most development tasks. The following should work. + + - `hatch build`: Build wheel and source tarball + - `hatch version X.X.X`: Set version + - `hatch run docs:html`: Build documentation (requires pandoc) + - `hatch run docs:clean-notebooks` to execute all example notebooks that start with 00-03 and clean all metadata. + - `hatch run changelog:draft` and `hatch run changelog:release` to preview or update the changelog. + +## License + +The current version of qupulse is available under the `LGPL-3.0-or-later` license. Versions up to and including 0.10 were licensed under the MIT license. If you require different licensing terms, please contact us to discuss your needs. diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index c61c8b8c0..c76c7e9c9 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -2,6 +2,69 @@ .. towncrier release notes start +qupulse 0.10 (2024-04-04) +========================= + +Features +-------- + +- Move HDAWG driver to qupulse-hdawg-legacy to disentangle driver version from qupulse version. The new HDAWG driver will be published under qupulse-hdawg. (`#779 `_) +- Add the `ProgramBuilder` interface pattern to make the generated program of `PulseTemplate.create_program` easily customizable. (`#781 `_) +- Measurement windows can now automatically shrank in case of overlap to counteract small numeric errors. (`#791 `_) + + +Bugfixes +-------- + +- ``ConstantPulseTemplate``s from all versions can now be deserialized. (`#696 `_) +- Fixed that single segment tables where always interpreted to be constant. (`#707 `_) +- Add missing pulse registry support to `ArithmeticPT`. (`#775 `_) + + +qupulse 0.9 (2023-11-08) +======================== + +Features +-------- + +- Add `__pow__` as a repetition shortcut. This means you can do `my_pulse_template ** 5` or `my_pulse_template ** 'my_repetition_count'`. (`#692 `_) +- Promote ``qupulse.expression`` to a subpackage and create ``qupulse.expression.protocol`` with protocol classes that define the expression interface that is supposed to be used by qupulse. + The ```sympy`` based implementation is moved to ``qupulse.expressions.sympy`` and imported in ``qupulse.expressions``. + + The intended use is to be able to use less powerful but faster implementations of the ``Expression`` protocol where appropriate. + In this first iteration, qupulse still relies on internals of the ``sympy`` based implementation in many places which is to be removed in the future. (`#750 `_) +- Promote parts of the private subpackage `qupulse._program` to the public subpackage `qupulse.program`, i.e. `loop`, `volatile`, `transformation` and `waveforms`. This allows external packages/drivers to rely on stability of the `Loop` class. (`#779 `_) +- Add ``PulseTemplate.pad_to`` method to help padding to minimal lengths or multiples of given durations. (`#801 `_) + + +Misc +---- + +- `#771 `_ + + +qupulse 0.8 (2023-03-28) +======================== + +Features +-------- + +- New two dimensional plotting function ``qupulse.pulses.plotting.plot_2d``. (`#703 `_) +- Add support for time dependent expressions for arithmetics with atomic pulse templates i.e. ``ParallelChannelPT`` and + ``ArithmeticPT`` support time dependent expressions if used with atomic pulse templates. + Rename ``ParallelConstantChannelPT`` to ``ParallelChannelPT`` to reflect this change. (`#709 `_) +- Add ``with_`` family of helper methods to ``PulseTemplate`` to allow convinient and easily discoverable pulse template + combination. (`#710 `_) +- The plotting module is now located at `qupulse.plotting`. There is a legacy alias at `qupulse.pulses.plotting`. (`#735 `_) + + +Deprecations and Removals +------------------------- + +- Remove the ``Parameter``, ``MappedParameter`` and ``ConstantParameter`` classes that where deprecated in version 0.5. (`#512 `_) +- Drop support for python version 3.7. (`#760 `_) + + qupulse 0.7 (2022-10-05) ======================== diff --git a/changes.d/512.removal b/changes.d/512.removal deleted file mode 100644 index 83a9d441b..000000000 --- a/changes.d/512.removal +++ /dev/null @@ -1 +0,0 @@ -Remove the `Parameter`, `MappedParameter` and `ConstantParameter` class that where deprecated in version 0.5. diff --git a/changes.d/696.fix b/changes.d/696.fix deleted file mode 100644 index 9df69bd0b..000000000 --- a/changes.d/696.fix +++ /dev/null @@ -1 +0,0 @@ -`ConstantPulseTemplate`s from all versions can now be deserialized. \ No newline at end of file diff --git a/changes.d/707.fix b/changes.d/707.fix deleted file mode 100644 index 33e9e9f8e..000000000 --- a/changes.d/707.fix +++ /dev/null @@ -1 +0,0 @@ -Fixed that single segment tables where always interpreted to be constant. diff --git a/changes.d/709.feature b/changes.d/709.feature deleted file mode 100644 index 9bdf45b12..000000000 --- a/changes.d/709.feature +++ /dev/null @@ -1,3 +0,0 @@ -Add support for time dependent expressions for arithmetics with atomic pulse templates i.e. ParallelChannelPT and -ArithmeticPT support time dependent expressions if used with atomic pulse templates. -Rename `ParallelConstantChannelPT` to `ParallelChannelPT` to reflect this change. diff --git a/changes.d/710.feature b/changes.d/710.feature deleted file mode 100644 index 650482cc2..000000000 --- a/changes.d/710.feature +++ /dev/null @@ -1,2 +0,0 @@ -Add `with_` family of helper methods to `PulseTemplate` to allow convinient and easily discoverable pulse template -combination. diff --git a/changes.d/808.doc b/changes.d/808.doc new file mode 100644 index 000000000..a27837ceb --- /dev/null +++ b/changes.d/808.doc @@ -0,0 +1 @@ +Add an example with a Zurich Instruments HDAWG and MFLI. \ No newline at end of file diff --git a/changes.d/835.removal b/changes.d/835.removal new file mode 100644 index 000000000..cc2f7a5f0 --- /dev/null +++ b/changes.d/835.removal @@ -0,0 +1 @@ +Remove python 3.8 and 3.9 support. Version 3.10 is now the minimal supported version. \ No newline at end of file diff --git a/changes.d/841.removal b/changes.d/841.removal new file mode 100644 index 000000000..fe39edbe9 --- /dev/null +++ b/changes.d/841.removal @@ -0,0 +1 @@ +Remove MATLAB code and the qctoolkit alias for qupulse. diff --git a/changes.d/845.removal b/changes.d/845.removal new file mode 100644 index 000000000..b47bfa1fb --- /dev/null +++ b/changes.d/845.removal @@ -0,0 +1 @@ +Fallback for a missing `gmpy2` via `fractions` was removed. \ No newline at end of file diff --git a/changes.d/853.misc b/changes.d/853.misc new file mode 100644 index 000000000..cf8b7ff32 --- /dev/null +++ b/changes.d/853.misc @@ -0,0 +1 @@ +Remove private and unused frozendict fallback implementations `_FrozenDictByInheritance` and `_FrozenDictByWrapping`. \ No newline at end of file diff --git a/changes.d/882.feature b/changes.d/882.feature new file mode 100644 index 000000000..008540475 --- /dev/null +++ b/changes.d/882.feature @@ -0,0 +1 @@ +Add functions ``PulseTemplate.pad_selected_subtemplates_to`` for padding inner templates and ``PulseTemplate.with_mapped_subtemplates`` as implementation helper. diff --git a/changes.d/882.removal b/changes.d/882.removal new file mode 100644 index 000000000..136b2d3b6 --- /dev/null +++ b/changes.d/882.removal @@ -0,0 +1 @@ +The ``pt_kwargs`` keyword argument of ``PulseTemplate.pad_to`` is now deprecated and was replaced by the ``spt_kwargs`` argument which no longer enforces sequence pulse template creation even if no padding is required. diff --git a/changes.d/888.removal b/changes.d/888.removal new file mode 100644 index 000000000..fcb30d9d4 --- /dev/null +++ b/changes.d/888.removal @@ -0,0 +1 @@ +Remove unused `qupulse.comparable` module. diff --git a/changes.d/904.removal b/changes.d/904.removal new file mode 100644 index 000000000..2ab5c7c0c --- /dev/null +++ b/changes.d/904.removal @@ -0,0 +1 @@ +Remove long deprecated `AtomicPulseTemplate.atomicity`. diff --git a/changes.d/906.feature b/changes.d/906.feature new file mode 100644 index 000000000..57969486b --- /dev/null +++ b/changes.d/906.feature @@ -0,0 +1,4 @@ +Add metadata attribute to ``PulseTemplate`` and the keyword argument to ``SequencePT``, ``RepetitionPT``, ``ForLoopPT`` and ``MappingPT``. +The metadata is intended for user data that does not influence the pulse itself. It is serialized with the pulse template but not part of the equality check because the field is mutable. + +Currently, the only field that is used by qupulse itself is ``to_single_waveform``. When ``to_single_waveform='always'`` is set kin the metadata the corresponding pulse template is translated into a single waveform on program creation. diff --git a/changes.d/907.removal b/changes.d/907.removal new file mode 100644 index 000000000..f0c5bedbd --- /dev/null +++ b/changes.d/907.removal @@ -0,0 +1,2 @@ +The internal structure of `qupulse.program` changed. `Program` and `ProgramBuilder` moved to `qupulse.program.protocol` +with a backwards compatible import. `SimpleExpression` was renamed to `DynamicLinearValue` and lives now in `qupulse.program.values`. diff --git a/changes.d/933.feature b/changes.d/933.feature new file mode 100644 index 000000000..2f44e23f3 --- /dev/null +++ b/changes.d/933.feature @@ -0,0 +1 @@ +Replace PulseTemplate._create_program(**a_lot_of__kwargs) with PulseTemplate._build_program(program_builder). \ No newline at end of file diff --git a/coverage.ini b/coverage.ini index f92469606..aeac2c624 100644 --- a/coverage.ini +++ b/coverage.ini @@ -3,4 +3,3 @@ branch = True omit = *main.py *__init__.py - */qcmatlab/manager.py diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index d0c3cbf10..000000000 --- a/doc/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/README.md b/doc/README.md index 4aab70678..014783155 100644 --- a/doc/README.md +++ b/doc/README.md @@ -8,6 +8,6 @@ You may either build the documentation yourself or read it on [readthedocs](http In the subdirectory *examples* you can find various [Jupyter notebook](http://jupyter.org/) files providing some step-by-step examples of how qupulse can be used. These can be explored in an interactive fashion by running the *Jupyter notebook* application inside the folder. However, a static version will also be included in the documentation created with *sphinx*. ## Building the Documentation -To build the documentation, you will need [sphinx](http://www.sphinx-doc.org/en/stable/) and [nbsphinx](https://nbsphinx.readthedocs.org/) which, in turn, requires [pandoc](http://pandoc.org/). +To build the documentation, you will need [sphinx](http://www.sphinx-doc.org/en/stable/) and [nbsphinx](https://nbsphinx.readthedocs.org/) which, in turn, requires [pandoc](http://pandoc.org/) which must be installed separately. -The documentation is built by invoking `make ` inside the */doc* directory, where `` is an output format supported by *sphinx*, e.g., `html`. The output will then be found in `/doc/build/`. +You can use hatch to build the documentation locally via `hatch run docs:build ` or a bit more concise `hatch run docs:html`. The output will then be found in `/doc/build/`. diff --git a/doc/make.bat b/doc/make.bat deleted file mode 100644 index 9534b0181..000000000 --- a/doc/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 575c546ab..000000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx==4.4.0 -nbsphinx==0.8.8 -ipykernel==6.9.1 diff --git a/doc/source/_templates/autosummary/package.rst b/doc/source/_templates/autosummary/package.rst index aa58817da..ebe119f62 100644 --- a/doc/source/_templates/autosummary/package.rst +++ b/doc/source/_templates/autosummary/package.rst @@ -8,7 +8,7 @@ :toctree: :recursive: {% for item in modules %} - {{ item }} + {{ fullname }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} diff --git a/doc/source/concepts/awgs.rst b/doc/source/concepts/awgs.rst new file mode 100644 index 000000000..e51fc45a0 --- /dev/null +++ b/doc/source/concepts/awgs.rst @@ -0,0 +1,33 @@ +.. _awgs: + +How qupulse models AWGs +----------------------- + +This section is supposed to help you understand how qupulse sees AWGs and by extension help you understand the driver implementations in :py:mod:`~qupulse.hardware.awgs` and :py:mod:`~qupulse.hardware.feature_awg`. + +When a program is uploaded to an arbitrary waveform generator (AWG) it needs to brought in a form that the hardware +understands. +Most AWGs consist of three significant parts: + +* The actual digital to analog converter (DAC) that outputs samples at a (semi-) fixed rate [1]_, +* a sequencer which tells the DAC what to do, +* waveform memory which contains sampled waveforms in a format that the DAC understands. + +The sequencer feeds the data from the waveform memory to the DAC in the correct order. +Uploading a qupulse pulse to an AWG requires to sample the program, upload waveforms to the memory +and program the sequencer. + +The interface exposed by the vendor to program the sequencer reaches from a simple table like for +Tektronix' AWG5000 series to some kind of complex domain specific language (DSL) like Zurich Instrument' sequencing C. + +Basically all AWGs have some kind of limitations regarding the length of the waveform samples which is often of the +form :math:`n_{\texttt{samples}} = n_{\texttt{min}} + m \cdot n_{\texttt{div}}` with the minimal number of samples +:math:`n_{\texttt{min}}` and some divisor :math:`n_{\texttt{div}}`. + +.. topic:: Implementation detail (might be outdated) + + Holding a voltage for a long time was often best accomplished by repeating a waveform of :math:`n_{\texttt{min}}` to save waveform memory. + Earlier versions of qupulse required you to write your pulse in this way i.e. with a ``RepetitionPT``. + Now qupulse contains the function ``qupulse._program._loop.roll_constant_waveform`` which detects long constant waveforms and rolls them into corresponding repetitions. This should be done by the hardware backend automatically. + +.. [1] Some AWGs like the HDAWG can be programmed change the sample rate to a divisor of the "main" rate dynamically. diff --git a/doc/source/concepts/concepts.rst b/doc/source/concepts/concepts.rst index ac17a2c44..a191bb7e1 100644 --- a/doc/source/concepts/concepts.rst +++ b/doc/source/concepts/concepts.rst @@ -6,4 +6,7 @@ This section explains the fundamental design concepts of qupulse. .. toctree:: pulsetemplates serialization - instantiating \ No newline at end of file + instantiating + program + awgs + diff --git a/doc/source/concepts/instantiating.rst b/doc/source/concepts/instantiating.rst index e999e3b51..387db5db6 100644 --- a/doc/source/concepts/instantiating.rst +++ b/doc/source/concepts/instantiating.rst @@ -7,19 +7,25 @@ As already briefly mentioned in :ref:`pulsetemplates`, instantiation of pulses i interpretable representation of a concrete pulse ready for execution from the quite high-level :class:`.PulseTemplate` object tree structure that defines parameterizable pulses in qupulse. -This is a two-step process that involves +The entry point is the :meth:`.PulseTemplate.create_program` method of the :class:`.PulseTemplate` hierarchy. +It accepts the pulse parameters, and allows to rename and/or omit channels or measurements. +It checks that the provided parameters and mappings are consistent and meet the optionally defined parameter constraints of the pulse template. +The translation target is defined by the :class:`.ProgramBuilder` argument. -#. Inserting concrete parameter values and obtaining a hardware-independent pulse program tree -#. Flattening that tree, sampling and merging of leaf waveforms according to needs of hardware +Each pulse template knows what program builder methods to call to translate itself. +For example, the :class:`.ConstantPulseTemplate` calls :meth:`.ProgramBuilder.hold_voltage` to hold a constant voltage for a defined amount of time while the :class:`.SequncePulseTemplate` forwards the program builder to the sub-templates in order. +The resulting program is completely backend dependent. -This separation allows the first step to be performed in a hardware-agnostic way while the second step does not have -to deal with general functionality and can focus only on hardware-specific tasks. Step 1 is implemented in the -:meth:`.PulseTemplate.create_program` method of the :class:`.PulseTemplate` hierarchy. It checks parameter consistency -with parameter constraints and returns an object of type -:class:`.Loop` which represents a pulse as nested loops of atomic waveforms. This is another object tree structure -but all parameters (including repetition counts) have been substituted by the corresponding numeric values passed into -``create_program``. The :class:`.Loop` object acts as your reference to the instantiated pulse. -See :ref:`/examples/06CreatePrograms.ipynb` for an example on usage of :meth:`.PulseTemplate.create_program`. +**Historically**, there was only a single program type :class:`.Loop` which is still the default output type. +As the time of this writing there is the additional :class:`.LinSpaceProgram` which allows for the efficient representation of linearly spaced voltage changes in arbitrary control structures. There is no established way to handle the latter yet. +The following describes handling of :class:`.Loop` object only via the :class:`qupulse.hardware.HardwareSetup`. + +The :class:`.Loop` class was designed as a hardware-independent pulse program tree for waveform table based sequencers. +Therefore, the translation into a hardware specific format is a two-step process which consists of the loop object creation as a first step +and the transformation of that tree according to the needs of the hardware as a second step. +However, the AWGs became more flexibly programmable over the years as discussed in :ref:`awgs`. + +The first step of this pulse instantiation is showcased in :ref:`/examples/02CreatePrograms.ipynb` where :meth:`.PulseTemplate.create_program` is used to create a :class:`.Loop` program. The second step of the instantiation is performed by the hardware backend and transparent to the user. Upon registering the pulse with the hardware backend via :meth:`qupulse.hardware.HardwareSetup.register_program`, the backend will determine which @@ -37,6 +43,6 @@ by the driver with its neighbors in the execution sequence until the minimum wav optimizations and merges (or splits) of waveforms for performance are also possible. In contrast, the Zurich Instruments HDAWG allows arbitrary nesting levels and is only limited by the instruction cache. +However, this device supports increment commands which allow the efficient representation of linear voltage sweeps which is **not** possible with the :class:`.Loop` class. -However, as already mentioned, the user does not have to be concerned about this in regular use of qupulse, since this -is dealt with transparently in the hardware backend. +The section :ref:`program` touches the ideas behind the current program implementations i.e. :class:`.Loop` and :class:`.LinSpaceProgram`. diff --git a/doc/source/concepts/program.rst b/doc/source/concepts/program.rst new file mode 100644 index 000000000..8591309bd --- /dev/null +++ b/doc/source/concepts/program.rst @@ -0,0 +1,34 @@ +.. _program: + +Instantiated Pulse: Program +--------------------------- + +In qupulse an instantiated pulse template is called a program as it is something that an arbitrary waveform generator (AWG) can execute/playback. +It can be thought of as compact representation of a mapping :math:`\{t | 0 \le t \le t_{\texttt{duration}}\} \rightarrow \mathbb{R}^n` from the time while the program lasts :math:`t` to an n-dimensional voltage space :math:`\mathbb{R}^n`. +The dimensions are named by the channel names. + +Programs are created by the :meth:`~.PulseTemplate.create_program` method of `PulseTemplate` which returns a hardware independent and un-parameterized representation. +The method takes a ``program_builder`` keyword argument that is propagated through the pulse template tree and thereby implements the visitor pattern. +If the argument is not passed :func:`~qupulse.program.default_program_builder()` is used instead which is :class:`.LoopBuilder` by default, i.e. the program created by default is of type :class:`.Loop`. The available program builders, programs and their constituents like :class:`.Waveform` and :class:`.VolatileRepetitionCount` are defined in th :mod:`qupulse.program` subpackage and it's submodules. There is a private ``qupulse._program`` subpackage that was used for more rapid iteration development and is slowly phased out. It still contains the hardware specific program representation for the tabor electronics AWG driver. Zurich instrument specific code has been factored into the separate package ``qupulse-hdawg``. Please refer to the reference and the docstrings for exact interfaces and implementation details. + +The :class:`.Loop` default program is the root node of a tree of loop objects of arbitrary depth. +Each node consists of a repetition count and either a waveform or a sequence of nodes which are repeated that many times. +Iterations like the :class:`.ForLoopPT` cannot be represented natively but are unrolled into a sequence of items. +The repetition count is currently the only property of a program that can be defined as volatile. This means that the AWG driver tries to upload the program in a way, where the repetition count can quickly be changed. This is implemented via the ``VolatileRepetitionCount`` class. + +A much more capable program format is :class:`.LinSpaceNode` which efficiently encodes linearly spaced sweeps in voltage space by utilizing increment commands. It is build via :class:`.LinSpaceBuilder`. +The main complexity of this program class is the efficient handling of interleaved constant points. +The increment and set commands do not only carry a channel and a value but also a dependency key which encodes the dependence of loop indices. +This allows the efficient encoding of + +.. code:: python + + for idx in range(10): + set_voltage(CONSTANT) # No dependencies + set_voltage(OFFSET + idx * FACTOR) # depends on idx with + + for _ in range(10): # loop + set_voltage(CONSTANT, key=None) + increment_by(FACTOR, key=(FACTOR,)) + +The motivation is that increment commands with this capability are available in the HDAWG command table. diff --git a/doc/source/concepts/pulsetemplates.rst b/doc/source/concepts/pulsetemplates.rst index 4b84d3fbc..a94ec578b 100644 --- a/doc/source/concepts/pulsetemplates.rst +++ b/doc/source/concepts/pulsetemplates.rst @@ -8,7 +8,7 @@ qupulse represents pulses as abstract pulse templates. A pulse template can be u There are multiple types of different pulse template classes, briefly explained in the following. :class:`.TablePulseTemplate`, :class:`.PointPulseTemplate` and :class:`.FunctionPulseTemplate` are used to define the atomic building blocks of pulses in the following ways: :class:`.TablePulseTemplate` and :class:`.PointPulseTemplate` allow the user to specify pairs of time and voltage values and choose an interpolation strategy between neighbouring points. Both templates support multiple channels but :class:`.TablePulseTemplate` allows for different time values for different channels meaning that the channels can change their voltages at different times. :class:`.PointPulseTemplate` restricts this to switches at the same time by interpreting the voltage as a vector and provides a more convenient interface for this case. -:class:`.FunctionPulseTemplate` accepts any mathematical function that maps time to voltage values. Internally it uses :class:`.Expression` for function evaluation. +:class:`.FunctionPulseTemplate` accepts any mathematical function that maps time to voltage values. Internally it uses :class:`qupulse.expressions.Expression` for function evaluation. All other pulse template classes are then used to construct arbitrarily complex pulse templates by combining existing ones into new structures [#tree]_: :class:`.SequencePulseTemplate` enables the user to specify a sequence of existing pulse templates (subtemplates) and modify parameter values using a mapping function. @@ -20,8 +20,6 @@ In some cases, it is desired to write a pulse which partly consists of placehold You can do some simple arithmetic with pulses which is implemented via :class:`.ArithmeticPulseTemplate` and :class:`.ArithmeticAtomicPulseTemplate`. The relevant arithmetic operators are overloaded so you do not need to use these classes directly. -In the future might be pulse templates that allow conditional execution like a `BranchPulseTemplate` or a `WhileLoopPulseTemplate`. - All of these pulse template variants can be similarly accessed through the common interface declared by the :class:`.PulseTemplate` base class. [#pattern]_ As the class names are quite long the recommended way for abbreviation is to use the aliases defined in :py:mod:`~qupulse.pulses`. For example :class:`.FunctionPulseTemplate` is aliased as :class:`.FunctionPT` @@ -33,7 +31,7 @@ Parameters As mentioned above, all pulse templates may depend on parameters. During pulse template initialization the parameters simply are the free variables of expressions that occur in the pulse template. For example the :class:`.FunctionPulseTemplate` has expressions for its duration and the voltage time dependency i.e. the underlying function. Some pulse templates provided means to constrain parameters by accepting a list of :class:`.ParameterConstraint` which encapsulate comparative expressions that must evaluate to true for a given parameter set to successfully instantiate a pulse from the pulse template. This can be used to encode physical or logical parameter boundaries at pulse level. -The mathematical expressions (for parameter transformation or as the function of the :class:`.FunctionPulseTemplate`) are encapsulated into an :class:`.Expression` class which wraps `sympy `_ for string evaluation. +The mathematical expressions (for parameter transformation or as the function of the :class:`.FunctionPulseTemplate`) are encapsulated into an :class:`.sympy.Expression` class which wraps `sympy `_ for string evaluation by default. Other more performant or secure backends can potentially be implemented by conforming to the :class:`.protocol.Expression`. Parameters can be mapped to arbitrary expressions via :class:`.mapping_pulse_template.MappingPulseTemplate`. One use case can be deriving pulse parameters from physical quantities. @@ -45,6 +43,62 @@ Measurements Pulses are usually used to manipulate the state of some physical system and the system's response has to be somehow validated and thus measured. qupulse pulse templates allow to define measurement windows that specify at what times measurements should be made and identify those windows with an identifier. After the pulse templates are instantiated, uploading the resulting pulses to the hardware setup will cause qupulse to also configure corresponding measurement devices according to the specified measurement windows. +Metadata +^^^^^^^^ + +Pulse templates have a :attr:`.PulseTemplate.metadata` attribute which is the only mutable part of the class. It is the place for translation hints and user-data. Currently, the only effect on qupulse is that all pulse templates that have the metadata field :attr:`.TemplateMetadata.to_single_waveform` set to 'always' are translated into a single waveform. + +Since it is a regular python object, you can freely add any fields you like to it without changing the class. All your custom fields will be serialized by qupulse if you want to save the template to disk. + +Due to the non-constant nature of the metadata field it is ignored when comparing pulse templates. This is necessary, because pulse templates implement hash. + +Convenience Functionality +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to the fundamental concepts and subclassing structure, :class:`.PulseTemplate` offers a variety of +**convenience features** that make it easier to combine and modify pulses: + +- **Convenience Methods**: + + - :meth:`.PulseTemplate.with_parallel_channels` attaches additional constant channel values in parallel to the + existing channels of a pulse. + - :meth:`.PulseTemplate.with_repetition` repeats a pulse a specified number of times. + - :meth:`.PulseTemplate.with_mapping` enables mapping or renaming of parameters, channel names, and measurement + identifiers. + - :meth:`.PulseTemplate.with_iteration` wraps a pulse into a loop construct, allowing iteration over an index with a + defined range. + - :meth:`.PulseTemplate.with_time_reversal` generates a time-reversed version of a pulse. + - :meth:`.PulseTemplate.with_appended` concatenates additional pulse templates, creating a sequence which can be more + concise than manually building a :class:`.SequencePulseTemplate`. + +- **Padding**: + + - :meth:`.PulseTemplate.pad_to` extends the duration of a pulse template to a desired length, automatically appending + a constant pulse segment that matches the final output values. + - :meth:`.PulseTemplate.pad_selected_subtemplates_to` extends the duration selected subtemplates to a desired length, automatically appending + a constant pulse segment that matches the final output values. By default it pads all atomic subtemplates. + +- **Properties**: + + - :attr:`.PulseTemplate.duration` provides an expression for the pulse’s total duration. + - :attr:`.PulseTemplate.initial_values` and :attr:`.PulseTemplate.final_values` specify the voltage levels at the + start and end of the pulse, respectively. + - :attr:`.PulseTemplate.integral` returns an expression evaluating the area under the pulse for each channel. + +- **Arithmetic**: + + - Basic arithmetic operators (``+``, ``-``, ``*``, ``/``) are overloaded to allow direct numerical combination or + scaling of pulses. + - The :meth:`@` operator (matrix multiplication) is repurposed to represent time-wise concatenation of pulses (see + :meth:`.SequencePulseTemplate.concatenate`). + +- **Utility**: + + - :meth:`.PulseTemplate.with_mapped_subtemplates` allows mapping some or all subtemplates with a configurable recursion strategy. It is used to implement :meth:`.PulseTemplate.pad_selected_subtemplates_to`. + +These convenience features allow for more compact, readable, and flexible pulse definitions, helping to focus on the +overall structure of the experiment. + Obtaining a Concrete Pulse (Pulse Instantiation) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +106,7 @@ To obtain a pulse ready for execution on the hardware from a pulse template, the In order to translate the object structures that encode the pulse template in the software into a (sequential) representation of the concrete pulse with the given parameter values that is understandable by the hardware, we proceed in several steps. -First, the :meth:`.PulseTemplate.create_program` checks parameter consistency with parameter constraints and translates the pulse template into an instantiated program object, which is then further interpreted and sequenced by the hardware backend code (in :py:mod:`~qupulse.hardware`). +First, the :meth:`.PulseTemplate.create_program` checks parameter consistency with parameter constraints and translates the pulse template into an instantiated program object. The nature of this program depends on the targeted hardware and is determined by the ``program_builder`` keyword argument. This program is further interpreted and sequenced by the hardware backend code (in :py:mod:`~qupulse.hardware`). See :ref:`instantiating` for a more in-depth explanation of instantiating pulses. @@ -62,20 +116,22 @@ Relevant Examples Examples demonstrating the construction of pulse templates and parameters from very simple to somewhat more complex pulses are * :ref:`/examples/00SimpleTablePulse.ipynb` -* :ref:`/examples/01AdvancedTablePulse.ipynb` -* :ref:`/examples/02FunctionPulse.ipynb` -* :ref:`/examples/03PointPulse.ipynb` -* :ref:`/examples/03xComposedPulses.ipynb` -* :ref:`/examples/03ConstantPulseTemplate.ipynb` -* :ref:`/examples/05MappingTemplate.ipynb` -* :ref:`/examples/07MultiChannelTemplates.ipynb` -* :ref:`/examples/14ArithmeticWithPulseTemplates.ipynb` +* :ref:`/examples/00AdvancedTablePulse.ipynb` +* :ref:`/examples/00FunctionPulse.ipynb` +* :ref:`/examples/00PointPulse.ipynb` +* :ref:`/examples/00ComposedPulses.ipynb` +* :ref:`/examples/00ConstantPulseTemplate.ipynb` +* :ref:`/examples/00MappingTemplate.ipynb` +* :ref:`/examples/00MultiChannelTemplates.ipynb` +* :ref:`/examples/00ArithmeticWithPulseTemplates.ipynb` + +:ref:`/examples/01ParameterConstraints.ipynb` demonstrates the mentioned parameter constraints. -:ref:`/examples/09ParameterConstraints.ipynb` demonstrates the mentioned parameter constraints. +:ref:`/examples/01Measurements.ipynb` shows how to specify measurements. -:ref:`/examples/08Measurements.ipynb` shows how to specify measurements. +:ref:`/examples/02CreatePrograms.ipynb` illustrates usage of the :meth:`.PulseTemplate.create_program` method. -Finally, :ref:`/examples/06CreatePrograms.ipynb` illustrates usage of the :meth:`.PulseTemplate.create_program` method. +:ref:`physical_examples` show realistic use cases of pulse templates. .. rubric:: Footnotes .. [#tree] Regarded as objects in the programming language, each pulse template is a tree of PulseTemplate objects, where the atomic templates (:class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects) are the leafs while the remaining ones form the inner nodes of the tree. diff --git a/doc/source/concepts/serialization.rst b/doc/source/concepts/serialization.rst index 080de40d1..e44566ffe 100644 --- a/doc/source/concepts/serialization.rst +++ b/doc/source/concepts/serialization.rst @@ -14,7 +14,7 @@ The :class:`.PulseStorage` offers a convenient dictionary-like interface for sto Finally, the :class:`.StorageBackend` interface abstracts the actual storage backend. While currently there only exists a few implementations of this interface, most importantly the :class:`.FilesystemStorageBackend`, this allows to support, e.g., database storage, in the future. :class:`.PulseStorage` requires an instance of :class:`.StorageBackend` which represents its persistent pulse storage during initialization. -For an example of how to use :class:`.PulseStorage` to store and load pulse templates, see :ref:`/examples/04PulseStorage.ipynb` in the examples section. +For an example of how to use :class:`.PulseStorage` to store and load pulse templates, see :ref:`/examples/01PulseStorage.ipynb` in the examples section. Global Pulse Registry ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/conf.py b/doc/source/conf.py index 232f53c67..4d12f5e5c 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -63,7 +63,7 @@ autoclass_content = 'both' autosummary_generate = True -napoleon_include_init_with_doc = True +napoleon_include_init_with_doc = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -81,7 +81,7 @@ # General information about the project. project = 'qupulse' -copyright = '2015-2022, Quantum Technology Group, RWTH Aachen University' +copyright = '2015-2024, Quantum Technology Group, RWTH Aachen University' author = 'Quantum Technology Group and Chair of Software Engineering, RWTH Aachen University' # The version info for the project you're documenting, acts as replacement for @@ -98,7 +98,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -119,7 +119,10 @@ # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +add_module_names = False + +# A string that determines how domain objects (functions, classes, attributes, etc.) are displayed in their table of contents entry. +toc_object_entries_show_parents = 'hide' # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. @@ -320,8 +323,9 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - 'python': ('https://docs.python.org/', None), - 'numpy': ('http://docs.scipy.org/doc/numpy/', None) + 'python': ('https://docs.python.org/3/', None), + 'numpy': ('https://numpy.org/doc/stable/', None), + 'sympy': ('https://docs.sympy.org/latest/', None), } nbsphinx_execute_arguments = [ @@ -330,10 +334,10 @@ ] -def skip(app, what, name, obj, skip, options): +def skip_init(app, what, name, obj, skip, options): if name == "__init__" and hasattr(obj, '__doc__') and isinstance(obj.__doc__, str) and len(obj.__doc__): return True - return skip + return None def change_property_rtype_to_type(app, what, name, obj, options, lines): if what == 'attribute': @@ -342,5 +346,5 @@ def change_property_rtype_to_type(app, what, name, obj, options, lines): lines[i] = line.replace(':rtype: :py:class:', ':type:') def setup(app): - app.connect('autodoc-skip-member', skip) + app.connect('autodoc-skip-member', skip_init) #app.connect('autodoc-process-docstring', change_property_rtype_to_type) diff --git a/doc/source/examples/12AbstractPulseTemplate.ipynb b/doc/source/examples/00AbstractPulseTemplate.ipynb similarity index 87% rename from doc/source/examples/12AbstractPulseTemplate.ipynb rename to doc/source/examples/00AbstractPulseTemplate.ipynb index 050e81f91..7c2899b9e 100644 --- a/doc/source/examples/12AbstractPulseTemplate.ipynb +++ b/doc/source/examples/00AbstractPulseTemplate.ipynb @@ -14,9 +14,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "from qupulse.pulses import AbstractPT, FunctionPT, AtomicMultiChannelPT, PointPT\n", @@ -46,7 +44,7 @@ "output_type": "stream", "text": [ "The integral has been declared so we can get it\n", - "{'Y': Expression('a*b + sin(t_manip)'), 'X': Expression('t_init - cos(t_manip) + 2')}\n", + "{'X': ExpressionScalar('t_init/2 - cos(t_manip) + 2'), 'Y': ExpressionScalar('a*b + t_init/2 + sin(t_manip)')}\n", "\n", "We get an error that for the pulse \"readout\" the property \"duration\" was not specified:\n", "NotSpecifiedError('readout', 'duration')\n" @@ -84,7 +82,7 @@ "text": [ "With wrong integral value:\n", "RuntimeError('Cannot link to target. Wrong value of property \"integral\"')\n", - "the linking worked. The new experiment has now a defined duration of Expression('t_init + t_manip + t_read') .\n" + "the linking worked. The new experiment has now a defined duration of ExpressionScalar('t_init + t_manip + t_read') .\n" ] } ], @@ -107,22 +105,8 @@ } ], "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.7.2" + "name": "python" } }, "nbformat": 4, diff --git a/doc/source/examples/00AdvancedTablePulse.ipynb b/doc/source/examples/00AdvancedTablePulse.ipynb new file mode 100644 index 000000000..1ea295c7b --- /dev/null +++ b/doc/source/examples/00AdvancedTablePulse.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modelling an Advanced TablePulseTemplate\n", + "\n", + "[The SimpleTablePulse example](00SimpleTablePulse.ipynb) shows how a simple parametrized ```TablePT``` on one channel can implemented and how the interpolation works.\n", + "\n", + "This example demonstrates how to set up a more complex ```TablePT```. This means we will include multiple channels and use expressions for times and voltages.\n", + "\n", + "First lets reimplement the pulse from the previous example but this time with a second channel `'B'`, that has the same voltage values but negative. To do this, we extend the entry dict by a second item with the channel ID `'B'` as key and the entry list as value.\n", + "\n", + "Then we plot it to see that it actually works." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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LFlSkDnuKDMzU926dVOTJk00a9YsQ7MAAICiJ98LhQvb2LFjJUlz5sxx+DlWq1VWq9V+Py0tzdWxAABAEXFXH+ku6pKTkxUSEmK/RUVFGR0JAAAUEFOXmsTERKWmptpvx44dMzoSAAAoIIaWmhdffFEWi+W2t7179+Z7/76+vgoODs5xAwAA5mTomprnn39effv2ve02MTExhRMGAAC4NUNLTVhYmMLCwoyMAAAATMJtPv109OhRnT9/XkePHlVWVpa2b98u6cb1pwIDA40NBwAADOc2pWbUqFGaO3eu/X69evUkSatWrVLLli0NSgUAAIoKt/n005w5c2Sz2W65UWgAAIDkRqUGAADgdig1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFCg1AADAFNyi1Bw+fFhPPvmkKleuLH9/f1WpUkWjR49WZmam0dEAAEAR4WV0AEfs3btX2dnZevvttxUbG6tdu3bp6aef1uXLl/Xqq68aHQ8AABQBblFqOnTooA4dOtjvx8TE6LffftOMGTMoNSh2rl7L1tVrWfLz9jQ6CgAUKW5RanKTmpqq0NDQ225jtVpltVrt99PS0go6FlBgPCwW+9fVX14mSXqjR109VDdSlj+MAUBx5RZrav7X/v379eabb+rZZ5+97XbJyckKCQmx36KiogopIeB6ESF+qlexZI7HBi/YrsqJX6tp8kptO3rBmGAAUEQYWmpefPFFWSyW29727t2b4znHjx9Xhw4d1K1bNz399NO33X9iYqJSU1Ptt2PHjhXktwMUKIvFosV/b6ZfRrXTI/Ur5Bg7kXpVD/+/nxX94lL1nrVBp1KvGpQSAIxjsdlsNqNe/MyZMzp37txtt4mJiZGPj48k6cSJE2rZsqXuu+8+zZkzRx4eznWytLQ0hYSEKDU1VcHBwfnODRQVh85e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FBYWlq/nZmdnS1KOw0sAAKD4coszCm/YsEGbNm1S8+bNVapUKR04cEAvv/yyqlSp4vAsDQAAMDe3+PRTQECAPvvsM7Vp00bVqlXTk08+qfj4eK1evVq+vr5GxwMAAEWAW8zU1K5dW99//73RMQAAQBHmFjM1AAAAd0KpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApuBldIDCZLPZJElpaWkGJwEAAI66+Xv75u/xvBSrUpOeni5JioqKMjgJAABwVnp6ukJCQvIct9juVHtMJDs7WydOnFBQUJAsFouhWdLS0hQVFaVjx44pODjY0CxFDe9N3nhv8sZ7kzfem9zxvuStqL03NptN6enpioyMlIdH3itnitVMjYeHhypUqGB0jByCg4OLxH8wRRHvTd54b/LGe5M33pvc8b7krSi9N7ebobmJhcIAAMAUKDUAAMAUKDUG8fX11ejRo+Xr62t0lCKH9yZvvDd5473JG+9N7nhf8uau702xWigMAADMi5kaAABgCpQaAABgCpQaAABgCpQaAABgCpQag0yfPl3R0dHy8/PTvffeq40bNxodyXA//vijunTposjISFksFn3++edGRyoykpOT1ahRIwUFBals2bLq2rWrfvvtN6NjGW7GjBmKj4+3nyCsSZMm+uabb4yOVSRNmDBBFotFgwcPNjqK4caMGSOLxZLjVr16daNjFRnHjx9Xr169VLp0afn7+6t27dravHmz0bEcQqkxwIIFCzR06FCNHj1aW7duVZ06ddS+fXulpKQYHc1Qly9fVp06dTR9+nSjoxQ5q1ev1oABA7R+/XqtWLFC165dU7t27XT58mWjoxmqQoUKmjBhgrZs2aLNmzerdevWeuihh/Trr78aHa1I2bRpk95++23Fx8cbHaXIqFmzpk6ePGm/rVmzxuhIRcKFCxfUrFkzeXt765tvvtHu3bv12muvqVSpUkZHc4wNha5x48a2AQMG2O9nZWXZIiMjbcnJyQamKlok2RYvXmx0jCIrJSXFJsm2evVqo6MUOaVKlbK9++67RscoMtLT021xcXG2FStW2Fq0aGH7xz/+YXQkw40ePdpWp04do2MUScOHD7c1b97c6Bj5xkxNIcvMzNSWLVvUtm1b+2MeHh5q27at1q1bZ2AyuJPU1FRJUmhoqMFJio6srCx9/PHHunz5spo0aWJ0nCJjwIAB6ty5c46fOZD+85//KDIyUjExMXrsscd09OhRoyMVCUuWLFHDhg3VrVs3lS1bVvXq1dM777xjdCyHUWoK2dmzZ5WVlaVy5crleLxcuXI6deqUQangTrKzszV48GA1a9ZMtWrVMjqO4Xbu3KnAwED5+vqqX79+Wrx4sWrUqGF0rCLh448/1tatW5WcnGx0lCLl3nvv1Zw5c7Rs2TLNmDFDhw4d0v3336/09HSjoxnu4MGDmjFjhuLi4rR8+XL1799fgwYN0ty5c42O5pBidZVuwAwGDBigXbt2sQbg/1SrVk3bt29XamqqPv30UyUkJGj16tXFvtgcO3ZM//jHP7RixQr5+fkZHadI6dixo/3r+Ph43XvvvapUqZIWLlyoJ5980sBkxsvOzlbDhg2VlJQkSapXr5527dqlt956SwkJCQanuzNmagpZmTJl5OnpqdOnT+d4/PTp0woPDzcoFdzFwIED9dVXX2nVqlWqUKGC0XGKBB8fH8XGxqpBgwZKTk5WnTp1NGXKFKNjGW7Lli1KSUlR/fr15eXlJS8vL61evVpTp06Vl5eXsrKyjI5YZJQsWVJVq1bV/v37jY5iuIiIiFv+ILjnnnvc5vAcpaaQ+fj4qEGDBlq5cqX9sezsbK1cuZJ1AMiTzWbTwIEDtXjxYn3//feqXLmy0ZGKrOzsbFmtVqNjGK5NmzbauXOntm/fbr81bNhQjz32mLZv3y5PT0+jIxYZly5d0oEDBxQREWF0FMM1a9bsltNF7Nu3T5UqVTIokXM4/GSAoUOHKiEhQQ0bNlTjxo31xhtv6PLly3r88ceNjmaoS5cu5fhL6dChQ9q+fbtCQ0NVsWJFA5MZb8CAAZo/f76++OILBQUF2ddfhYSEyN/f3+B0xklMTFTHjh1VsWJFpaena/78+frhhx+0fPlyo6MZLigo6JY1VyVKlFDp0qWL/VqsYcOGqUuXLqpUqZJOnDih0aNHy9PTUz179jQ6muGGDBmipk2bKikpSd27d9fGjRs1c+ZMzZw50+hojjH641fF1ZtvvmmrWLGizcfHx9a4cWPb+vXrjY5kuFWrVtkk3XJLSEgwOprhcntfJNnee+89o6MZ6oknnrBVqlTJ5uPjYwsLC7O1adPG9u233xodq8jiI9039OjRwxYREWHz8fGxlS9f3tajRw/b/v37jY5VZHz55Ze2WrVq2Xx9fW3Vq1e3zZw50+hIDrPYbDabQX0KAADAZVhTAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSA6DQ9O3bV127djXs9Xv37m2/+vDdyszMVHR0tDZv3uyS/QG4e5xRGIBLWCyW246PHj1aQ4YMkc1mU8mSJQsn1B/88ssvat26tY4cOaLAwECX7HPatGlavHhxjgvUAjAOpQaAS9y8yKYkLViwQKNGjcpxtd/AwECXlYn8eOqpp+Tl5aW33nrLZfu8cOGCwsPDtXXrVtWsWdNl+wWQPxx+AuAS4eHh9ltISIgsFkuOxwIDA285/NSyZUs999xzGjx4sEqVKqVy5crpnXfesV+1PigoSLGxsfrmm29yvNauXbvUsWNHBQYGqly5curdu7fOnj2bZ7asrCx9+umn6tKlS47Ho6OjlZSUpCeeeEJBQUGqWLFijqsRZ2ZmauDAgYqIiJCfn58qVaqk5ORk+3ipUqXUrFkzffzxx3f57gFwBUoNAEPNnTtXZcqU0caNG/Xcc8+pf//+6tatm5o2baqtW7eqXbt26t27tzIyMiRJFy9eVOvWrVWvXj1t3rxZy5Yt0+nTp9W9e/c8X2PHjh1KTU1Vw4YNbxl77bXX1LBhQ23btk1///vf1b9/f/sM09SpU7VkyRItXLhQv/32mz788ENFR0fneH7jxo31008/ue4NAZBvlBoAhqpTp45GjhypuLg4JSYmys/PT2XKlNHTTz+tuLg4jRo1SufOndOOHTsk3VjHUq9ePSUlJal69eqqV6+eZs+erVWrVmnfvn25vsaRI0fk6empsmXL3jLWqVMn/f3vf1dsbKyGDx+uMmXKaNWqVZKko0ePKi4uTs2bN1elSpXUvHlz9ezZM8fzIyMjdeTIERe/KwDyg1IDwFDx8fH2rz09PVW6dGnVrl3b/li5cuUkSSkpKZJuLPhdtWqVfY1OYGCgqlevLkk6cOBArq9x5coV+fr65rqY+Y+vf/OQ2c3X6tu3r7Zv365q1app0KBB+vbbb295vr+/v30WCYCxvIwOAKB48/b2znHfYrHkeOxmEcnOzpYkXbp0SV26dNHEiRNv2VdERESur1GmTBllZGQoMzNTPj4+d3z9m69Vv359HTp0SN98842+++47de/eXW3bttWnn35q3/78+fMKCwtz9NsFUIAoNQDcSv369bVo0SJFR0fLy8uxH2F169aVJO3evdv+taOCg4PVo0cP9ejRQ48++qg6dOig8+fPKzQ0VNKNRcv16tVzap8ACgaHnwC4lQEDBuj8+fPq2bOnNm3apAMHDmj58uV6/PHHlZWVletzwsLCVL9+fa1Zs8ap13r99df10Ucfae/evdq3b58++eQThYeH5zjPzk8//aR27drdzbcEwEUoNQDcSmRkpNauXausrCy1a9dOtWvX1uDBg1WyZEl5eOT9I+2pp57Shx9+6NRrBQUFadKkSWrYsKEaNWqkw4cP6+uvv7a/zrp165SamqpHH330rr4nAK7ByfcAFAtXrlxRtWrVtGDBAjVp0sQl++zRo4fq1KmjESNGuGR/AO4OMzUAigV/f3/Nmzfvtifpc0ZmZqZq166tIUOGuGR/AO4eMzUAAMAUmKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACm8P8BVNLy6vA1a2EAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses.plotting import plot\n", + "from qupulse.pulses import TablePT\n", + "\n", + "param_entries = {'A': [(0, 0),\n", + " ('ta', 'va', 'hold'),\n", + " ('tb', 'vb', 'linear'),\n", + " ('tend', 0, 'jump')],\n", + " 'B': [(0, 0),\n", + " ('ta', '-va', 'hold'),\n", + " ('tb', '-vb', 'linear'),\n", + " ('tend', 0, 'jump')]}\n", + "mirror_pulse = TablePT(param_entries)\n", + "\n", + "parameters = {'ta': 2,\n", + " 'va': 2,\n", + " 'tb': 4,\n", + " 'vb': 3,\n", + " 'tend': 6}\n", + "\n", + "_ = plot(mirror_pulse, parameters, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You may have noticed that we already used an expression in the entry list: `'-va'` and `'-vb'`. Of course we can also do a bit more complex things with these than a simple negation. Let's have a look at the next example where we use some simple mathematical oeprators and built-in functions:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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0KBBqlfP+XpFfn6+fagoNDRULVq00FNPPaUpU6a4Nd4L2QxXJo1bTH5+vmJjY5WXl6eYmBizwwEAuOinn37SgQMH1KpVK4WFhZkdDtzoYv+2rnx+M/QDAAAsi0QFAABYFokKAACwLJppAX9lGFJpYcXz4AjplzUcAMCXkKgA/sgwpLcGSkc2V2wnXyndvZJkBYDPYegH8EelheeSFEk6skkqOFGRwACADyFRAQLF/BTprUEkKwB8CokK4O8S0s89p7ICwMeQqAD+LmOlNHn/uW0qK4DHHTx4UDabTdu3bzc7FKf06dNHEyZMMDsMh0hUAH9ns0mR8RUNtZWorACohaKiIsXFxSk+Pl7FxcVeeU8SFSAQ2GwVs36orACog+XLl6tDhw5KS0vTBx984JX3JFEBAgWVFcCtysvLNW/ePKWkpCg0NFTNmzfXrFmzqhzz7bff6vrrr1dERIQ6d+6sjRs32l87efKkRowYoWbNmikiIkLp6elaunRpla/v06ePxo8fr0cffVRxcXFKSEjQE088UeUYm82mN954Q7feeqsiIiKUmpqqDz/8sMoxu3bt0uDBgxUVFaWmTZtq1KhROnHihMvf85tvvqmRI0dq5MiRLt0pui5IVIBAQmUFvsAwpJICcx4u/B5MnTpVf/zjHzV9+nTt3r1b7777rpo2bVrlmMcff1yTJ0/W9u3b1bZtW40YMUI///yzpIqb9nXr1k0fffSRdu3apfvvv1+jRo3SF198UeUcixcvVmRkpDZv3qx58+bpqaee0urVq6sc8+STT2rYsGHasWOHbrjhBt155506deqUJOn06dPq27evunTpoq1bt2rlypU6duyYhg0b5tI/S3Z2tjZu3Khhw4Zp2LBhWrdunQ4dOuTSOWqDuycD/qikQJqdVPH8saNSSGTV1w2jIjk5suncvsn7KyouLAoHL3J4h93zf369zdHviwNnzpxR48aNtXDhQt17773VXj948KBatWqlN954Q/fcc48kaffu3erQoYP27NmjtLQ0h+e96aablJaWpvnz50uqqKiUlZVp3bp19mN69uypvn376o9//KOkiorKtGnT9PTTT0uSCgoKFBUVpY8//liDBg3SM888o3Xr1mnVqlX2c3z33XdKTk7W3r171bZtW/Xp00dXXHGFFixYUOP3/Pjjj2v37t1asWKFJGno0KG64oor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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "expr_pulse = TablePT({'A': [(0, 'a_0'),\n", + " ('t_1', 'a_0 + exp(theta)', 'hold'),\n", + " ('t_2', 'Abs(x_0 - y_0)', 'linear')],\n", + " 'B': [(0, 'b_0'),\n", + " ('t_1*(b_0/a_0)', 'b_1', 'linear'),\n", + " ('t_2', 'b_2')]})\n", + "_ = plot(expr_pulse, dict(a_0=1.1, theta=2, x_0=0.5, y_0=1, t_1=10, t_2=25, b_0=0.6, b_1=6, b_2=0.4))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " __Is there a requirement that all channels have the same duration?__\n", + " \n", + " No. The shorter channels stay on their last value until the last channel is finished. The duration of the complete pulse template is given as the corresponding expression:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Max(t_A, t_B)\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAGwCAYAAABVdURTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA5gUlEQVR4nO3de3RTZdr+8SstpecWSukBLCepMGA5FrDAyEGGigyKo8CwlJOi4qAMdljyVhHEURA8geIrMsiLzIwjKsIwoiBW5GQVEDqKKAgCRWg509IWW2zy+4NfI6EpJG3KTna+n7WyVrOzs3MnQHOxn2c/t8Vms9kEAABgEgFGFwAAAOBJhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqdYwu4GqzWq06cuSIIiMjZbFYjC4HAAC4wGaz6ezZs2rUqJECAi5/bsbvws2RI0eUlJRkdBkAAKAaDh06pGuuueay+/hduImMjJR04cOJiooyuBoAAOCKwsJCJSUl2b/HL8fvwk3FUFRUVBThBgAAH+PKlBImFAMAAFMh3AAAAFMh3AAAAFPxuzk3riovL9f58+eNLgMeEBQUpMDAQKPLAABcJYSbS9hsNuXn5+vMmTNGlwIPqlevnhISEljbCAD8AOHmEhXBJi4uTmFhYXwZ+jibzaaSkhIdO3ZMkpSYmGhwRQCA2ka4uUh5ebk92DRo0MDocuAhoaGhkqRjx44pLi6OISoAMDkmFF+kYo5NWFiYwZXA0yr+TJlHBQDmR7hxgqEo8+HPFAD8B+EGAACYCuEGAACYCuHGDxw4cEAWi0U5OTlGl+KS3r17a+LEiUaXAQDwUYQb+JzFixfLYrHYbxEREercubPef/99o0sDAHgBwg18UlRUlPLy8pSXl6cdO3YoPT1dQ4cO1e7du40uDQBgMMLNFdhsNpWU/WLIzWazuVyn1WrV7Nmz1bJlSwUHB6tJkyZ65plnHPb58ccf1adPH4WFhal9+/bKzs62P3by5EkNHz5cjRs3VlhYmFJSUvSvf/3L4fm9e/fWhAkT9OijjyomJkYJCQl68sknHfaxWCxauHChbr/9doWFhSk5OVkrV6502Gfnzp0aMGCAIiIiFB8frxEjRujEiRMuv9eK10lISFBCQoKSk5P19NNPKyAgQF9//bVbxwEAmA+L+F3BufPlajN1jSGvveupdIXVde2PKDMzU3/729/00ksvqWfPnsrLy9P333/vsM/jjz+u559/XsnJyXr88cc1fPhw7d27V3Xq1NHPP/+szp07a/LkyYqKitKqVas0YsQIXXvtteratav9GG+++aYyMjL05ZdfKjs7W6NHj1aPHj30u9/9zr7P9OnTNXv2bD333HN65ZVXdNddd+ngwYOKiYnRmTNn1LdvX40dO1YvvfSSzp07p8mTJ2vo0KH69NNPq/U5lZeXa8mSJZKkTp06VesYAADzINyYwNmzZzV37lzNmzdPo0aNkiRde+216tmzp8N+kyZN0sCBAyVdCCBt27bV3r171bp1azVu3FiTJk2y7/vwww9rzZo1eueddxzCTbt27TRt2jRJUnJysubNm6esrCyHcDN69GgNHz5ckjRjxgy9/PLL2rJli26++WbNmzdPHTt21IwZM+z7L1q0SElJSdqzZ4+uu+46l95zQUGBIiIiJEnnzp1TUFCQFixYoGuvvdblzw0AYE6EmysIDQrUrqfSDXttV3z33XcqLS3VTTfddNn92rVrZ/+5osfSsWPH1Lp1a5WXl2vGjBl65513dPjwYZWVlam0tLTSas0XH6PiOBV9m5ztEx4erqioKPs+//3vf7Vu3Tp7MLnYvn37XA43kZGR2r59uySppKREn3zyicaNG6cGDRpo0KBBLh0DAGBOhJsrsFgsLg8NGaWid9KVBAUF2X+uWLHXarVKkp577jnNnTtXc+bMUUpKisLDwzVx4kSVlZVVeYyK41Qcw5V9ioqKNGjQIM2aNatSfe40tQwICFDLli3t99u1a6ePP/5Ys2bNItwAgJ/z7m9tuCQ5OVmhoaHKysrS2LFjq3WMzZs367bbbtPdd98t6ULo2bNnj9q0aePJUtWpUyctW7ZMzZo1U506nv3rFxgYqHPnznn0mAAA38PVUiYQEhKiyZMn69FHH9WSJUu0b98+ffHFF3rjjTdcPkZycrLWrl2rzz//XN99950eeOABHT161OO1jh8/XqdOndLw4cO1detW7du3T2vWrNGYMWNUXl7u8nFsNpvy8/OVn5+v/fv3a8GCBVqzZo1uu+02j9cMAPAtnLkxiSeeeEJ16tTR1KlTdeTIESUmJmrcuHEuP3/KlCn68ccflZ6errCwMN1///0aPHiwCgoKPFpno0aNtHnzZk2ePFn9+/dXaWmpmjZtqptvvlkBAa5n7cLCQvswVnBwsJo2baqnnnpKkydP9mi9AADfY7G5s5iKCRQWFio6OloFBQWKiopyeOznn3/W/v371bx5c4WEhBhUIWoDf7YA4Nsu9/19KYalAACAqRgabmbOnKkuXbooMjJScXFxGjx4sEvL57/77rtq3bq1QkJClJKSog8//PAqVAsAAHyBoeFm/fr1Gj9+vL744gutXbtW58+fV//+/VVcXFzlcz7//HMNHz5c9957r3bs2KHBgwdr8ODB2rlz51WsHAAAeCuvmnNz/PhxxcXFaf369brxxhud7jNs2DAVFxfrgw8+sG+74YYb1KFDB82fP/+Kr8GcG//Eny1gQjabdL7E6Cp8ns1m07nzF65WDQ2LlMWNizuuJnfm3HjV1VIVV+bExMRUuU92drYyMjIctqWnp2vFihVO9y8tLVVpaan9fmFhYc0LBQAYy2qVFtwo5X9jdCU+zyKpYi36kkm5CouINrIcj/CaeGa1WjVx4kT16NFD119/fZX75efnKz4+3mFbfHy88vPzne4/c+ZMRUdH229JSUkerRsAcJVZrdK8VIINquQ1Z27Gjx+vnTt3atOmTR49bmZmpsOZnsLCQgIOAPiqimBzat+F+zHXSg9skP5/Sxm4xmq1aeArm3Tg5K9zXDs1qa9/hEUaWJXneEW4eeihh/TBBx9ow4YNuuaaay67b0JCQqWVc48ePaqEhASn+wcHBys4ONhjtQIADOIs2Dy0TfLSOSLeyGazqaSsXL+ft0n7T5ZLClHz2HB98HBPhdUNtPcd9HWG/o2w2Wx66KGHtHz5cn366adq3rz5FZ+TlpamrKwsh21r165VWlpabZXp8w4cOCCLxaKcnByjS3FJ7969NXHiRKPLAOAtbDaptIhgU0NWq00DX96kttPWaP+JC2dsmseGKyujl8KD65gm2EgGn7kZP3683nrrLf373/9WZGSkfd5MdHS0vdP1yJEj1bhxY82cOVOS9Oc//1m9evXSCy+8oIEDB+rtt9/Wtm3btGDBAsPeB4xx7tw5NW7cWAEBATp8+DBn6AAzstmkRenSoS9/3UawcZvVatNNL663hxpJapMYpQ8e7qmAAPOEmgqG/s147bXXVFBQoN69eysxMdF+W7p0qX2f3Nxc5eXl2e93795db731lhYsWKD27dvrvffe04oVKy47CRnmtGzZMrVt21atW7eu8mo5AD6urNgx2CSkEGzcYLPZVFz6i0OwaR4brm+np2vVBHMGG8kLhqWc3UaPHm3f57PPPtPixYsdnjdkyBDt3r1bpaWl2rlzp2655ZarW7gXslqtmj17tlq2bKng4GA1adJEzzzzjMM+P/74o/r06aOwsDC1b99e2dnZ9sdOnjyp4cOHq3HjxgoLC1NKSor+9a9/OTy/d+/emjBhgh599FHFxMQoISFBTz75pMM+FotFCxcu1O23366wsDAlJydr5cqVDvvs3LlTAwYMUEREhOLj4zVixAidOHHC7ff8xhtv6O6779bdd9/tVgd0AD6gYijq9YvWPJu0V3pgI8HGRf40DHUp/oZcic124X8ORtzcWF8xMzNTzz77rJ544gnt2rVLb731VqVL5h9//HFNmjRJOTk5uu666zR8+HD98ssvki4scte5c2etWrVKO3fu1P33368RI0Zoy5YtDsd48803FR4eri+//FKzZ8/WU089pbVr1zrsM336dA0dOlRff/21brnlFt111106deqUJOnMmTPq27evOnbsqG3btmn16tU6evSohg4d6tYfy759+5Sdna2hQ4dq6NCh2rhxow4ePOjWMQB4KatVev230szGv86xSUiRwmO5KspFFcNQu/J+XdutTWKUsjJ6mfZszcW8aoXiq8HtFYrLiqUZjQyoVNJjR6S64Vfc7ezZs2rYsKHmzZunsWPHVnr8wIEDat68uRYuXKh7771XkrRr1y61bdtW3333nVq3bu30uL///e/VunVrPf/885IunLkpLy/Xxo0b7ft07dpVffv21bPPPivpwpmbKVOm6K9//askqbi4WBEREfroo49088036+mnn9bGjRu1Zs0a+zF++uknJSUlaffu3bruuuvUu3dvdejQQXPmzKnyPT/++OPatWuXli9fLkkaPHiwOnToUOlMUgVWKAZ8hM12IdhcvIZNQop0/wbO2LjAfjXUK5scztaY4WoouoL7me+++06lpaW66aabLrtfu3bt7D8nJiZKko4dOyZJKi8v11//+lelpKQoJiZGERERWrNmjXJzc6s8RsVxKo7hbJ/w8HBFRUXZ9/nvf/+rdevWKSIiwn6rCFf79u1z6f2Wl5frzTff1N13323fdvfdd2vx4sWyWq0uHQOAF7LZpOITvwabmGulzMMMRbnIn4eh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FBUVZXQ5gG8oK5ZmNLrw82NHpLrhxtbjREnZL2ozdY0kaddT6Qqra/j/3QB4kDvf3z53tRQAAMDlEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpEG4AAICpeEW4efXVV9WsWTOFhISoW7du2rJly2X3f/fdd9W6dWuFhIQoJSVFH3744VWqFAAAeDvDw83SpUuVkZGhadOmafv27Wrfvr3S09N17Ngxp/t//vnnGj58uO69917t2LFDgwcP1uDBg7Vz586rXDkAAPBGFpvNZjOygG7duqlLly6aN2+eJMlqtSopKUkPP/yw/ud//qfS/sOGDVNxcbE++OAD+7YbbrhBHTp00Pz586/4eoWFhYqOjlZBQYGioqI890Y8yGa16lzJWaPLAH51vkRhc1tLkkom5Up1ww0uqLKSsnKlPv2JJGnXU+kKq1vH4IoAeJI739+G/usvKyvTV199pczMTPu2gIAA9evXT9nZ2U6fk52drYyMDIdt6enpWrFihdP9S0tLVVpaar9fWFhY88Jr2bmSswp7vonRZQBOdX76E51TiNFlAECVDB2WOnHihMrLyxUfH++wPT4+Xvn5+U6fk5+f79b+M2fOVHR0tP2WlJTkmeIBP7TVep3OKdjoMi4rtWl9hQYFGl0GAAOZ/rxtZmamw5mewsJCrw84oWGRF079A16mbVCYdlksRpdxWaFBgbJ4eY0Aapeh4SY2NlaBgYE6evSow/ajR48qISHB6XMSEhLc2j84OFjBwd79P81LWQICFBYRbXQZAAD4JEOHperWravOnTsrKyvLvs1qtSorK0tpaWlOn5OWluawvyStXbu2yv0BAIB/MXxYKiMjQ6NGjVJqaqq6du2qOXPmqLi4WGPGjJEkjRw5Uo0bN9bMmTMlSX/+85/Vq1cvvfDCCxo4cKDefvttbdu2TQsWLDDybQAAAC9heLgZNmyYjh8/rqlTpyo/P18dOnTQ6tWr7ZOGc3NzFRDw6wmm7t2766233tKUKVP02GOPKTk5WStWrND1119v1FsAAABexPB1bq42X1jnBgAAOHLn+9vwFYoBAAA8iXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMpY7RBVxtNptNklRYWGhwJQAAwFUV39sV3+OX43fh5uzZs5KkpKQkgysBAADuOnv2rKKjoy+7j8XmSgQyEavVqiNHjigyMlIWi8XocqpUWFiopKQkHTp0SFFRUUaX47P4HD2Hz9Jz+Cw9g8/Rc3zhs7TZbDp79qwaNWqkgIDLz6rxuzM3AQEBuuaaa4wuw2VRUVFe+xfNl/A5eg6fpefwWXoGn6PnePtneaUzNhWYUAwAAEyFcAMAAEyFcOOlgoODNW3aNAUHBxtdik/jc/QcPkvP4bP0DD5HzzHbZ+l3E4oBAIC5ceYGAACYCuEGAACYCuEGAACYCuEGAACYCuHGC7366qtq1qyZQkJC1K1bN23ZssXoknzOhg0bNGjQIDVq1EgWi0UrVqwwuiSfNXPmTHXp0kWRkZGKi4vT4MGDtXv3bqPL8jmvvfaa2rVrZ18kLS0tTR999JHRZZnCs88+K4vFookTJxpdis958sknZbFYHG6tW7c2uqwaI9x4maVLlyojI0PTpk3T9u3b1b59e6Wnp+vYsWNGl+ZTiouL1b59e7366qtGl+Lz1q9fr/Hjx+uLL77Q2rVrdf78efXv31/FxcVGl+ZTrrnmGj377LP66quvtG3bNvXt21e33Xabvv32W6NL82lbt27V66+/rnbt2hldis9q27at8vLy7LdNmzYZXVKNcSm4l+nWrZu6dOmiefPmSbrQCyspKUkPP/yw/ud//sfg6nyTxWLR8uXLNXjwYKNLMYXjx48rLi5O69ev14033mh0OT4tJiZGzz33nO69916jS/FJRUVF6tSpk/73f/9XTz/9tDp06KA5c+YYXZZPefLJJ7VixQrl5OQYXYpHcebGi5SVlemrr75Sv3797NsCAgLUr18/ZWdnG1gZ8KuCggJJF76YUT3l5eV6++23VVxcrLS0NKPL8Vnjx4/XwIEDHX5nwn0//PCDGjVqpBYtWuiuu+5Sbm6u0SXVmN81zvRmJ06cUHl5ueLj4x22x8fH6/vvvzeoKuBXVqtVEydOVI8ePXT99dcbXY7P+eabb5SWlqaff/5ZERERWr58udq0aWN0WT7p7bff1vbt27V161ajS/Fp3bp10+LFi9WqVSvl5eVp+vTp+u1vf6udO3cqMjLS6PKqjXADwGXjx4/Xzp07TTEmb4RWrVopJydHBQUFeu+99zRq1CitX7+egOOmQ4cO6c9//rPWrl2rkJAQo8vxaQMGDLD/3K5dO3Xr1k1NmzbVO++849PDpYQbLxIbG6vAwEAdPXrUYfvRo0eVkJBgUFXABQ899JA++OADbdiwQddcc43R5fikunXrqmXLlpKkzp07a+vWrZo7d65ef/11gyvzLV999ZWOHTumTp062beVl5drw4YNmjdvnkpLSxUYGGhghb6rXr16uu6667R3716jS6kR5tx4kbp166pz587Kysqyb7NarcrKymJcHoax2Wx66KGHtHz5cn366adq3ry50SWZhtVqVWlpqdFl+JybbrpJ33zzjXJycuy31NRU3XXXXcrJySHY1EBRUZH27dunxMREo0upEc7ceJmMjAyNGjVKqamp6tq1q+bMmaPi4mKNGTPG6NJ8SlFRkcP/PPbv36+cnBzFxMSoSZMmBlbme8aPH6+33npL//73vxUZGan8/HxJUnR0tEJDQw2uzndkZmZqwIABatKkic6ePau33npLn332mdasWWN0aT4nMjKy0pyv8PBwNWjQgLlgbpo0aZIGDRqkpk2b6siRI5o2bZoCAwM1fPhwo0urEcKNlxk2bJiOHz+uqVOnKj8/Xx06dNDq1asrTTLG5W3btk19+vSx38/IyJAkjRo1SosXLzaoKt/02muvSZJ69+7tsP3//u//NHr06KtfkI86duyYRo4cqby8PEVHR6tdu3Zas2aNfve73xldGvzYTz/9pOHDh+vkyZNq2LChevbsqS+++EINGzY0urQaYZ0bAABgKsy5AQAApkK4AQAApkK4AQAApkK4AQAApkK4AQAApkK4AQAApkK4AQAApkK4AQAApkK4AXDVjR49WoMHDzbs9UeMGKEZM2Z45FhlZWVq1qyZtm3b5pHjAag5VigG4FEWi+Wyj0+bNk2PPPKIbDab6tWrd3WKush///tf9e3bVwcPHlRERIRHjjlv3jwtX77coektAOMQbgB4VEVjTUlaunSppk6dqt27d9u3RUREeCxUVMfYsWNVp04dzZ8/32PHPH36tBISErR9+3a1bdvWY8cFUD0MSwHwqISEBPstOjpaFovFYVtERESlYanevXvr4Ycf1sSJE1W/fn3Fx8frb3/7m4qLizVmzBhFRkaqZcuW+uijjxxea+fOnRowYIAiIiIUHx+vESNG6MSJE1XWVl5ervfee0+DBg1y2N6sWTPNmDFD99xzjyIjI9WkSRMtWLDA/nhZWZkeeughJSYmKiQkRE2bNtXMmTPtj9evX189evTQ22+/XcNPD4AnEG4AeIU333xTsbGx2rJlix5++GE9+OCDGjJkiLp3767t27erf//+GjFihEpKSiRJZ86cUd++fdWxY0dt27ZNq1ev1tGjRzV06NAqX+Prr79WQUGBUlNTKz32wgsvKDU1VTt27NCf/vQnPfjgg/YzTi+//LJWrlypd955R7t379Y///lPNWvWzOH5Xbt21caNGz33gQCoNsINAK/Qvn17TZkyRcnJycrMzFRISIhiY2N13333KTk5WVOnTtXJkyf19ddfS7owz6Vjx46aMWOGWrdurY4dO2rRokVat26d9uzZ4/Q1Dh48qMDAQMXFxVV67JZbbtGf/vQntWzZUpMnT1ZsbKzWrVsnScrNzVVycrJ69uyppk2bqmfPnho+fLjD8xs1aqSDBw96+FMBUB2EGwBeoV27dvafAwMD1aBBA6WkpNi3xcfHS5KOHTsm6cLE4HXr1tnn8ERERKh169aSpH379jl9jXPnzik4ONjppOeLX79iKK3itUaPHq2cnBy1atVKEyZM0Mcff1zp+aGhofazSgCMVcfoAgBAkoKCghzuWywWh20VgcRqtUqSioqKNGjQIM2aNavSsRITE52+RmxsrEpKSlRWVqa6dete8fUrXqtTp07av3+/PvroI33yyScaOnSo+vXrp/fee8++/6lTp9SwYUNX3y6AWkS4AeCTOnXqpGXLlqlZs2aqU8e1X2UdOnSQJO3atcv+s6uioqI0bNgwDRs2THfeeaduvvlmnTp1SjExMZIuTG7u2LGjW8cEUDsYlgLgk8aPH69Tp05p+PDh2rp1q/bt26c1a9ZozJgxKi8vd/qchg0bqlOnTtq0aZNbr/Xiiy/qX//6l77//nvt2bNH7777rhISEhzW6dm4caP69+9fk7cEwEMINwB8UqNGjbR582aVl5erf//+SklJ0cSJE1WvXj0FBFT9q23s2LH65z//6dZrRUZGavbs2UpNTVWXLl104MABffjhh/bXyc7OVkFBge68884avScAnsEifgD8yrlz59SqVSstXbpUaWlpHjnmsGHD1L59ez322GMeOR6AmuHMDQC/EhoaqiVLllx2sT93lJWVKSUlRY888ohHjgeg5jhzAwAATIUzNwAAwFQINwAAwFQINwAAwFQINwAAwFQINwAAwFQINwAAwFQINwAAwFQINwAAwFQINwAAwFT+H6NwcMXRlrAyAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "param_entries = {'A': [(0, 0),\n", + " ('t_A/2', 'va', 'hold'),\n", + " ('t_A', 'vb', 'linear')],\n", + " 'B': [(0, 0),\n", + " ('t_B / 2', 'va', 'hold'),\n", + " ('t_B', 'vb', 'linear')]}\n", + "\n", + "c_pulse = TablePT(param_entries)\n", + "print(c_pulse.duration)\n", + "_ = plot(c_pulse, dict(t_A=4, t_B=5, va=1, vb=2, t_wait = 2), sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you see channel `'A'` only was defined until 4ns and holds this level to the end of the pulse." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/00ArithmeticWithPulseTemplates.ipynb b/doc/source/examples/00ArithmeticWithPulseTemplates.ipynb new file mode 100644 index 000000000..1715f000e --- /dev/null +++ b/doc/source/examples/00ArithmeticWithPulseTemplates.ipynb @@ -0,0 +1,246 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Arithmetic with Pulse Templates\n", + "\n", + "Pulse templates support some simple arithmetic operations that make it nearly a vector space. It is implemented via\n", + "the two classes `ArithmeticPulseTemplate` and `ArithmeticAtomicPulseTemplate`. This notebook demonstrates the direct\n", + "and indirect (via invoking operators) usage of these two pulse template classes. We start by defining some building\n", + "blocks." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import math\n", + "from qupulse.pulses import TablePT, FunctionPT, RepetitionPT, AtomicMultiChannelPT, plotting\n", + "\n", + "# define some building blocks\n", + "sin_pt = FunctionPT('sin(omega*t)', 't_duration', channel='X')\n", + "cos_pt = FunctionPT('sin(omega*t)', 't_duration', channel='Y')\n", + "exp_pt = AtomicMultiChannelPT(sin_pt, cos_pt)\n", + "tpt = TablePT({'X': [(0, 0), (3., 4.), ('t_duration', 2., 'linear')],\n", + " 'Y': [(0, 1.), ('t_y', 5.), ('t_duration', 0., 'linear')]})\n", + "\n", + "complex_pt = RepetitionPT(tpt, 5) @ exp_pt\n", + "\n", + "parameters = dict(t_duration=10, omega=math.pi*2/10, t_y=3.4)\n", + "_ = plotting.plot(complex_pt, parameters, show=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Operations with pulse templates and scalars\n", + "Operations between a pulse template and a scalar are implemented via `ArithmeticAtomicPulseTemplate`.\n", + "\n", + "#### Scale\n", + "Given an arbitrary pulse template $P$ and a scalar $\\alpha$ we can scale the amplitude of all channels by multiplying\n", + "$P$ with $\\alpha$. Multiplying with $\\alpha^{-1}$ (some people call it dividing by $\\alpha$) is also implemented. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.expressions import Expression\n", + "\n", + "scaled = 'alpha' * complex_pt\n", + "\n", + "# casts alpha implicitly to ExpressionScalar\n", + "multiplied = complex_pt * 'x + y'\n", + "divided = complex_pt / 4.4\n", + "\n", + "_ = plotting.plot(scaled, {**parameters, 'alpha': 2}, show=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### Offset\n", + "You can add and subtract expression like objects to/from arbitrary pulse templates.\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "offset_pt = scaled + 'offset * alpha'\n", + "\n", + "diff_pt = 4 - complex_pt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### Channel specific operands\n", + "If you only want to apply an operation to a specific subset of a pulse template's channels you can do this by using a\n", + "dictionary as the other operand. Channels not in the dictionary are treated as if the dictionary contains the neutral\n", + "element of the operation i.e. 0 for addition and subtraction and 1 for multiplication and division." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "scaled_x = {'X': 'x_scale'} * complex_pt\n", + "scaled_x_y = {'X': 'x_scale', 'Y': 2} * complex_pt\n", + "\n", + "offset_x = complex_pt + {'X': 2}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Adding and subtracting pulse templates\n", + "Addition and subtraction of pulse templates returns an atomic pulse template, the `ArithmeticAtomicPulseTemplate`\n", + " - Both have the same length\n", + " - Both are atomic. Otherwise they are interpreted as atomic.\n", + " - Channels defined in only one of the two operands are implicitly defined as 0 in the other" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAGwCAYAAACHJU4LAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABAoElEQVR4nO3deXRTdfrH8U/o3tKWnbZaNilWVoGCIvxGUEZARR0VHQ4goIzKoAgdR6aIICit4AJuB9zF+Y0K6uAw4wiDDIIwgAVF4QeC7Mg6rIUWG2jz+6MmNG3SJm2Se5O8X+fk2Nzc3jxNa/Lw/T7P92ux2Ww2AQAAmFAdowMAAABwh0QFAACYFokKAAAwLRIVAABgWiQqAADAtEhUAACAaZGoAAAA04o0OoDaKC0t1cGDB5WYmCiLxWJ0OAAAwAM2m01nzpxRWlqa6tSpeswkqBOVgwcPKj093egwAABADezfv1+XXnpplecEdaKSmJgoqewHTUpKMjgaAADgiYKCAqWnpzs+x6sS1ImKfbonKSmJRAUAgCDjSdkGxbQAAMC0SFQAAIBpkagAAADTCuoaFQBA6CgpKdH58+eNDgM+EBUVpYiICJ9ci0QFAGAom82mw4cP69SpU0aHAh+qV6+eUlJSar3OGYkKAMBQ9iSlSZMmio+PZwHPIGez2VRUVKSjR49KklJTU2t1PRIVAIBhSkpKHElKw4YNjQ4HPhIXFydJOnr0qJo0aVKraSCKaQEAhrHXpMTHxxscCXzN/jutbd0RiQoAwHBM94QeX/1OSVQAAIBpkagAAADTIlEBAMDH9uzZI4vFoo0bNxodikd69+6tcePGGR2GSyQqAADAraeeekqpqak6ceKE0/HvvvtOMTEx+sc//uHX5ydRAQAAbuXk5Cg9PV1jxoxxHDt//ryGDx+uoUOH6uabb/br85OoAABMxWazqch6wZCbzWbzOM7S0lLNnDlTrVu3VkxMjJo1a6bp06c7nbNr1y716dNH8fHx6tSpk9asWeN47Pjx4xo8eLAuueQSxcfHq0OHDvrggw+cvr93794aO3asHnvsMTVo0EApKSl68sknnc6xWCx688039Zvf/Ebx8fHKyMjQokWLnM7ZvHmzBgwYoLp166pp06YaNmyYjh075tHPGRkZqffee0+ffvqpPv74Y0nS9OnTderUKc2aNcvTl6vGWPANAGAq586XqO3kJYY895Zp/RQf7dlHY05Ojt544w3NmjVLvXr10qFDh/TDDz84nfP444/rueeeU0ZGhh5//HENHjxYO3bsUGRkpH7++Wd17dpVEyZMUFJSkj777DMNGzZMl112mbp37+64xrx585Sdna1169ZpzZo1GjFihHr27Klf//rXjnOmTp2qmTNn6tlnn9XLL7+sIUOGaO/evWrQoIFOnTql6667TqNGjdKsWbN07tw5TZgwQXfddZf+/e9/e/SzZmZmKi8vT6NHj1ZiYqLy8vK0ePFiJSUlefT9tWH4iMqBAwc0dOhQNWzYUHFxcerQoYPWr19vdFgAALh15swZvfjii5o5c6aGDx+uyy67TL169dKoUaOcznv00Ud10003qU2bNpo6dar27t2rHTt2SJIuueQSPfroo7ryyivVqlUrPfzww+rfv78WLFjgdI2OHTtqypQpysjI0D333KOsrCwtW7bM6ZwRI0Zo8ODBat26tXJzc3X27Fl9/fXXkqRXXnlFnTt3Vm5urjIzM9W5c2e9/fbbWr58ubZv3+7xz/zII4+offv2uvHGGzV69Gj16dOnJi+d1wwdUTl58qR69uypPn366PPPP1fjxo31448/qn79+kaGBQAwUFxUhLZM62fYc3ti69atKi4u1vXXX1/leR07dnR8bd/z5ujRo8rMzFRJSYlyc3O1YMECHThwQFarVcXFxZVW6S1/Dft17PvouDonISFBSUlJjnO+++47LV++XHXr1q0U386dO9WmTRsPfuKyKabHH39cX375pSZNmuTR9/iCoYnKjBkzlJ6ernfeecdxrGXLlgZGBAAwmsVi8Xj6xSj2vWyqExUV5fjavlJraWmpJOnZZ5/Viy++qNmzZ6tDhw5KSEjQuHHjZLVa3V7Dfh37NTw55+zZsxo4cKBmzJhRKT5vNwyMjIx0+m8gGDr1s2jRImVlZWnQoEFq0qSJOnfurDfeeMPt+cXFxSooKHC6AQAQaBkZGYqLi6s0BeON1atX69Zbb9XQoUPVqVMntWrVyqupGE916dJF//d//6cWLVqodevWTreEhASfP5+vGZqo7Nq1S3PmzFFGRoaWLFmi0aNHa+zYsZo3b57L8/Py8pScnOy4paenBzhiAACk2NhYTZgwQY899pjee+897dy5U2vXrtVbb73l8TUyMjK0dOlS/ec//9HWrVv1wAMP6MiRIz6PdcyYMTpx4oQGDx6s/Px87dy5U0uWLNHIkSNVUlLi8+fzNUPH1kpLS5WVlaXc3FxJUufOnbV582bNnTtXw4cPr3R+Tk6OsrOzHfcLCgpIVgAAhnjiiScUGRmpyZMn6+DBg0pNTdWDDz7o8fdPmjRJu3btUr9+/RQfH6/7779ft912m06fPu3TONPS0rR69WpNmDBBN9xwg4qLi9W8eXP1799fdeoY3lNTLYvNm6ZxH2vevLl+/etf680333QcmzNnjp5++mkdOHCg2u8vKChQcnKyTp8+HZAWKQCAb/3888/avXu3WrZsqdjYWKPDgQ9V9bv15vPb0FSqZ8+e2rZtm9Ox7du3q3nz5gZFBAAAzMTQRGX8+PFau3atcnNztWPHDr3//vt6/fXXnZbpBQAA4cvQRKVbt25auHChPvjgA7Vv315PPfWUZs+erSFDhhgZFgAAMAnDG9Vvvvlmv29oBJiRzWbTufOVK+7joiIc6y0AQLgzPFEBwpHNZtOdc9dow96TlR7Lal5fHz3Yg2QFAGSCvX6AcHTufInLJEWS1u896XKkBQDCESMqgMHWT+qr+OgIFVlLlPX0F0aHAwCmQqICGCw+OsL0+5oAgFGY+gEAwMf27Nkji8WijRs3Gh2KR3r37q1x48YZHYZLJCqACRVZS1RkvaAi6wUZuHg0AEiSJkyYoBYtWujMmTNOxwcOHKhf/epXlXZz9iXGmwETKl+rQhcQAKNNmzZNn332mbKzs/XGG29Ikt5++20tX75c3333nV/3DGJEBTCJuKgIZTWvX+k4XUCAOZWWlmrmzJlq3bq1YmJi1KxZM02fPt3pnF27dqlPnz6Kj49Xp06dtGbNGsdjx48f1+DBg3XJJZcoPj5eHTp00AcffOD0/b1799bYsWP12GOPqUGDBkpJSdGTTz7pdI7FYtGbb76p3/zmN4qPj1dGRoYWLVrkdM7mzZs1YMAA1a1bV02bNtWwYcN07Ngxj3/WmJgYzZs3T/PmzdPixYu1b98+jR8/XjNnztRll13m8XVqgkQFMAmLxaKPHuyhLdP6acu0flo/qa/RIQHGsNkka6ExNy+mWnNycvTMM8/oiSee0JYtW/T++++radOmTuc8/vjjevTRR7Vx40a1adNGgwcP1oULFySVbdrXtWtXffbZZ9q8ebPuv/9+DRs2TF9//bXTNebNm6eEhAStW7dOM2fO1LRp07R06VKnc6ZOnaq77rpL33//vW688UYNGTJEJ06ckCSdOnVK1113nTp37qz169dr8eLFOnLkiO666y6vfi1du3ZVTk6ORo0apWHDhql79+4aPXq0V9eoCUN3T64tdk9GsCqyXlDbyUskSVum9XPZ9ePJOUCwc7nDrrVQyk0zJqCJB6XohGpPO3PmjBo3bqxXXnlFo0aNqvT4nj171LJlS7355pu67777JElbtmxRu3bttHXrVmVmZrq87s0336zMzEw999xzkspGVEpKSvTVV185zunevbuuu+46PfPMM5LK/pEzadIkPfXUU5KkwsJC1a1bV59//rn69++vp59+Wl999ZWWLFniuMZPP/2k9PR0bdu2TW3atFHv3r115ZVXavbs2VX+3OfPn9dll12mo0ePavv27WrWrJnbc321ezLvfAAAeGnr1q0qLi7W9ddfX+V5HTt2dHydmpoqSTp69KgyMzNVUlKi3NxcLViwQAcOHJDValVxcbHi4+PdXsN+naNHj7o9JyEhQUlJSY5zvvvuOy1fvlx169atFN/OnTvVpk0bD37iMkuXLtXhw4clSfn5+VUmKr5CogIEgSKrc40K+wEhpEXFl41sGPXcHoiLi/PsclFRjq/t/8/aO2SeffZZvfjii5o9e7Y6dOighIQEjRs3Tlar1e017Nep2GVT1Tlnz57VwIEDNWPGjErx2ZMnT5w8eVK/+93vNGnSJNlsNv3+97/Xtddeq0aNGnl8jZogUQGCQMUVa+kEQkizWDyafjFSRkaG4uLitGzZMpdTP55YvXq1br31Vg0dOlRSWQKzfft2tW3b1pehqkuXLvrkk0/UokULRUbW/GP/4YcfVkpKiiZOnChJ+tvf/qYxY8Zo/vz5vgrVJYppAZNy1wUk0QkEGC02NlYTJkzQY489pvfee087d+7U2rVr9dZbb3l8jYyMDC1dulT/+c9/tHXrVj3wwAM6cuSIz2MdM2aMTpw4ocGDBys/P187d+7UkiVLNHLkSJWUePY+snDhQn300UeaN2+eIiMjFRkZqXnz5unTTz/VJ5984vOYy2NEBTApexdQ+YSE/YAA83jiiScUGRmpyZMn6+DBg0pNTdWDDz7o8fdPmjRJu3btUr9+/RQfH6/7779ft912m06fPu3TONPS0rR69WpNmDBB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//vfbe3bt7fFxMTYMjMzba+//rrRIYWcgoIC2yOPPGJr1qyZLTY21taqVSvb448/bisuLjY6tKC2fPlyl+/Hw4cPt9lsZS3KTzzxhK1p06a2mJgY2/XXX2/btm1bwOKz2Gws6QcAAMyJGhUAAGBaJCoAAMC0SFQAAIBpkagAAADTIlEBAACmRaICAABMi0QFAACYFokKAAAwLRIVALUyYsSIwC2l7cKwYcMcuxbXltVqVYsWLbR+/XqfXA9A7bEyLQC3LBZLlY9PmTJF48ePl81mU7169QITVDnfffedrrvuOu3du1d169b1yTVfeeUVLVy40GkTNgDGIVEB4JZ9s0hJmj9/viZPnuy0S3DdunV9liDUxKhRoxQZGam5c+f67JonT55USkqKvvnmG7Vr185n1wVQM0z9AHArJSXFcUtOTpbFYnE6Vrdu3UpTP71799bDDz+scePGqX79+mratKneeOMNxy7kiYmJat26tT7//HOn59q8ebMGDBigunXrqmnTpho2bJiOHTvmNraSkhJ9/PHHGjhwoNPxFi1aKDc3V/fee68SExPVrFkzp12MrVarHnroIaWmpio2NlbNmzdXXl6e4/H69eurZ8+e+vDDD2v56gHwBRIVAD43b948NWrUSF9//bUefvhhjR49WoMGDdI111yjb775RjfccIOGDRumoqIiSdKpU6d03XXXqXPnzlq/fr0WL16sI0eO6K677nL7HN9//71Onz6trKysSo89//zzysrK0rfffqvf//73Gj16tGMk6KWXXtKiRYu0YMECbdu2TX/5y1/UokULp+/v3r27vvrqK9+9IABqjEQFgM916tRJkyZNUkZGhnJychQbG6tGjRrpd7/7nTIyMjR58mQdP35c33//vaSyupDOnTsrNzdXmZmZ6ty5s95++20tX75c27dvd/kce/fuVUREhJo0aVLpsRtvvFG///3v1bp1a02YMEGNGjXS8uXLJUn79u1TRkaGevXqpebNm6tXr14aPHiw0/enpaVp7969Pn5VANQEiQoAn+vYsaPj64iICDVs2FAdOnRwHGvatKkk6ejRo5LKimKXL1/uqHmpW7euMjMzJUk7d+50+Rznzp1TTEyMy4Lf8s9vn66yP9eIESO0ceNGXX755Ro7dqz+9a9/Vfr+uLg4x2gPAGNFGh0AgNATFRXldN9isTgdsycXpaWlkqSzZ89q4MCBmjFjRqVrpaamunyORo0aqaioSFarVdHR0dU+v/25unTpot27d+vzzz/XF198obvuukt9+/bVxx9/7Dj/xIkTaty4sac/LgA/IlEBYLguXbrok08+UYsWLRQZ6dnb0pVXXilJ2rJli+NrTyUlJenuu+/W3XffrTvvvFP9+/fXiRMn1KBBA0llhb2dO3f26poA/IOpHwCGGzNmjE6cOKHBgwcrPz9fO3fu1JIlSzRy5EiVlJS4/J7GjRurS5cuWrVqlVfP9cILL+iDDz7QDz/8oO3bt+ujjz5SSkqK0zowX331lW644Yba/EgAfIREBYDh0tLStHr1apWUlOiGG25Qhw4dNG7cONWrV0916rh/mxo1apT+8pe/ePVciYmJmjlzprKystStWzft2bNH//znPx3Ps2bNGp0+fVp33nlnrX4mAL7Bgm8Agta5c+d0+eWXa/78+erRo4dPrnn33XerU6dOmjhxok+uB6B2GFEBELTi4uL03nvvVbkwnDesVqs6dOig8ePH++R6AGqPERUAAGBajKgAAADTIlEBAACmRaICAABMi0QFAACYFokKAAAwLRIVAABgWiQqAADAtEhUAACAaZGoAAAA0/p/FEaMvyNV3twAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjUAAAGwCAYAAABRgJRuAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA730lEQVR4nO3deXSU9b3H8c9kX4ksgSQa9mgKIgIRFOkVkCugYulVsBxBQEGhqIXoFYIsRYUIoiLqkbpQsddaUCqlpYCIVAEBQQHhsMmObJE1kGACydw/YsZkMklmkmeW55n365wcMtsz30xC5pPf7/v7PTa73W4XAACAyYX4uwAAAAAjEGoAAIAlEGoAAIAlEGoAAIAlEGoAAIAlEGoAAIAlEGoAAIAlhPm7AF8qLi7WsWPHFB8fL5vN5u9yAACAG+x2uy5cuKCUlBSFhFQ+HhNUoebYsWNKTU31dxkAAKAGjhw5omuuuabS24Mq1MTHx0sqeVHq1Knj52oAAIA7cnNzlZqa6ngfr0xQhZrSKac6deoQagAAMJnqWkdoFAYAAJZAqAEAAJZAqAEAAJYQVD01AADrKCoq0uXLl/1dBgwQHh6u0NDQWh+HUAMAMBW73a4TJ07o3Llz/i4FBrrqqquUlJRUq33kCDUAAFMpDTQNGzZUTEwMm6manN1uV35+vnJyciRJycnJNT4WoQYAYBpFRUWOQFO/fn1/lwODREdHS5JycnLUsGHDGk9F0SgMADCN0h6amJgYP1cCo5V+T2vTJ0WoAQCYDlNO1mPE95RQAwAALIFQAwAALIFQAwCAnx08eFA2m01btmzxdylu6dq1q0aPHu3vMiog1AAAAMM899xzSk5O1pkzZ8pdv3XrVkVGRupf//qX156bUAMAAAyTlZWl1NRUjRo1ynHd5cuXNXjwYA0cOFB33323156bUAMAMDW73a78wis+/7Db7R7VWVxcrBkzZqhly5aKjIxU48aNNXXq1HL32b9/v7p166aYmBi1bdtW69atc9x2+vRpDRgwQFdffbViYmLUpk0bffjhh+Ue37VrVz3xxBN6+umnVa9ePSUlJemPf/xjufvYbDa98847+u1vf6uYmBilpaVp8eLF5e6zfft29e7dW3FxcWrUqJEGDRqkU6dOufV1hoWF6f3339eiRYv08ccfS5KmTp2qc+fO6ZVXXnH35aoRNt8DAJjapctFajVpuc+fd8ezPRUT4f7baFZWlt5++2298sor6tKli44fP65du3aVu88zzzyjmTNnKi0tTc8884wGDBigvXv3KiwsTD/99JM6dOigsWPHqk6dOlqyZIkGDRqkFi1aqGPHjo5jzJs3T5mZmdqwYYPWrVunIUOG6NZbb9V///d/O+4zZcoUzZgxQy+++KJee+01PfDAAzp06JDq1aunc+fOqXv37ho2bJheeeUVXbp0SWPHjlX//v31+eefu/W1pqenKzs7WyNHjlR8fLyys7O1bNky1alTx+3XqyZsdk+jponl5uYqISFB58+f9/oLCwAw3k8//aQDBw6oWbNmioqKkiTlF14J+FBz4cIFJSYm6vXXX9ewYcMq3H7w4EE1a9ZM77zzjh5++OGS4+/YodatW2vnzp1KT093edy7775b6enpmjlzpqSSkZqioiKtXr3acZ+OHTuqe/fueuGFFySVjNRMmDBBzz33nCQpLy9PcXFxWrp0qXr16qXnn39eq1ev1vLlv7ymP/zwg1JTU7V7925de+216tq1q2688UbNmjWr0q/Zbrere/fu+vLLL/X4449XeV/J9fe2lLvv34zUAABMLTo8VDue7emX53XXzp07VVBQoNtvv73K+91www2Oz0vPgZSTk6P09HQVFRVp2rRpWrBggY4eParCwkIVFBRU2F257DFKj1N6XiVX94mNjVWdOnUc99m6datWrVqluLi4CvXt27dP1157rRtfcUl4euaZZ/Sf//xHEyZMcOsxtUWoAQCYms1m82gayB9Kz21UnfDwcMfnpTvsFhcXS5JefPFFvfrqq5o1a5batGmj2NhYjR49WoWFhZUeo/Q4pcdw5z4XL15Unz59NH369Ar1eXqyybCwsHL/eltg/xQAAGABaWlpio6O1sqVK11OP7lj7dq1+s1vfqOBAwdKKgk7e/bsUatWrYwsVe3bt9fChQvVtGlTn4URo7D6CQAAL4uKitLYsWP19NNP6/3339e+ffu0fv16vfvuu24fIy0tTStWrNBXX32lnTt36tFHH9XJkycNr3XUqFE6c+aMBgwYoI0bN2rfvn1avny5hg4dqqKiIsOfz0jmimAAAJjUxIkTFRYWpkmTJunYsWNKTk7WiBEj3H78hAkTtH//fvXs2VMxMTF65JFH1LdvX50/f97QOlNSUrR27VqNHTtW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kZSU5PhISEiQzWYrd11cXFyF6aeuXbvq8ccf1+jRo1W3bl01atRIb7/9tuNM9/Hx8WrZsqWWLl1a7rm2b9+u3r17Ky4uTo0aNdKgQYN06tSpSmsrKirSxx9/rD59+pS7vmnTppo2bZoeeughxcfHq3HjxuXOll1YWKjHHntMycnJioqKUpMmTZSdne24vW7durr11lv1t7/9rZavHgAjEGoA+NW8efPUoEEDff3113r88cc1cuRI9evXT507d9a3336rO+64Q4MGDVJ+fr4k6dy5c+revbvatWunTZs2admyZTp58qT69+9f6XN89913On/+vDIyMirc9tJLLykjI0ObN2/W73//e40cOdIxwjR79mwtXrxYCxYs0O7du/XBBx+oadOm5R7fsWNHrV692rgXBECNEWoA+FXbtm01YcIEpaWlKSsrS1FRUWrQoIGGDx+utLQ0TZo0SadPn9Z3330nqaSPpV27dpo2bZrS09PVrl07zZ07V6tWrdKePXtcPsehQ4cUGhqqhg0bVrjtzjvv1O9//3u1bNlSY8eOVYMGDbRq1SpJ0uHDh5WWlqYuXbqoSZMm6tKliwYMGFDu8SkpKTp06JDBrwqAmiDUAPCrG264wfF5aGio6tevrzZt2jiua9SokSQpJydHUknD76pVqxw9OnFxcUpPT5ck7du3z+VzXLp0SZGRkS6bmcs+f+mUWelzDRkyRFu2bNF1112nJ554Qp9++mmFx0dHRztGkQD4V5i/CwAQ3MLDw8tdttls5a4rDSLFxcWSpIsXL6pPnz6aPn16hWMlJye7fI4GDRooPz9fhYWFioiIqPb5S5+rffv2OnDggJYuXarPPvtM/fv3V48ePfTxxx877n/mzBklJia6++UC8CJCDQBTad++vRYuXKimTZsqLMy9X2E33nijJGnHjh2Oz91Vp04d3X///br//vt13333qVevXjpz5ozq1asnqaRpuV27dh4dE4B3MP0EwFRGjRqlM2fOaMCAAdq4caP27dun5cuXa+jQoSoqKnL5mMTERLVv315r1qzx6Llefvllffjhh9q1a5f27Nmjjz76SElJSeX22Vm9erXuuOOO2nxJAAxCqAFgKikpKVq7dq2Kiop0xx13qE2bNho9erSuuuoqhYRU/itt2LBh+uCDDzx6rvj4eM2YMUMZGRm66aabdPDgQf373/92PM+6det0/vx53XfffbX6mgAYg833AASFS5cu6brrrtP8+fN1yy23GHLM+++/X23bttX48eMNOR6A2mGkBkBQiI6O1vvvv1/lJn2eKCwsVJs2bTRmzBhDjgeg9hipAQAAlsBIDQAAsARCDQAAsARCDQAAsARCDQAAsARCDQAAsARCDQAAsARCDQAAsARCDQAAsARCDQAAsIT/B7yLwJV9sTObAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "_ = plotting.plot(exp_pt + tpt, parameters, show=False)\n", + "_ = plotting.plot(exp_pt - tpt, parameters, show=False)\n", + "\n", + "combined = exp_pt + tpt" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Manual creation\n", + "For exact control what is needed we can use the classes directly instead of implicitly via the operators" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Simon\\AppData\\Local\\Temp\\ipykernel_11640\\2452374967.py:6: ImplicitAtomicityInArithmeticPT: ArithmeticAtomicPulseTemplate treats all operands as if they are atomic. You can silence this warning by passing `silent_atomic=True` or by ignoring this category.\n", + " complex_added_1 = ArithmeticAtomicPT(complex_pt, '+', complex_pt)\n" + ] + } + ], + "source": [ + "from qupulse.pulses import ArithmeticPT, ArithmeticAtomicPT\n", + "\n", + "scaled_x = ArithmeticPT({'X': 'x_scale'}, '*', complex_pt, identifier='scaled_x')\n", + "\n", + "# this raises a warning because complex_pt is treated as atomic\n", + "complex_added_1 = ArithmeticAtomicPT(complex_pt, '+', complex_pt)\n", + "\n", + "# this raises a warning because complex_pt is treated as atomic\n", + "complex_added_2 = ArithmeticAtomicPT(complex_pt, '+', complex_pt, silent_atomic=True)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/doc/source/examples/00ComposedPulses.ipynb b/doc/source/examples/00ComposedPulses.ipynb new file mode 100644 index 000000000..014eb4e53 --- /dev/null +++ b/doc/source/examples/00ComposedPulses.ipynb @@ -0,0 +1,240 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Combining Pulse Templates\n", + "\n", + "So far we have seen how to define simple pulses using the `TablePulseTemplate` ([Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb)), `FunctionPulseTemplate` ([Modelling Pulses Using Functions And Expressions](00FunctionPulse.ipynb)) and `PointPulseTemplate` ([The PointPulseTemplate](00PointPulse.ipynb)) classes. These are the elementary building blocks to create pulses and we call them *atomic* pulse templates.\n", + "\n", + "We will now have a look at how to compose more complex pulse structures.\n", + "\n", + "## SequencePulseTemplate: Putting Pulses in a Sequence\n", + "\n", + "As the name suggests `SequencePulseTemplate` allows us to define a pulse as a sequence of already existing pulse templates which are run one after another. In the following example we have two templates created using `PointPulseTemplate` and want to define a higher-level pulse template that puts them in sequence." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sequence parameters: {'v_0', 'v_1', 't_2', 't'}\n", + "sequence measurements: {'M'}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import PointPT, SequencePT\n", + "# create our atomic \"low-level\" PointPTs\n", + "first_point_pt = PointPT([(0, 'v_0'),\n", + " (1, 'v_1', 'linear'),\n", + " ('t', 'v_0+v_1', 'jump')],\n", + " channel_names=('A',),\n", + " measurements=[('M', 1, 't-1')])\n", + "second_point_pt = PointPT([(0, 'v_0+v_1'),\n", + " ('t_2', 'v_0', 'linear')],\n", + " channel_names=('A',),\n", + " measurements=[('M', 0, 1)])\n", + "\n", + "# define the SequencePT\n", + "sequence_pt = SequencePT(first_point_pt, second_point_pt)\n", + "\n", + "print(\"sequence parameters: {}\".format(sequence_pt.parameter_names))\n", + "print(\"sequence measurements: {}\".format(sequence_pt.measurement_names))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is important to note that all of the pulse templates used to create a `SequencePT` (we call those *subtemplates*) are defined on the same channels, in this case the channel `A` (otherwise we would encounter an exception). The `SequencePT` will also be defined on the same channel.\n", + "\n", + "The `SequencePT` will further have the union of all parameters defined in its subtemplates as its own parameter set. If two subtemplates defined parameters with the same name, they will be treated as the same parameters in the `SequencePT`.\n", + "\n", + "Finally, `SequencePT` will also expose all measurements defined in subtemplates. It is also possible to define additional measurements in the constructor of `SequencePT`. See [Definition of Measurements](01Measurements.ipynb) for me info about measurements.\n", + "\n", + "There are several cases where the above constraints represent a problem: Subtemplates might not all be defined on the same channel, subtemplates might define parameters with the same name which should still be treated as different parameters in the sequence or names of measurements defined by different subtemplates might collide. To deal with these, we can wrap a subtemplate with the `MappingPulseTemplate` class which allows us to rename parameters, channels and measurements or even derive parameter values from other parameters using mathematical expressions. You can learn how to do all this in [Mapping with the MappingPulseTemplate](00MappingTemplate.ipynb).\n", + "\n", + "In our example above, however, we were taking care not to encounter these problems yet. Let's plot all of them with some parameters to see the results." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAGwCAYAAABFFQqPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA3fUlEQVR4nO3dfVxUZf7/8feAOIDAKCkCird4f0OY2qKWN5mmLq27rbqWgqlttmip3RjV2tpusrqaXys3t9LMXVtNTWu7M/IG0kXTkk2zNBXFXNDUBAEXFc7vjx7MLxJwBmcYhvN6Ph7zeDBnrnPmc3EaeXeu6zpjMQzDEAAAgAn5eLoAAAAATyEIAQAA0yIIAQAA0yIIAQAA0yIIAQAA0yIIAQAA0yIIAQAA06rn6QJqWmlpqf773/8qODhYFovF0+UAAAAHGIahCxcuKDIyUj4+rruOY7og9N///ldRUVGeLgMAAFTDiRMn1Lx5c5cdz3RBKDg4WNIPv8iQkBAPVwMAAByRn5+vqKgo+99xVzFdECobDgsJCSEIAQDgZVw9rYXJ0gAAwLQIQgAAwLQIQgAAwLRMN0fIUSUlJbp8+bKny4AL+Pn5ydfX19NlAABqIYLQTxiGodzcXJ0/f97TpcCFGjZsqPDwcO4dBQAohyD0E2UhKCwsTIGBgfzh9HKGYaioqEinT5+WJEVERHi4IgBAbUIQ+pGSkhJ7CLrhhhs8XQ5cJCAgQJJ0+vRphYWFMUwGALBjsvSPlM0JCgwM9HAlcLWyc8q8LwDAjxGEKsBwWN3DOQUAVIQgBAAATIsgBAAATIsgZALHjh2TxWJRZmamp0txyIABAzR9+nRPlwEAMAGCELzWxYsXFRoaqsaNG6u4uNjT5QAAvBBBCF5r/fr16tKlizp27KiNGzd6uhwAgBciCF2DYRgqunTFIw/DMByus7S0VPPnz1d0dLSsVqtatGihZ599tlybo0ePauDAgQoMDFRMTIwyMjLsr509e1Zjx45Vs2bNFBgYqG7duumf//xnuf0HDBigBx98UI899phCQ0MVHh6uP/zhD+XaWCwWvfrqq/rlL3+pwMBAtWvXTu+88065Nvv379ewYcMUFBSkpk2bavz48Tpz5ozDfS2zbNkyjRs3TuPGjdOyZcuc3h8AAG6oeA0XL5eo8+xNHnnvA88MVWB9x05RcnKyXnnlFS1atEj9+vVTTk6Ovv7663JtnnzySS1YsEDt2rXTk08+qbFjx+rw4cOqV6+e/ve//+mmm27SrFmzFBISovfee0/jx49X27Zt1bt3b/sxXn/9dc2cOVO7du1SRkaGJkyYoL59++r222+3t5kzZ47mz5+vv/zlL3rhhRd0zz336Pjx4woNDdX58+c1aNAgTZ48WYsWLdLFixc1a9YsjR49Wlu2bHH4d3PkyBFlZGTorbfekmEYmjFjho4fP66WLVs6fAwAALgiVAdcuHBBixcv1vz585WYmKi2bduqX79+mjx5crl2jzzyiEaMGKH27dtrzpw5On78uA4fPixJatasmR555BHdeOONatOmjaZNm6Y77rhDb775ZrljdO/eXU8//bTatWunhIQE9ezZU5s3by7XZsKECRo7dqyio6M1d+5cFRQU6NNPP5Ukvfjii4qNjdXcuXPVsWNHxcbGavny5dq6dasOHTrkcJ+XL1+uYcOGqVGjRgoNDdXQoUP12muvVefXBwAwMa4IXUOAn68OPDPUY+/tiK+++krFxcW67bbbqmzXvXt3+89l37l1+vRpdezYUSUlJZo7d67efPNNnTx5UpcuXVJxcfFVd9n+8THKjlP2PV4VtWnQoIFCQkLsbf7zn/9o69atCgoKuqq+I0eOqH379tfsb0lJiV5//XUtXrzYvm3cuHF65JFHNHv2bPn4kO8BAI4hCF2DxWJxeHjKU8q+S+ta/Pz87D+X3Wm5tLRUkvSXv/xFixcv1v/93/+pW7duatCggaZPn65Lly5Veoyy45Qdw5E2BQUFio+P17x5866qz9EvRN20aZNOnjypMWPGlNteUlKizZs3lxumAwCgKrX7Lzwc0q5dOwUEBGjz5s1XDYc5aseOHfrFL36hcePGSfohIB06dEidO3d2Zanq0aOH1q9fr1atWqlever957ds2TL95je/0ZNPPllu+7PPPqtly5YRhAAADmMMoQ7w9/fXrFmz9Nhjj2nlypU6cuSIdu7c6dRKqnbt2ik1NVX//ve/9dVXX+n+++/XqVOnXF5rUlKSzp07p7Fjx2r37t06cuSINm3apHvvvVclJSXX3P+7777Tv/71LyUmJqpr167lHgkJCdq4caPOnTvn8roBAHUTQaiO+P3vf6+HH35Ys2fPVqdOnTRmzJir5u5U5amnnlKPHj00dOhQDRgwQOHh4Ro5cqTL64yMjNSOHTtUUlKiIUOGqFu3bpo+fboaNmzo0NyelStXqkGDBhXOh7rtttsUEBCgf/zjHy6vGwBQN1kMZ25WUwfk5+fLZrMpLy9PISEh5V773//+p6ysLLVu3Vr+/v4eqhDuwLkFAO9W1d/v68EVIQAAYFoeDUIpKSnq1auXgoODFRYWppEjR+rgwYMO77969WpZLBa3DOEAAIC6z6NBKC0tTUlJSdq5c6dSU1N1+fJlDRkyRIWFhdfc99ixY3rkkUd0yy231EClAACgLvLo8vkPP/yw3PMVK1YoLCxMn332mW699dZK9yspKdE999yjOXPm6JNPPtH58+ddWpfJpk2ZgtnOqWEYunj52qvwAHivAD9f+z3hUH216j5CeXl5kqTQ0NAq2z3zzDMKCwvTpEmT9Mknn1TZtri4WMXFxfbn+fn5lbYtuxFgUVGRwzcphHcoKiqSdPXNHusiwzD066UZ+uz4954uBYAbOfN9lKhcrfkNlpaWavr06erbt6+6du1aabvt27dr2bJlyszMdOi4KSkpmjNnjkNtfX191bBhQ/uy88DAQNK2lzMMQ0VFRTp9+rQaNmwoX1/HvrbEm128XEIIAgAH1ZoglJSUpP3792v79u2Vtrlw4YLGjx+vV155RY0bN3bouMnJyZo5c6b9eX5+vqKioiptHx4eLklO3YMHtV/Dhg3t59ZM9jw1WIH16374A8zI0e+jRNVqRRCaOnWq3n33XaWnp6t58+aVtjty5IiOHTum+Ph4+7ay77CqV6+eDh48qLZt25bbx2q1ymq1OlyLxWJRRESEwsLCdPnyZSd7gtrIz8/PFFeCKhJY35dL5wBQBY/+C2kYhqZNm6YNGzZo27Ztat26dZXtO3bsqH379pXb9tRTT+nChQtavHhxlVd6nOXr62vaP54AAJiFR4NQUlKS3njjDb399tsKDg5Wbm6uJMlms9knKyckJKhZs2ZKSUmRv7//VfOHGjZsKElVzisCAACoiEeD0EsvvSRJGjBgQLntr732miZMmCBJys7Odug7qAAAAJzl8aGxa9m2bVuVr69YscI1xQAAANPhUgsAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtghAAADAtjwahlJQU9erVS8HBwQoLC9PIkSN18ODBKvd55ZVXdMstt6hRo0Zq1KiRBg8erE8//bSGKgYAAHWJR4NQWlqakpKStHPnTqWmpury5csaMmSICgsLK91n27ZtGjt2rLZu3aqMjAxFRUVpyJAhOnnyZA1WDgAA6gKLYRiGp4so89133yksLExpaWm69dZbHdqnpKREjRo10osvvqiEhIRrts/Pz5fNZlNeXp5CQkKut2Sg1im6dEWdZ2+SJB14ZqgC69fzcEUAcP3c9fe7Vv0LmZeXJ0kKDQ11eJ+ioiJdvny50n2Ki4tVXFxsf56fn399RQIAgDqj1kyWLi0t1fTp09W3b1917drV4f1mzZqlyMhIDR48uMLXU1JSZLPZ7I+oqChXlQwAALxcrQlCSUlJ2r9/v1avXu3wPn/+85+1evVqbdiwQf7+/hW2SU5OVl5env1x4sQJV5UMAAC8XK0YGps6dareffddpaenq3nz5g7ts2DBAv35z3/Wxx9/rO7du1fazmq1ymq1uqpUAABQh3g0CBmGoWnTpmnDhg3atm2bWrdu7dB+8+fP17PPPqtNmzapZ8+ebq4SAADUVR4NQklJSXrjjTf09ttvKzg4WLm5uZIkm82mgIAASVJCQoKaNWumlJQUSdK8efM0e/ZsvfHGG2rVqpV9n6CgIAUFBXmmIwAAwCt5dI7QSy+9pLy8PA0YMEARERH2x5o1a+xtsrOzlZOTU26fS5cu6de//nW5fRYsWOCJLgAAAC/m8aGxa9m2bVu558eOHXNPMQAAwHRqzaoxAACAmkYQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQAgAApkUQ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ALiB00Fo2bJlCg0N1U033SSr1Sqr1aqePXsqNDRUy5YtkyQFBQVp4cKFLi8WAADAlZyeIxQeHq7U1FR9/fXXOnTokCSpQ4cO6tChg73NwIEDXVchAACAm1T7hoodO3ZUx44dXVkLAABAjapWEPr222/1zjvvKDs7W5cuXSr32nPPPeeSwgAAANzN6SC0efNm3XnnnWrTpo2+/vprde3aVceOHZNhGOrRo4c7agQAAHALpydLJycn65FHHtG+ffvk7++v9evX68SJE+rfv79GjRrljhoBAADcwukg9NVXXykhIUGSVK9ePV28eFFBQUF65plnNG/ePKeOlZ6ervj4eEVGRspisWjjxo3X3Ke4uFhPPvmkWrZsKavVqlatWmn58uXOdgMAAMD5obEGDRrY5wVFREToyJEj6tKliyTpzJkzTh2rsLBQMTExmjhxon71q185tM/o0aN16tQpLVu2TNHR0crJyVFpaalznQAAAFA1gtDPfvYzbd++XZ06ddLw4cP18MMPa9++fXrrrbf0s5/9zKljDRs2TMOGDXO4/Ycffqi0tDQdPXpUoaGhkqRWrVo59Z4AAABlnB4ae+6553TzzTdLkubMmaPbbrtNa9asUatWrew3VHSXd955Rz179tT8+fPVrFkztW/fXo888oguXrxY6T7FxcXKz88v9wAAAJCqcUWoTZs29p8bNGigpUuXurSgqhw9elTbt2+Xv7+/NmzYoDNnzuh3v/udzp49q9dee63CfVJSUjRnzpwaqxEAAHgPp68ItWnTRmfPnr1q+/nz58uFJHcoLS2VxWLRqlWr1Lt3bw0fPlzPPfecXn/99UqvCiUnJysvL8/+OHHihFtrBAAA3sPpK0LHjh1TSUnJVduLi4t18uRJlxRVmYiICDVr1kw2m82+rVOnTjIMQ99++63atWt31T5l34cGAADwUw4HoXfeecf+86ZNm8qFkZKSEm3evNntE5f79u2rtWvXqqCgQEFBQZKkQ4cOycfHR82bN3frewMAgLrH4SA0cuRISZLFYlFiYmK51/z8/NSqVSunv3G+oKBAhw8ftj/PyspSZmamQkND1aJFCyUnJ+vkyZNauXKlJOnuu+/WH//4R917772aM2eOzpw5o0cffVQTJ05UQECAU+8NAADgcBAqu1dP69attXv3bjVu3Pi633zPnj3lvql+5syZkqTE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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAGwCAYAAABFFQqPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA+lElEQVR4nO3dfVhUdf7/8dcMCCgCSYhAoWKa5k2GYUVSWpHmXev+WjW3JCvbNNTMbtn8arSlq5v1LXPX3Vaz+9RKc7XN9S4NQ4uSTbM0lcQMvEEFARcUzu8PvzMLAjKDcz/Px3XNdcnhnJk3R5x5eT6f8/6YDMMwBAAA4IfM7i4AAADAXQhCAADAbxGEAACA3yIIAQAAv0UQAgAAfosgBAAA/BZBCAAA+K1AdxfgatXV1frll18UFhYmk8nk7nIAAIANDMPQyZMnFRcXJ7PZcddx/C4I/fLLL4qPj3d3GQAAoAkOHDigSy+91GHP53dBKCwsTNLZExkeHu7magAAgC1KSkoUHx9v/Rx3FL8LQpbhsPDwcIIQAABextHTWpgsDQAA/BZBCAAA+C2CEAAA8Ft+N0cIAOA7qqurVVlZ6e4y4CBBQUEOvTXeFgQhAIBXqqysVF5enqqrq91dChzEbDYrISFBQUFBLntNghAAwOsYhqGCggIFBAQoPj7e5VcR4HiWhscFBQVq27aty5oeE4QAAF7nzJkzKi8vV1xcnFq0aOHucuAgrVu31i+//KIzZ86oWbNmLnlNIjQAwOtUVVVJkkuHUOB8lr9Py9+vKxCEAABeizUjfYs7/j4JQgAAwG8RhAAAgN8iCAEA4AF++uknmUwm5ebmursUm/Tr10+TJ092dxkXjCAEAACc5tSpU4qMjFRUVJQqKircXU4dBCEAAOA0H374obp166YuXbpo+fLl7i6nDoIQAMDrGYah8sozbnkYhmFzndXV1Zo9e7Y6duyo4OBgtW3bVs8//3ytffbt26ebbrpJLVq0UM+ePZWdnW39XlFRkUaNGqVLLrlELVq0UI8ePfTee+/VOr5fv36aNGmSnnjiCUVGRiomJkbPPPNMrX1MJpP+/ve/69e//rVatGihTp06acWKFbX22bFjhwYOHKiWLVuqTZs2Gj16tI4ePWrzz2qxYMEC3X333br77ru1YMECu493NhoqAgC83qnTVeo6bbVbXnvnswPUIsi2j9OMjAy99tpreumll5SSkqKCggL98MMPtfZ5+umn9cILL6hTp056+umnNWrUKO3Zs0eBgYH6z3/+o6uvvlpPPvmkwsPDtWrVKo0ePVqXXXaZrrnmGutzvPHGG5oyZYq2bt2q7OxsjRkzRn369NGtt95q3SczM1OzZ8/Wn/70J82dO1d33XWX9u/fr8jISJ04cUI333yzxo4dq5deekmnTp3Sk08+qREjRmj9+vU2n5u9e/cqOztbH330kQzD0COPPKL9+/erXbt2Nj+Hs3FFCAAAFzh58qRefvllzZ49W/fcc48uu+wypaSkaOzYsbX2e+yxxzR48GBdfvnlyszM1P79+7Vnzx5J0iWXXKLHHntMV111lTp06KCJEyfqtttu05IlS2o9x5VXXqnp06erU6dOSktLU1JSktatW1drnzFjxmjUqFHq2LGjZsyYodLSUn355ZeSpFdffVWJiYmaMWOGunTposTERC1cuFAbNmzQ7t27bf6ZFy5cqIEDB6pVq1aKjIzUgAED9Prrrzfl9DkNV4QAAF6vebMA7Xx2gNte2xbff/+9KioqdMstt5x3vyuvvNL659jYWEnS4cOH1aVLF1VVVWnGjBlasmSJDh48qMrKSlVUVNRZZqTmc1ie5/Dhww3uExoaqvDwcOs+//73v7Vhwwa1bNmyTn179+7V5Zdf3ujPW1VVpTfeeEMvv/yyddvdd9+txx57TNOmTfOY9eEIQgAAr2cymWwennKX5s2b27RfzTW2LJ2Wq6urJUl/+tOf9PLLL+t///d/1aNHD4WGhmry5MmqrKxs8Dksz2N5Dlv2KS0t1dChQzVr1qw69VnCWWNWr16tgwcPauTIkbW2V1VVad26dbWG6dzJs39rAADwEZ06dVLz5s21bt26OsNhttq8ebN+9atf6e6775Z0NiDt3r1bXbt2dWSp6tWrlz788EO1b99egYFNiwoLFizQnXfeqaeffrrW9ueff14LFizwmCDkGdelAADwcSEhIXryySf1xBNP6M0339TevXu1ZcsWu+6k6tSpk9asWaMvvvhC33//vR588EEdOnTI4bWmp6fr2LFjGjVqlL766ivt3btXq1ev1r333mvTgqhHjhzRP/7xD91zzz3q3r17rUdaWpqWL1+uY8eOObzupiAIAQDgIv/zP/+jRx99VNOmTdMVV1yhkSNH1pm7cz5Tp05Vr169NGDAAPXr108xMTEaNmyYw+uMi4vT5s2bVVVVpf79+6tHjx6aPHmyLrroIpvm9rz55psKDQ2tdz7ULbfcoubNm+vtt992eN1NYTLsaYDgA0pKShQREaHi4mKFh4e7uxwAQBP85z//UV5enhISEhQSEuLucuAg5/t7ddbnN1eEAACA33JrEJo5c6Z69+6tsLAwRUdHa9iwYdq1a5fNx7///vsymUxOuSwIAAB8n1uD0MaNG5Wenq4tW7ZozZo1On36tPr376+ysrJGj/3pp5/02GOP6YYbbnBBpQAAwBe59fb5Tz/9tNbXixYtUnR0tL7++mvdeOONDR5XVVWlu+66S5mZmfr888914sQJJ1eKcxmGoVOn/3vnQPNmAdZ+FwDgKn42zdXnuePv06P6CBUXF0uSIiMjz7vfs88+q+joaN1///36/PPPz7tvRUWFKioqrF+XlJRceKGos65P19hwrZyYIrOZMATA+QICznZzrqystLlRITyfpTGk5e/XFTwmCFVXV2vy5Mnq06ePunfv3uB+WVlZWrBggXJzc2163pkzZyozM9NBVaIhOwtKNGRullZNSuHKEACnCwwMVIsWLXTkyBE1a9bMY5ZrQNNVV1fryJEjatGiRZObODaFxwSh9PR07dixQ1lZWQ3uc/LkSY0ePVqvvfaaoqKibHrejIwMTZkyxfp1SUmJ4uPjL7hef2dZ18cwpCFzs5R3tEw7C0pUVFapi0ODCEMAnMpkMik2NlZ5eXnav3+/u8uBg5jNZrVt29alnyEe0UdowoQJ+vjjj7Vp0yYlJCQ0uF9ubq4SExNrXTKzrItiNpu1a9cuXXbZZed9LfoIOV5ZxRl1m/7fYbKkdq20dFwyYQiA01VXV9dZZwveKygoqMGre876/HbrFSHDMDRx4kQtW7ZMn3322XlDkCR16dJF27dvr7Vt6tSpOnnypF5++WWu9LhJi6AAJbVrpZz9xyVJOfuPc2UIgEuYzWYaKuKCuDUIpaen691339XHH3+ssLAwFRYWSpIiIiKsk9/S0tJ0ySWXaObMmQoJCakzf+iiiy6SpPPOK4JzmUwmLR2XrKKySiU9t1aSlPTcWiZQAwA8nltnl/3lL39RcXGx+vXrp9jYWOtj8eLF1n3y8/NVUFDgxiphC5PJpItDg5TUrpV1m2UCtQeMvgIAUC+PmCPkSswRci7DMFReWWWdQC1JOVNTGSYDAFwQ1hqDVzCZTAoNDtTKiSnWbUnPrdXgV7JUVnGGq0MAAI9CEIJTWCZQW+wsKFG36as1fH42YQgA4DEIQnAKywTq7zIHqGvsfy9h5uw/rvLKqvMcCQCA6xCE4DSWYbJVk1KUMzXVun3IXIbJAACegSAEp7PcUWa5MpR3tIxhMgCARyAIwSVMJpNWTkypM0xWVFZJGAIAuA23z8OlDMOo1XhRYuV6AEDjuH0ePoHGiwAAT0IQgsvVvKMsISpUkqwr1xOGAACuRBCCW9B4EQDgCQhCcCsaLwIA3IkgBLei8SIAwJ0IQnA7Gi8CANyFIASPQeNFAICrEYTgUWi8CABwJRoqwiPV13gxqV0rLR2XLJOJxosA4G9oqAi/Ul/jRSZQAwAcjSAEj2W5o4wJ1AAAZyEIwaMxgRoA4EwEIXi8hiZQM0wGALhQBCF4BbPZRJ8hAIDDEYTgNRgmAwA4GkEIXoU+QwAAR6KPELxSfX2GusaGa+XEFJnN9BkCAF9DHyGghvr6DO0sKNGQuVlcGQIA2IwgBK9Vc+X6hKhQSWfDEMNkAABbEYTg1Swr16+cmGLdlvTcWg1+hTvKAACNIwjBJ7QICqgzTMYdZQCAxhCE4BNqDpPReBEAYCuCEHyGZZiMxosAAFsRhOBzaLwIALAVQQg+icaLAABb0FARPq2+xotJ7Vpp6bhkmUw0XgQAb+GTDRVnzpyp3r17KywsTNHR0Ro2bJh27dp13mNee+013XDDDWrVqpVatWql1NRUffnlly6qGN6mvsaLTKAGAFi4NQht3LhR6enp2rJli9asWaPTp0+rf//+Kisra/CYzz77TKNGjdKGDRuUnZ2t+Ph49e/fXwcPHnRh5fAmljvKmEANADiXRw2NHTlyRNHR0dq4caNuvPFGm46pqqpSq1at9OqrryotLa3R/Rka81+GYWjwK1naWVBi3cYwGQB4B58cGjtXcXGxJCkyMtLmY8rLy3X69OkGj6moqFBJSUmtB/wTE6gBAOfymCtC1dXVuv3223XixAllZWXZfNxDDz2k1atX67vvvlNISEid7z/zzDPKzMyss50rQv6LlesBwPv4/BWh9PR07dixQ++//77Nx/zxj3/U+++/r2XLltUbgiQpIyNDxcXF1seBAwccVTK8FCvXAwAsAt1dgCRNmDBBK1eu1KZNm3TppZfadMwLL7ygP/7xj1q7dq2uvPLKBvcLDg5WcHCwo0qFj7BMoC6vrNKQuVnKO1pmXbn+4tAg5gwBgJ9w6xUhwzA0YcIELVu2TOvXr1dCQoJNx82ePVt/+MMf9OmnnyopKcnJVcJXsXI9AMCtQSg9PV1vv/223n33XYWFhamwsFCFhYU6deqUdZ+0tDRlZGRYv541a5b+53/+RwsXLlT79u2tx5SWlrrjR4APYOV6APBfbg1Cf/nLX1RcXKx+/fopNjbW+li8eLF1n/z8fBUUFNQ6prKyUr/5zW9qHfPCCy+440eAD2DlegDwXx5z15ir0EcI53PuHWUJUaFaOTFFLYICmDcEAG7k83eNAZ6AlesBwL8QhIBz0HgRAPwHQ2NAA2i8CACeg6ExwMVovAgAvo8gBJxHzTvKEqJCJcnaeJEwBADejyAENILGiwDguwhCgI1ovAgAvocgBNiIxosA4HsIQoAdLMNkqyalKGdqqnU7V4UAwDsRhIAmOLfxIhOoAcA7EYSAJrIMlVkwgRoAvA9BCLgATKAGAO9GEAIuABOoAcC7EYSAC9TQBOohcxkmAwBPRxACHISV6wHA+xCEAAdqaOV6hskAwDMRhAAHM5tNDJMBgJcgCAFOwDAZAHgHghDgJA0Nk9F4EQA8h8nws3fkkpISRUREqLi4WOHh4Y0fAFwgwzBUVFappOfWWrd1jQ3XyokpMptNbqwMALyHsz6/uSIEOJllmOzcxotD5mZxZQgA3IwgBLhAzcaLCVGhklifDAA8AUEIcBFL48WVE1Os21ifDADciyAEuBjrkwGA5yAIAS7G+mQA4DkIQoAbsD4ZAHgGghDgRjReBAD3IggBbkbjRQBwHxoqAh6ivsaLSe1aaem4ZJlMNF4E4N9oqAj4uPoaLzKBGgCciyAEeBDLHWVMoAYA1yAIAR6GCdQA4DoEIcADMYEaAFzDrUFo5syZ6t27t8LCwhQdHa1hw4Zp165djR63dOlSdenSRSEhIerRo4c++eQTF1QLuJbZbKrTZ8iyJEd1NWEIABzBrUFo48aNSk9P15YtW7RmzRqdPn1a/fv3V1lZWYPHfPHFFxo1apTuv/9+bdu2TcOGDdOwYcO0Y8cOF1YOuAYr1wOAc3nU7fNHjhxRdHS0Nm7cqBtvvLHefUaOHKmysjKtXLnSuu26667TVVddpfnz5zf6Gtw+D29kGIbKK6s0ZG6W8o6e/Y9CztRUXRwaxK31APyCX9w+X1xcLEmKjIxscJ/s7GylpqbW2jZgwABlZ2fXu39FRYVKSkpqPQBvw8r1AOAcHhOEqqurNXnyZPXp00fdu3dvcL/CwkK1adOm1rY2bdqosLCw3v1nzpypiIgI6yM+Pt6hdQOuxMr1AOBYHhOE0tPTtWPHDr3//vsOfd6MjAwVFxdbHwcOHHDo8wOuxMr1AOBYHhGEJkyYoJUrV2rDhg269NJLz7tvTEyMDh06VGvboUOHFBMTU+/+wcHBCg8Pr/UAvBkr1wOA47g1CBmGoQkTJmjZsmVav369EhISGj0mOTlZ69atq7VtzZo1Sk5OdlaZgEei8SIAXDi3BqH09HS9/fbbevfddxUWFqbCwkIVFhbq1KlT1n3S0tKUkZFh/frhhx/Wp59+qjlz5uiHH37QM888o5ycHE2YMMEdPwLgVjReBIAL49bb5xu67ff111/XmDFjJEn9+vVT+/bttWjRIuv3ly5dqqlTp+qnn35Sp06dNHv2bA0aNMim1+T2efii+lau7xobrpUTU2Q2c3s9AO/nrM9vj+oj5AoEIfgqwzA0fH62cvYft27rGhuuVZNS6DUEwOv5RR8hAE1X846yhKhQSWdvr2eYDAAaRhACfAiNFwHAPgQhwAfReBEAbEMQAnwQjRcBwDYEIcBHNdR4katCAPBfBCHAx53beJEJ1ADwXwQhwA9YhsosLBOoq6sJQwD8G0EI8BP1TaAeMjeLK0MA/BpBCPAT9BkCgLoIQoAfoc8QANRGEAL8EH2GAOAsghDgh+gzBABnEYQAP9VQn6EhcxkmA+A/CEKAnzu3z1De0TKGyQD4DYIQAJlMJq2cmFJnmIw7ygD4OpNh57tcRUWFtm7dqv3796u8vFytW7dWYmKiEhISnFWjQ5WUlCgiIkLFxcUKDw9v/ADAjxiGoaKySiU9t9a6rWtsuFZOTJHZbHJjZQD8nbM+vwNt3XHz5s16+eWX9Y9//EOnT59WRESEmjdvrmPHjqmiokIdOnTQ7373O40bN05hYWEOKxCA61iGyZLatVLO/uOS/tt4cdWkFJlMhCEAvsWmobHbb79dI0eOVPv27fWvf/1LJ0+eVFFRkX7++WeVl5frxx9/1NSpU7Vu3TpdfvnlWrNmjbPrBuAkNF4E4E9sGhr761//qvvuu0/NmjVr9Al37typgoIC3XLLLQ4p0NEYGgNsV1ZxRt2mr7Z+3TU2XEvHJatFUABXhwC4lLM+v+2eI+TtCEKA7QzD0PD52dZhMoukdq20dFwyYQiAyzjr85u7xgA0iMaLAHydw4LQPffco5tvvtlRTwfAQzTUeJE+QwB8gcOC0CWXXKJ27do56ukAeJhzGy8ygRqAL2COEAC7MIEagDswRwiAR2DlegC+xOaGihb33Xffeb+/cOHCJhcDwPNZJlCXV1Zp+Pxs7SwokfTfCdShwXa/rQCA29j9jnX8eO3baE+fPq0dO3boxIkTTJYG/ETNCdQ1l+QYMjdLKyemMEwGwGvYHYSWLVtWZ1t1dbXGjx+vyy67zCFFAfAONSdQ7ywosa5cT58hAN7CIXOEzGazpkyZopdeeskRTwfAi7ByPQBv5rDJ0nv37tWZM2cc9XQAvIjZbKrTZyjpubUa/EqWqqsJQwA8l91DY1OmTKn1tWEYKigo0KpVq3TPPfc4rDAA3oWV6wF4I7uD0LZt22p9bTab1bp1a82ZM6fRO8oA+Laad5QNmZulvKNl1saLF4cGEYYAeBwaKgJwChovAnAkn2youGnTJg0dOlRxcXEymUxavnx5o8e888476tmzp1q0aKHY2Fjdd999Kioqcn6xAOxC40UA3sBhQej3v/+93UNjZWVl6tmzp+bNm2fT/ps3b1ZaWpruv/9+fffdd1q6dKm+/PJLPfDAA00pGYATsXI9AG/gsBawBw8e1IEDB+w6ZuDAgRo4cKDN+2dnZ6t9+/aaNGmSJCkhIUEPPvigZs2aZdfrAnANGi8C8HQOuyL0xhtvaP369Y56unolJyfrwIED+uSTT2QYhg4dOqQPPvhAgwYNavCYiooKlZSU1HoAcK1zV663NF5kmAyAu3nVoqt9+vTRO++8o5EjRyooKEgxMTGKiIg479DazJkzFRERYX3Ex8e7sGIAFjReBOCJmnTXWFlZmTZu3Kj8/HxVVlbW+p5l2MruQkwmLVu2TMOGDWtwn507dyo1NVWPPPKIBgwYoIKCAj3++OPq3bu3FixYUO8xFRUVqqiosH5dUlKi+Ph47hoD3MQwjFrDZNLZO8pWTkyR2cwwGYD6OeuuMbuD0LZt2zRo0CCVl5errKxMkZGROnr0qFq0aKHo6Gjt27evaYXYEIRGjx6t//znP1q6dKl1W1ZWlm644Qb98ssvio2NbfR1uH0ecD/DMDR8fra18aJ0NgzReBFAQzzm9vlHHnlEQ4cO1fHjx9W8eXNt2bJF+/fv19VXX60XXnjBYYXVp7y8XGZz7ZIDAgIkiUvrgBepeUdZQlSoJFkbL/JvGYAr2R2EcnNz9eijj8psNisgIEAVFRWKj4/X7Nmz9fvf/96u5yotLVVubq5yc3MlSXl5ecrNzVV+fr4kKSMjQ2lpadb9hw4dqo8++kh/+ctftG/fPm3evFmTJk3SNddco7i4OHt/FABuZLmjbOXEFOu2pOfWMoEagEvZHYSaNWtmvSoTHR1tDS0RERF23z6fk5OjxMREJSYmSjq7jlliYqKmTZsmSSooKLA+vySNGTNGL774ol599VV1795dw4cPV+fOnfXRRx/Z+2MA8BDnNl5kAjUAV7J7jlD//v01ZswY/fa3v9UDDzygb7/9VpMmTdJbb72l48ePa+vWrc6q1SGYIwR4HiZQA2iMx8wRmjFjhnVS8vPPP69WrVpp/PjxOnLkiP72t785rDAA/qPmyvUWlpXruTIEwJlYdBWAxzAMo9bK9ZKUMzWVlesBeM4VIQBwloYmUA9+JUvV1X71fzYALmJTELrtttu0ZcuWRvc7efKkZs2aZfMiqgBQn/pWrmeYDIAz2LTo6vDhw3XHHXcoIiJCQ4cOVVJSkuLi4hQSEqLjx49r586dysrK0ieffKLBgwfrT3/6k7PrBuDDLH2Gag6TWfoMMUwGwJFsniNUUVGhpUuXavHixcrKylJxcfHZJzCZ1LVrVw0YMED333+/rrjiCqcWfKGYIwR4l7KKM+o2fbX1666x4Vo6LpmV6wE/4zFLbFgUFxfr1KlTuvjii9WsWTOHFeRsBCHAu9S3HIckJbVrpaXjkglDgJ/wuMnSERERiomJ8aoQBMD71FyO49yV68srq9xYGQBfwF1jADye5W6yVZNSlDM11bp9yNwslVWcYRI1gCYjCAHwGpbGi5YrQ3lHy9Rt+mrWJwPQZAQhAF7FZDJp5cSUOsNkrE8GoCnoLA3AK7E+GeBfPGqy9IkTJ/T3v/9dGRkZOnbsmCTpm2++0cGDBx1WGACcD+uTAXAEmxoq1vTtt98qNTVVERER+umnn/TAAw8oMjJSH330kfLz8/Xmm286o04AqIPGiwAulN1XhKZMmaIxY8boxx9/VEhIiHX7oEGDtGnTJocWBwCNOd/6ZNxRBqAxdgehr776Sg8++GCd7ZdccokKCwsdUhQA2Ku+9cm4owxAY+wOQsHBwSopKamzfffu3WrdurVDigIAe9F4EUBT2B2Ebr/9dj377LM6ffq0pLNvPvn5+XryySd1xx13OLxAALBVQ40XuSoEoCF2B6E5c+aotLRU0dHROnXqlPr27auOHTsqLCxMzz//vDNqBAC7nNt40TKBmjAE4FxN7iOUlZWlb7/9VqWlperVq5dSU1MbP8gD0EcI8B+sXA/4Do9bfd5bEYQA/8HK9YDvcNbnt919hF555ZV6t5tMJoWEhKhjx4668cYbFRAQcMHFAcCFqNlnaPj8bO0sOHujh2UCdWiw3W+BAHyM3VeEEhISdOTIEZWXl6tVq7O3qh4/flwtWrRQy5YtdfjwYXXo0EEbNmxQfHy8U4q+EFwRAvzTuUtyJESFauXEFIbJAC/hMUtszJgxQ71799aPP/6ooqIiFRUVaffu3br22mv18ssvKz8/XzExMXrkkUccViQAXChWrgdQH7uvCF122WX68MMPddVVV9Xavm3bNt1xxx3at2+fvvjiC91xxx0qKChwZK0OwRUhwL9VVxsaMjfLOkwmSTlTU1mSA/BwHnNFqKCgQGfOnKmz/cyZM9bO0nFxcTp58uSFVwcADmY2m+r0GbIsyVFdzZUhwN/YHYRuuukmPfjgg9q2bZt127Zt2zR+/HjdfPPNkqTt27crISHBcVUCgAOxcj0AC7uD0IIFCxQZGamrr75awcHBCg4OVlJSkiIjI7VgwQJJUsuWLTVnzhyHFwsAjlJzSY6EqFBJNF4E/FGT+wj98MMP2r17tySpc+fO6ty5s0MLcxbmCAE4F40XAc9HQ0UHIQgBOBeNFwHP5zENFSXp559/1ooVK5Sfn6/Kyspa33vxxRcdUhgAuAqNFwH/Zfe/7nXr1un2229Xhw4d9MMPP6h79+766aefZBiGevXq5YwaAcDpaq5cX7Px4pC5WTReBHyY3ZOlMzIy9Nhjj2n79u0KCQnRhx9+qAMHDqhv374aPny4M2oEAJeh8SLgX+wOQt9//73S0tIkSYGBgTp16pRatmypZ599VrNmzbLruTZt2qShQ4cqLi5OJpNJy5cvb/SYiooKPf3002rXrp2Cg4PVvn17LVy40N4fAwAaZDKZtHJiijUMSWeHybijDPA9dgeh0NBQ67yg2NhY7d271/q9o0eP2vVcZWVl6tmzp+bNm2fzMSNGjNC6deu0YMEC7dq1S++9957X3LEGwHvQeBHwD3bPEbruuuuUlZWlK664QoMGDdKjjz6q7du366OPPtJ1111n13MNHDhQAwcOtHn/Tz/9VBs3btS+ffsUGRkpSWrfvr1drwkAtqrZeNFyR5ml8eKqSSnMGQJ8gN1XhF588UVde+21kqTMzEzdcsstWrx4sdq3b29tqOgsK1asUFJSkmbPnq1LLrlEl19+uR577DGdOnWqwWMqKipUUlJS6wEAtqLxIuDb7L4i1KFDB+ufQ0NDNX/+fIcWdD779u1TVlaWQkJCtGzZMh09elQPPfSQioqK9Prrr9d7zMyZM5WZmemyGgH4HssdZSsnplgbLyY9t5Y+Q4APsPuKUIcOHVRUVFRn+4kTJ2qFJGeorq6WyWTSO++8o2uuuUaDBg3Siy++qDfeeKPBq0IZGRkqLi62Pg4cOODUGgH4rhZBAbXWJ2MCNeD97A5CP/30k6qqqupsr6io0MGDBx1SVENiY2N1ySWXKCIiwrrtiiuukGEY+vnnn+s9Jjg4WOHh4bUeANAUlmEyJlADvsPmobEVK1ZY/7x69epaYaSqqkrr1q1z+sTlPn36aOnSpSotLVXLli0lSbt375bZbNall17q1NcGAIkJ1ICvsXmtMbP57MUjk8lU5zJws2bN1L59e82ZM0dDhgyx+cVLS0u1Z88eSVJiYqJefPFF3XTTTYqMjFTbtm2VkZGhgwcP6s0337Tuf8UVV+i6665TZmamjh49qrFjx6pv37567bXXbHpN1hoD4AiGYai8skpD5mYp72iZJClnaqouDg0iDAFO4KzPb5uHxqqrq1VdXa22bdvq8OHD1q+rq6tVUVGhXbt22RWCJCknJ0eJiYlKTEyUJE2ZMkWJiYmaNm2aJKmgoED5+fnW/Vu2bKk1a9boxIkTSkpK0l133aWhQ4fqlVdeset1AeBC1ZxAbcEwGeB9WH0eAC5AfSvXd40NZ5gMcDC3rj5vzxWXSZMmNbkYAPA2NVeutwyTWfoMMUwGeD6brgglJCTY9mQmk/bt23fBRTkTV4QAOEtZxRlrnyHp7JWhpeOSWbkecAC3XhHKy8tz2AsCgK+y9BmqeTdZt+mrabwIeDC7+wjVZBgGjcQA4P/UXI7j3JXryyvr9l8D4H5NCkJvvvmmevTooebNm6t58+a68sor9dZbbzm6NgDwOpa7yc5duX7I3CyVVZzhP4+Ah2nSoqvjx4/XoEGDtGTJEi1ZskS33Xabxo0bp5deeskZNQKA17E0XrRcGco7WqZu01dr+PxswhDgQey+fT4hIUGZmZlKS0urtf2NN97QM8884/HziZgsDcCVqqsNDZmbpZ0FJdZtNF4E7Of2hooWBQUFuv766+tsv/7661VQUOCQogDAV5jNpjrDZDReBDyH3UGoY8eOWrJkSZ3tixcvVqdOnRxSFAD4kprrk1lY1idjmAxwL5sXXbXIzMzUyJEjtWnTJvXp00eStHnzZq1bt67egAQAoPEi4KlsviK0Y8cOSdIdd9yhrVu3KioqSsuXL9fy5csVFRWlL7/8Ur/+9a+dVigAeLuG1idjAjXgPjZfEbryyivVu3dvjR07VnfeeafefvttZ9YFAD7r3MaLOfuPc2UIcBObrwht3LhR3bp106OPPqrY2FiNGTNGn3/+uTNrAwCfZBkmYwI14H42B6EbbrhBCxcuVEFBgebOnau8vDz17dtXl19+uWbNmqXCwkJn1gkAPoUJ1IBnsLuPUE179uzR66+/rrfeekuFhYW67bbbtGLFCkfW53D0EQLgSQzDqDWBWqLPEFAfZ31+X1AQkqSysjK98847ysjI0IkTJ1RV5dnr6RCEAHgiVq4Hzs9jGipabNq0SWPGjFFMTIwef/xx/b//9/+0efNmhxUGAP7EMoHawrJyPXeUAc5lVx+hX375RYsWLdKiRYu0Z88eXX/99XrllVc0YsQIhYaGOqtGAPB5NfsMDZ+fbV2Sw7JyfWiw3W3fANjA5qGxgQMHau3atYqKilJaWpruu+8+de7c2dn1ORxDYwA8nWEYKiqrVNJzayVJCVGhWjkxhWEy+DVnfX7b/F+MZs2a6YMPPtCQIUMUEBDgsAIAALXVXLl+Z0GJdeX6pHattHRcMmEIcCCb5witWLFCv/rVrwhBAOACJpNJKyemqGvsf//na2m8yJwhwHEu+K4xb8PQGABvcu4wmXT2jrKVE1NkNnNlCP7D4+4aAwA4H40XAeciCAGAh7PcUfZd5gAlRJ29Q9eycj1hCLgwBCEA8AINrVw/+JUslVWcIRABTUQQAgAvQuNFwLEIQgDgRWoOk517R1l5pWcvcQR4IoIQAHgZyzDZqkkpypmaat0+ZC7DZIC9CEIA4KVqNl6UZG28yDAZYDuCEAB4MRovAheGhooA4APqa7zIkhzwJTRUBAA0qL7Gi0ygBhpHEAIAH2G5o4wJ1IDt3BqENm3apKFDhyouLk4mk0nLly+3+djNmzcrMDBQV111ldPqAwBvwwRqwD5uDUJlZWXq2bOn5s2bZ9dxJ06cUFpamm655RYnVQYA3quhCdQMkwF1ecxkaZPJpGXLlmnYsGGN7nvnnXeqU6dOCggI0PLly5Wbm2vz6zBZGoC/OHcCdUJUqFZOTFGLoAAmUMPrMFn6/7z++uvat2+fpk+fbtP+FRUVKikpqfUAAH/AMBnQOK8KQj/++KOeeuopvf322woMDLTpmJkzZyoiIsL6iI+Pd3KVAOA56DMEnJ/XBKGqqir99re/VWZmpi6//HKbj8vIyFBxcbH1ceDAASdWCQCex2w21VmOw7JyfXU1YQj+zWuC0MmTJ5WTk6MJEyYoMDBQgYGBevbZZ/Xvf/9bgYGBWr9+fb3HBQcHKzw8vNYDAPxNfX2GdhaUaMjcLK4Mwa/ZNr7kAcLDw7V9+/Za2/785z9r/fr1+uCDD5SQkOCmygDAO1j6DJVXVmnI3CzlHS3TzoISFZVV6uLQICZQwy+5NQiVlpZqz5491q/z8vKUm5uryMhItW3bVhkZGTp48KDefPNNmc1mde/evdbx0dHRCgkJqbMdAFA/y8r1KyemqNv01ZLODpN1jQ3X0nHJ3FEGv+PWobGcnBwlJiYqMTFRkjRlyhQlJiZq2rRpkqSCggLl5+e7s0QA8EktggLqDJNxRxn8kcf0EXIV+ggBwFmGYai8skrD52drZ8F/W4t8lzlAocFeM3MCfoI+QgAAh7IMk517Rxnrk8GfEIQAwM/ReBH+jCAEAKDxIvwWc4QAAFbnrk8mSV1jw7VyYorMZu4mg/swRwgA4HQ0XoS/IQgBAGqxNF78LnOAEqJCJcnaeJEwBF9DEAIA1FGz8aJF0nNrmUANn0MQAgA06NzGi0yghq9hsjQA4LyYQA1PwGRpAIBbMIEavowgBABoFBOo4asIQgAAmzQ0gXrwKyzJAe9FEAIA2IWV6+FLCEIAALvUHCY7d0mO8soqN1YG2I8gBACwGyvXw1cQhAAATcbK9fB2BCEAwAVh5Xp4MxoqAgAcgsaLcCYaKgIAPBqNF+GNCEIAAIeh8SK8DUEIAOBQNF6ENyEIAQCcgsaL8AYEIQCAU9B4Ed6AIAQAcBoaL8LTEYQAAE5H40V4KoIQAMAlaLwIT0RDRQCAS9XXeDGpXSstHZcsk4nGi6gfDRUBAD6hvsaLTKCGuxCEAAAuZ7mjjAnUcDeCEADALZhADU9AEAIAuE1DE6gZJoOrEIQAAG5lNpvoMwS3IQgBANyOYTK4i1uD0KZNmzR06FDFxcXJZDJp+fLl593/o48+0q233qrWrVsrPDxcycnJWr16tWuKBQA4FX2G4A5uDUJlZWXq2bOn5s2bZ9P+mzZt0q233qpPPvlEX3/9tW666SYNHTpU27Ztc3KlAABXqG+YzLJyfXU1YQiO5zENFU0mk5YtW6Zhw4bZdVy3bt00cuRITZs2zab9aagIAJ7PMAwNn5+tnP3Hrdu6xoZr1aQUmi76KWd9fgc67JncoLq6WidPnlRkZGSD+1RUVKiiosL6dUlJiStKAwBcAEufofLKKg2Zm6W8o2XaWVCiorJKXRwaRBiCw3j1ZOkXXnhBpaWlGjFiRIP7zJw5UxEREdZHfHy8CysEADSVZeX6lRNTrNssw2TcUQZH8dog9O677yozM1NLlixRdHR0g/tlZGSouLjY+jhw4IALqwQAXKgWQQG1luPYWVDCHWVwGK8cGnv//fc1duxYLV26VKmpqefdNzg4WMHBwS6qDADgaDWHyYbPz9bOgrNTHCyNF0ODvfKjDB7C664Ivffee7r33nv13nvvafDgwe4uBwDgApZhMhovwtHcGoRKS0uVm5ur3NxcSVJeXp5yc3OVn58v6eywVlpamnX/d999V2lpaZozZ46uvfZaFRYWqrCwUMXFxe4oHwDgYjRehKO5NQjl5OQoMTFRiYmJkqQpU6YoMTHReit8QUGBNRRJ0t/+9jedOXNG6enpio2NtT4efvhht9QPAHA9Gi/CkTymj5Cr0EcIAHyDYRgqKqtU0nNrrduS2rXS0nHJ3F7vg5z1+e11c4QAAJD+O0xW844yVq6HvQhCAACvZbmjjAnUaCqCEADAqzGBGheCIAQA8HpMoEZTMVkaAOAz6ptA3TU2XCsnpshsZgK1N2OyNAAAjahvAvXOghINmZvFlSHUiyAEAPAplgnU32UOUEJUqCRZV64nDOFcBCEAgM9h5XrYiiAEAPBZrFyPxhCEAAA+q+Yw2bl3lNF4ERJBCADg41i5HudDEAIA+AUaL6I+BCEAgN+g8SLORUNFAIDfofGi96GhIgAADkLjRVgQhAAAfonGi5AIQgAAP0bjRRCEAAB+j8aL/osgBADwezRe9F8EIQAA1HDjRa4K+TaCEAAANZzbeJEJ1L6NIAQAwDksQ2UWTKD2XQQhAADqwQRq/0AQAgCgHkyg9g8EIQAAGsDK9b6PIAQAQCNYud53EYQAALBBQyvXM0zm3QhCAADYyGw2MUzmYwhCAADYgWEy30IQAgDATg0Nk9F40fuYDD/7GyspKVFERISKi4sVHh7e+AEAADTAMAwVlVUq6bm11m1dY8O1cmKKzGaTGyvzPc76/OaKEAAATWQZJju38eKQuVlcGfISBCEAAC5AzcaLCVGhklifzJu4NQht2rRJQ4cOVVxcnEwmk5YvX97oMZ999pl69eql4OBgdezYUYsWLXJ6nQAAnI+l8eLKiSnWbaxP5h3cGoTKysrUs2dPzZs3z6b98/LyNHjwYN10003Kzc3V5MmTNXbsWK1evdrJlQIA0DjWJ/M+HjNZ2mQyadmyZRo2bFiD+zz55JNatWqVduzYYd1255136sSJE/r0009teh0mSwMAnMkwDJVXVmn4/GztLCixbt/57AC1CAp0Y2XejcnSkrKzs5Wamlpr24ABA5Sdnd3gMRUVFSopKan1AADAWRpanwyeyauCUGFhodq0aVNrW5s2bVRSUqJTp07Ve8zMmTMVERFhfcTHx7uiVACAnzOZTGoRFODuMtAIrwpCTZGRkaHi4mLr48CBA+4uCQDgJ5o3C9DOZwdo57MD1LwZocgTedVgZUxMjA4dOlRr26FDhxQeHq7mzZvXe0xwcLCCg4NdUR4AALWcvSrkVR+1fserrgglJydr3bp1tbatWbNGycnJbqoIAAB4M7cGodLSUuXm5io3N1fS2dvjc3NzlZ+fL+nssFZaWpp1/3Hjxmnfvn164okn9MMPP+jPf/6zlixZokceecQd5QMAAC/n1iCUk5OjxMREJSYmSpKmTJmixMRETZs2TZJUUFBgDUWSlJCQoFWrVmnNmjXq2bOn5syZo7///e8aMGCAW+oHAADezWP6CLkKfYQAAPA+9BECAABwMIIQAADwWwQhAADgtwhCAADAbxGEAACA3yIIAQAAv0UQAgAAfosgBAAA/BZBCAAA+C2CEAAA8FsEIQAA4LcIQgAAwG8RhAAAgN8iCAEAAL9FEAIAAH6LIAQAAPwWQQgAAPgtghAAAPBbBCEAAOC3CEIAAMBvEYQAAIDfIggBAAC/RRACAAB+K9DdBbiaYRiSpJKSEjdXAgAAbGX53LZ8jjuK3wWhoqIiSVJ8fLybKwEAAPYqKipSRESEw57P74JQZGSkJCk/P9+hJ9IflZSUKD4+XgcOHFB4eLi7y/FqnEvH4Dw6DufScTiXjlFcXKy2bdtaP8cdxe+CkNl8dlpUREQEv5AOEh4ezrl0EM6lY3AeHYdz6TicS8ewfI477Pkc+mwAAABehCAEAAD8lt8FoeDgYE2fPl3BwcHuLsXrcS4dh3PpGJxHx+FcOg7n0jGcdR5NhqPvQwMAAPASfndFCAAAwIIgBAAA/BZBCAAA+C2CEAAA8Ft+EYSOHTumu+66S+Hh4brooot0//33q7S09LzH9OvXTyaTqdZj3LhxLqrYc8ybN0/t27dXSEiIrr32Wn355Zfn3X/p0qXq0qWLQkJC1KNHD33yyScuqtTz2XMuFy1aVOf3LyQkxIXVeqZNmzZp6NChiouLk8lk0vLlyxs95rPPPlOvXr0UHBysjh07atGiRU6v0xvYey4/++yzOr+TJpNJhYWFrinYQ82cOVO9e/dWWFiYoqOjNWzYMO3atavR43ivrK0p59FR75N+EYTuuusufffdd1qzZo1WrlypTZs26Xe/+12jxz3wwAMqKCiwPmbPnu2Caj3H4sWLNWXKFE2fPl3ffPONevbsqQEDBujw4cP17v/FF19o1KhRuv/++7Vt2zYNGzZMw4YN044dO1xcueex91xKZ7vQ1vz9279/vwsr9kxlZWXq2bOn5s2bZ9P+eXl5Gjx4sG666Sbl5uZq8uTJGjt2rFavXu3kSj2fvefSYteuXbV+L6Ojo51UoXfYuHGj0tPTtWXLFq1Zs0anT59W//79VVZW1uAxvFfW1ZTzKDnofdLwcTt37jQkGV999ZV12z//+U/DZDIZBw8ebPC4vn37Gg8//LALKvRc11xzjZGenm79uqqqyoiLizNmzpxZ7/4jRowwBg8eXGvbtddeazz44INOrdMb2HsuX3/9dSMiIsJF1XknScayZcvOu88TTzxhdOvWrda2kSNHGgMGDHBiZd7HlnO5YcMGQ5Jx/Phxl9TkrQ4fPmxIMjZu3NjgPrxXNs6W8+io90mfvyKUnZ2tiy66SElJSdZtqampMpvN2rp163mPfeeddxQVFaXu3bsrIyND5eXlzi7XY1RWVurrr79WamqqdZvZbFZqaqqys7PrPSY7O7vW/pI0YMCABvf3F005l5JUWlqqdu3aKT4+Xr/61a/03XffuaJcn8LvpONdddVVio2N1a233qrNmze7uxyPU1xcLEnnXRiU38vG2XIeJce8T/p8ECosLKxz6TYwMFCRkZHnHdv+7W9/q7ffflsbNmxQRkaG3nrrLd19993OLtdjHD16VFVVVWrTpk2t7W3atGnwvBUWFtq1v79oyrns3LmzFi5cqI8//lhvv/22qqurdf311+vnn392Rck+o6HfyZKSEp06dcpNVXmn2NhYzZ8/Xx9++KE+/PBDxcfHq1+/fvrmm2/cXZrHqK6u1uTJk9WnTx917969wf14rzw/W8+jo94nvXb1+aeeekqzZs067z7ff/99k5+/5hyiHj16KDY2Vrfccov27t2ryy67rMnPC9giOTlZycnJ1q+vv/56XXHFFfrrX/+qP/zhD26sDP6qc+fO6ty5s/Xr66+/Xnv37tVLL72kt956y42VeY709HTt2LFDWVlZ7i7Fq9l6Hh31Pum1QejRRx/VmDFjzrtPhw4dFBMTU2dC6pkzZ3Ts2DHFxMTY/HrXXnutJGnPnj1+EYSioqIUEBCgQ4cO1dp+6NChBs9bTEyMXfv7i6acy3M1a9ZMiYmJ2rNnjzNK9FkN/U6Gh4erefPmbqrKd1xzzTV86P+fCRMmWG/GufTSS8+7L++VDbPnPJ6rqe+TXjs01rp1a3Xp0uW8j6CgICUnJ+vEiRP6+uuvrceuX79e1dXV1nBji9zcXElnLw/7g6CgIF199dVat26ddVt1dbXWrVtXK4HXlJycXGt/SVqzZk2D+/uLppzLc1VVVWn79u1+8/vnKPxOOldubq7f/04ahqEJEyZo2bJlWr9+vRISEho9ht/LuppyHs/V5PfJC55u7QVuu+02IzEx0di6dauRlZVldOrUyRg1apT1+z///LPRuXNnY+vWrYZhGMaePXuMZ5991sjJyTHy8vKMjz/+2OjQoYNx4403uutHcIv333/fCA4ONhYtWmTs3LnT+N3vfmdcdNFFRmFhoWEYhjF69Gjjqaeesu6/efNmIzAw0HjhhReM77//3pg+fbrRrFkzY/v27e76ETyGvecyMzPTWL16tbF3717j66+/Nu68804jJCTE+O6779z1I3iEkydPGtu2bTO2bdtmSDJefPFFY9u2bcb+/fsNwzCMp556yhg9erR1/3379hktWrQwHn/8ceP777835s2bZwQEBBiffvqpu34Ej2HvuXzppZeM5cuXGz/++KOxfft24+GHHzbMZrOxdu1ad/0IHmH8+PFGRESE8dlnnxkFBQXWR3l5uXUf3isb15Tz6Kj3Sb8IQkVFRcaoUaOMli1bGuHh4ca9995rnDx50vr9vLw8Q5KxYcMGwzAMIz8/37jxxhuNyMhIIzg42OjYsaPx+OOPG8XFxW76Cdxn7ty5Rtu2bY2goCDjmmuuMbZs2WL9Xt++fY177rmn1v5LliwxLr/8ciMoKMjo1q2bsWrVKhdX7LnsOZeTJ0+27tumTRtj0KBBxjfffOOGqj2L5Rbucx+Wc3fPPfcYffv2rXPMVVddZQQFBRkdOnQwXn/9dZfX7YnsPZezZs0yLrvsMiMkJMSIjIw0+vXrZ6xfv949xXuQ+s6hpFq/Z7xXNq4p59FR75Om/ysAAADA73jtHCEAAIALRRACAAB+iyAEAAD8FkEIAAD4LYIQAADwWwQhAADgtwhCAADAbxGEAACA3yIIAXC5MWPGaNiwYW57/dGjR2vGjBkOea7Kykq1b99eOTk5Dnk+AK5FZ2kADmUymc77/enTp+uRRx6RYRi66KKLXFNUDf/+97918803a//+/WrZsqVDnvPVV1/VsmXL6iykCcDzEYQAOFRhYaH1z4sXL9a0adO0a9cu67aWLVs6LIA0xdixYxUYGKj58+c77DmPHz+umJgYffPNN+rWrZvDnheA8zE0BsChYmJirI+IiAiZTKZa21q2bFlnaKxfv36aOHGiJk+erFatWqlNmzZ67bXXVFZWpnvvvVdhYWHq2LGj/vnPf9Z6rR07dmjgwIFq2bKl2rRpo9GjR+vo0aMN1lZVVaUPPvhAQ4cOrbW9ffv2mjFjhu677z6FhYWpbdu2+tvf/mb9fmVlpSZMmKDY2FiFhISoXbt2mjlzpvX7rVq1Up8+ffT+++9f4NkD4GoEIQAe4Y033lBUVJS+/PJLTZw4UePHj9fw4cN1/fXX65tvvlH//v01evRolZeXS5JOnDihm2++WYmJicrJydGnn36qQ4cOacSIEQ2+xrfffqvi4mIlJSXV+d6cOXOUlJSkbdu26aGHHtL48eOtV7JeeeUVrVixQkuWLNGuXbv0zjvvqH379rWOv+aaa/T555877oQAcAmCEACP0LNnT02dOlWdOnVSRkaGQkJCFBUVpQceeECdOnXStGnTVFRUpG+//VbS2Xk5iYmJmjFjhrp06aLExEQtXLhQGzZs0O7du+t9jf379ysgIEDR0dF1vjdo0CA99NBD6tixo5588klFRUVpw4YNkqT8/Hx16tRJKSkpateunVJSUjRq1Khax8fFxWn//v0OPisAnI0gBMAjXHnlldY/BwQE6OKLL1aPHj2s29q0aSNJOnz4sKSzk543bNhgnXPUsmVLdenSRZK0d+/eel/j1KlTCg4OrndCd83XtwznWV5rzJgxys3NVefOnTVp0iT961//qnN88+bNrVerAHiPQHcXAACS1KxZs1pfm0ymWtss4aW6ulqSVFpaqqFDh2rWrFl1nis2Nrbe14iKilJ5ebkqKysVFBTU6OtbXqtXr17Ky8vTP//5T61du1YjRoxQamqqPvjgA+v+x44dU+vWrW39cQF4CIIQAK/Uq1cvffjhh2rfvr0CA217K7vqqqskSTt37rT+2Vbh4eEaOXKkRo4cqd/85je67bbbdOzYMUVGRko6O3E7MTHRrucE4H4MjQHwSunp6Tp27JhGjRqlr776Snv37tXq1at17733qqqqqt5jWrdurV69eikrK8uu13rxxRf13nvv6YcfftDu3bu1dOlSxcTE1OqD9Pnnn6t///4X8iMBcAOCEACvFBcXp82bN6uqqkr9+/dXjx49NHnyZF100UUymxt+axs7dqzeeecdu14rLCxMs2fPVlJSknr37q2ffvpJn3zyifV1srOzVVxcrN/85jcX9DMBcD0aKgLwK6dOnVLnzp21ePFiJScnO+Q5R44cqZ49e+r3v/+9Q54PgOtwRQiAX2nevLnefPPN8zZetEdlZaV69OihRx55xCHPB8C1uCIEAAD8FleEAACA3yIIAQAAv0UQAgAAfosgBAAA/BZBCAAA+C2CEAAA8FsEIQAA4LcIQgAAwG8RhAAAgN/6/87odjf0xUZaAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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b266sk8XWRr7hQTU+Pd3eDi7/+bfeOMNnTp1SsXFxWrYsKEk6dy5cwoJCVGDBg108uRJtWzZUps2bVJcXJzDCwYAwJp5cbF5eop1xb7N7gXFM2bMUPfu3fXTTz/pzJkzOnPmjA4cOKAePXrozTffVE5OjqKjozVp0iRn1AsAQJUqzkKxc8q32T1yM2XKFH322We68cYbLcdatWql2bNn68EHH9ShQ4c0a9YstoUDAOqUubHf3twCy86p0ECmpnyR3SM3ubm5unTp0hXHL126ZOlQHBsbqwsXLtS+OgAAbGR9zyluy+C77A43d999t5588knt2rXLcmzXrl16+umn1bdvX0nS7t27FR8f77gqAQCwQcW+N9yWwXfZHW4WLVqkyMhI3XLLLQoMDFRgYKC6deumyMhILVq0SJLUoEEDzZkzx+HFAgBwNdyWAVIN1txER0dr/fr12rdvnw4cOCBJatu2rdq2bWs55+6773ZchQAA2MF659SwhZn0vfExNV5p1a5dO7Vr186RtQAA4BAVG/vR98b31Ohv+pdfftHnn3+unJwclZWVVfrc3LlzHVIYAAA1ZX1bBpbd+Ba7w82GDRt0//33q2XLltq3b586duyow4cPy2QyqWvXrs6oEQAAu1WcheKeU77F7gXFqampmjx5snbv3q2goCB99tlnOnr0qO666y4NGzbMGTUCAGA3c98biZ1TvsbucPPjjz8qKSlJklSvXj2VlJSoQYMGevnllzVz5ky7nmvLli1KTExUbGysDAaDVq9efc1rSktL9eKLL6p58+YKDAxUixYttHjxYnu/DACAl2PnlO+yO9yEhoZa1tnExMTo4MGDls+dPn3arucqKipSly5dNH/+fJuvefjhh7VhwwYtWrRI+/fv1yeffFJppxYAAGbmnVNmNPbzDXavubntttuUkZGhm266SYMHD9azzz6r3bt3a+XKlbrtttvseq5BgwZp0KBBNp+/du1apaen69ChQ4qMjJQktWjRwq7XBAD4loo7p8zTU2wN9252j9zMnTtXPXr0kCRNnz5d/fr107Jly9SiRQtLEz9n+fzzz9WtWzfNmjVLN9xwg9q0aaPJkyerpKSk2mtKS0tVUFBQ6QEA8B1MT/keu0duWrZsaflzaGioFi5c6NCCrubQoUPKyMhQUFCQVq1apdOnT+u3v/2tzpw5o/fee6/K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RVXw73//W3379tWRI0fUoEEDhzzn22+/rVWrVlW66S0A1yHcAHAo8401JWnZsmWaOnWq9u/fbznWoEEDh4WKmhg7dqzq1aunhQsXOuw5z507p+joaH333Xfq0KGDw54XQM0wLQXAoaKjoy2PiIgIGQyGSscaNGhwxbRUnz59NH78eE2cOFENGzZUkyZN9O6776qoqEhjxoxRWFiYWrVqpX/84x+VXmvPnj0aNGiQGjRooCZNmuixxx7T6dOnq62tvLxcK1asUGJiYqXjLVq00IwZM/T4448rLCxMzZo10zvvvGP5fFlZmcaNG6eYmBgFBQWpefPmSktLs3y+YcOG6tWrl5YuXVrLdw+AIxBuALiFDz74QI0aNdL27ds1fvx4Pf300xo2bJhuv/12fffddxowYIAee+wxFRcXS5LOnz+vvn37KiEhQTt37tTatWt14sQJPfzww9W+xvfff6/8/Hx169btis/NmTNH3bp1065du/Tb3/5WTz/9tGXE6a233tLnn3+u5cuXa//+/fr444/VokWLStffeuut+vrrrx33hgCoMcINALfQpUsXTZkyRa1bt1ZqaqqCgoLUqFEj/eY3v1Hr1q01depUnTlzRt9//72ky+tcEhISNGPGDLVr104JCQlavHixNm3apAMHDlT5GkeOHJG/v7+ioqKu+NzgwYP129/+Vq1atdLzzz+vRo0aadOmTZKknJwctW7dWr1791bz5s3Vu3dvjRgxotL1sbGxOnLkiIPfFQA1QbgB4BY6d+5s+bO/v7+uv/56derUyXKsSZMmkqSTJ09KurwweNOmTZY1PA0aNFC7du0kSQcPHqzyNUpKShQYGFjloueKr2+eSjO/1ujRo5WVlaW2bdtqwoQJ+uqrr664Pjg42DKqBMC16rm6AACQpPr161f62GAwVDpmDiRGo1GSVFhYqMTERM2cOfOK54qJianyNRo1aqTi4mKVlZUpICDgmq9vfq2uXbsqOztb//jHP/TPf/5TDz/8sPr3768VK1ZYzj979qwaN25s65cLwIkINwA8UteuXfXZZ5+pRYsWqlfPtm9lN998syRp7969lj/bKjw8XMOHD9fw4cP10EMP6d5779XZs2cVGRkp6fLi5oSEBLueE4BzMC0FwCMlJyfr7NmzGjFihHbs2KGDBw9q3bp1GjNmjMrLy6u8pnHjxuratasyMjLseq25c+fqk08+0b59+3TgwAF9+umnio6OrtSn5+uvv9aAAQNq8yUBcBDCDQCPFBsbq61bt6q8vFwDBgxQp06dNHHiRF133XXy86v+W9vYsWP18ccf2/VaYWFhmjVrlrp166bu3bvr8OHD+vLLLy2vk5mZqfz8fD300EO1+poAOAZN/AD4lJKSErVt21bLli1Tz549HfKcw4cPV5cuXfTCCy845PkA1A4jNwB8SnBwsD788MOrNvuzR1lZmTp16qRJkyY55PkA1B4jNwAAwKswcgMAALwK4QYAAHgVwg0AAPAqhBsAAOBVCDcAAMCrEG4AAIBXIdwAAACvQrgBAABehXADAAC8yv8Ddq4hfisp6sYAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses.plotting import plot\n", + "\n", + "parameters = dict(t=3,\n", + " t_2=2,\n", + " v_0=1,\n", + " v_1=1.4)\n", + "\n", + "_ = plot(first_point_pt, parameters, sample_rate=100)\n", + "_ = plot(second_point_pt, parameters, sample_rate=100)\n", + "_ = plot(sequence_pt, parameters, sample_rate=100)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## RepetitionPulseTemplate: Repeating a Pulse\n", + "\n", + "If we simply want to repeat some pulse template a fixed number of times, we can make use of the `RepetitionPulseTemplate`. In the following, we will reuse one of our `PointPT`s, `first_point_pt` and use it to create a new pulse template that repeats it `n_rep` times, where `n_rep` will be a parameter." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "repetition parameters: {'t', 'v_0', 'v_1', 'n_rep'}\n", + "repetition measurements: {'M'}\n" + ] + }, + { + "data": { + "image/png": "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oZo/f76WLl2qxMREt7abOHGinnnmGS1atEitWrXy8ZQAAKA8sbTcpKWlaebMmfrwww8VGRmp/fv3S5KioqIUHh4uSerXr5/q1KmjjIwMSdKECRM0duxYzZw5UwkJCa5tIiIiFBERYc0LAQAAfsPSc26mTp2q3NxcdejQQbGxsa7b7NmzXetkZ2crJyen1DanT5/WXXfdVWqb559/3oqXAAAA/Izlb0tdztKlS0vd37Vrl2+GAQAAtuA3n5YCAADwBsoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFcoNAACwFUvLTUZGhlq3bq3IyEjFxMSoR48e2rJly2W3e//999W4cWOFhYWpWbNm+vTTTw1MCwAAygNLy82yZcuUlpam1atXKzMzU0VFRerSpYsKCgouus2///1v9enTR/fdd582btyoHj16qEePHtq0aZPByQEAgL8KsXLnn3/+ean706dPV0xMjNavX6+bb775gttMnjxZt99+u0aPHi1J+utf/6rMzEy9+uqreu2113w+MwAA8G9+dc5Nbm6uJCk6Ovqi66xatUqdO3cu9VjXrl21atWqC65fWFiovLy8UjcAAGBfflNuSkpKNHz4cLVv315Nmza96Hr79+9XrVq1Sj1Wq1Yt7d+//4LrZ2RkKCoqynWLj4/36twAAMC/+E25SUtL06ZNmzRr1iyvPm96erpyc3Ndtz179nj1+QEAgH+x9Jybc4YMGaKPP/5Yy5cvV926dS+5bu3atXXgwIFSjx04cEC1a9e+4PqhoaEKDQ312qwAAMC/WXrkxul0asiQIZo/f76++uorJSYmXnabtm3bavHixaUey8zMVNu2bX01JgAAKEcsPXKTlpammTNn6sMPP1RkZKTrvJmoqCiFh4dLkvr166c6deooIyNDkvTQQw/plltu0aRJk9StWzfNmjVL69at07Rp0yx7HQAAwH9YeuRm6tSpys3NVYcOHRQbG+u6zZ4927VOdna2cnJyXPfbtWunmTNnatq0aWrRooU++OADLViw4JInIQMAgMBh6ZEbp9N52XWWLl163mM9e/ZUz549fTARAAAo7/zm01IAAADeQLkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2QrkBAAC2EuLpBoWFhfrmm2+0e/dunThxQjVr1lRycrISExN9MR8AAIBH3C43K1eu1OTJk/XRRx+pqKhIUVFRCg8P15EjR1RYWKgGDRroT3/6kx544AFFRkb6cmYAAICLcuttqe7du6t3795KSEjQF198ofz8fB0+fFg///yzTpw4oZ9++kmPP/64Fi9erKuvvlqZmZm+nhsAAOCC3Dpy061bN82dO1cVKlS44M8bNGigBg0aqH///tq8ebNycnK8OiQAAIC73Co3999/v9tPeO211+raa68t80AAAABXgk9LAQAAW/Fauenfv786derkracDAAAoE48/Cn4xderUUVAQB4IAAIC1vFZuxo8f762nAgAAKDMOtQAAAFvx+MjNoEGDLvnzt956q8zDAAAAXCmPy83Ro0dL3S8qKtKmTZt07NgxTigGAACW87jczJ8//7zHSkpK9OCDD+qqq67yylAAAABl5ZVzboKCgjRy5Ei9+OKL3ng6AACAMvPaCcXbt2/XmTNnvPV0AAAAZeLx21IjR44sdd/pdConJ0effPKJ+vfv77XBAAAAysLjcrNx48ZS94OCglSzZk1NmjTpsp+kAgAA8DWPy82SJUt8MQcAAIBXWPolfsuXL1dqaqri4uLkcDi0YMGCy24zY8YMtWjRQpUqVVJsbKwGDRqkw4cP+35YAABQLnit3Dz66KMevy1VUFCgFi1aaMqUKW6tv3LlSvXr10/33Xef/vOf/+j999/XmjVr9Mc//rEsIwMAABvy2rWl9u7dqz179ni0TUpKilJSUtxef9WqVUpISNCwYcMkSYmJibr//vs1YcIEj/YLAADsy2tHbt555x199dVX3nq6C2rbtq327NmjTz/9VE6nUwcOHNAHH3ygO+6446LbFBYWKi8vr9QNAADYV7m6cGb79u01Y8YM9e7dWxUrVlTt2rUVFRV1ybe1MjIyFBUV5brFx8cbnBgAAJhWprelCgoKtGzZMmVnZ+v06dOlfnbuLSNf2Lx5sx566CGNHTtWXbt2VU5OjkaPHq0HHnhAb7755gW3SU9PL/XdPHl5eRQcAABsrEzfc3PHHXfoxIkTKigoUHR0tA4dOqRKlSopJibGp+UmIyND7du31+jRoyVJzZs3V+XKlXXTTTfpb3/7m2JjY8/bJjQ0VKGhoT6bCQAA+BeP35YaMWKEUlNTdfToUYWHh2v16tXavXu3rrvuOj3//PO+mNHlxIkTCgoqPXJwcLCks9+UDAAA4HG5ycrK0qhRoxQUFKTg4GAVFhYqPj5eEydO1KOPPurRcx0/flxZWVnKysqSJO3cuVNZWVnKzs6WdPYtpX79+rnWT01N1bx58zR16lTt2LFDK1eu1LBhw9SmTRvFxcV5+lIAAIANefy2VIUKFVxHT2JiYpSdna1rrrlGUVFRHn8UfN26derYsaPr/rlzY/r376/p06crJyfHVXQkacCAAcrPz9err76qUaNGqWrVqurUqRMfBQcAAC4el5vk5GStXbtWSUlJuuWWWzR27FgdOnRI//znP9W0aVOPnqtDhw6XfDtp+vTp5z02dOhQDR061NOxAQBAgPD4banx48e7Ttx95plnVK1aNT344IP65ZdfNG3aNK8PCAAA4AmPj9y0atXKtRwTE6PPP//cqwMBAOCukpKS876SxB3FRYWqExmsShWDderUKR9M5p/79ncVK1Y874NDZeG1yy8AAGDS6dOntXPnTpWUlHi87ZniEj3VMUZBjrMfZjHJyn37u6CgICUmJqpixYpX9DxulZvbb79dTz31lG644YZLrpefn6+///3vioiIUFpa2hUNBgDAxTidTuXk5Cg4OFjx8fEe/7/900XFKjlcoCCHQ4m1In00pf/t25+VlJRo3759ysnJUb169eRwOMr8XG6Vm549e+rOO+9UVFSUUlNT1apVK8XFxSksLExHjx7V5s2btWLFCn366afq1q2bnnvuuTIPBADA5Zw5c0YnTpxQXFycKlWq5PH2juBiOUKKFORwKCwszAcT+ue+/V3NmjW1b98+nTlzRhUqVCjz87hVbu677z7de++9ev/99zV79mxNmzZNubm5kiSHw6Frr71WXbt21dq1a3XNNdeUeRgAANxRXFwsSVf89gX8y7nfZ3Fxse/LjXT2Mgb33nuv7r33XklSbm6uTp48qerVq1/RAAAAlNWVvHUB/+Ot32eZTyg+d5VtAAAAf3Lln7cCAADwI5QbAAD8wK5du+RwOFzXW/R3HTp00PDhw60e44IoNwAAwGdOnjyp6Oho1ahRQ4WFhUb2SbkBAAA+M3fuXDVp0kSNGzfWggULjOyzTOXm2LFjeuONN5Senq4jR45IkjZs2KC9e/d6dTgAANzhdDp14vQZj26niop1qqjY4+1+fbvUBaB/raSkRJOef07/d2NLJTeIUb169fTMM8+UWmfHjh3q2LGjKlWqpBYtWmjVqlWunx0+fFh9+vRRnTp1VKlSJTVr1kzvvfdeqe07dOigYcOG6S9/+Yuio6NVu3ZtPfXUU6XWcTgceuONN/S73/1OlSpVUlJSkhYuXFhqnU2bNiklJUURERGqVauW+vbtq0OHDrn9Ws958803XZ+2fvPNNz3eviw8/rTUd999p86dOysqKkq7du3SH//4R0VHR2vevHnKzs7Wu+++64s5AQC4qJNFxbp27CJL9r356a6qVNG9f07T09P1+uuva+QTz+i6Nm0V6TyuH3/8sdQ6jz32mJ5//nklJSXpscceU58+fbRt2zaFhITo1KlTuu666zRmzBhVqVJFn3zyifr27aurrrpKbdq0cT3HO++8o5EjR+qbb77RqlWrNGDAALVv31633Xaba51x48Zp4sSJeu655/TKK6/onnvu0e7duxUdHa1jx46pU6dOGjx4sF588UWdPHlSY8aMUa9evfTVV1+5nc327du1atUqzZs3T06nUyNGjNDu3btVv359t5+jLDw+cjNy5EgNGDBAP/30U6lvVrzjjju0fPlyrw4HAIBd5Ofna/LkyXom41l179lH9RISdeONN2rw4MGl1nv44YfVrVs3XX311Ro3bpx2796tbdu2SZLq1Kmjhx9+WL/5zW/UoEEDDR06VLfffrvmzJlT6jmaN2+uJ598UklJSerXr59atWqlxYsXl1pnwIAB6tOnjxo2bKjx48fr+PHjWrNmjSTp1VdfVXJyssaPH6/GjRsrOTlZb731lpYsWaKtW7e6/ZrfeustpaSkqFq1aoqOjlbXrl319ttvlyU+j3h85Gbt2rX6xz/+cd7jderU0f79+70yFAAAngivEKzNT3d1e/3ComL9dPC4gh0OXRNX5Yr37Y4ffvhBhYWF6tixky51HfPmzZu7lmNjYyVJBw8eVOPGjVVc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+ylX5Wb//v2qVatWqcdq1aqlvLw8nTx58oLbZGRkKCoqynWLj48v8/4dDik0JEjx0eEa1bVRmZ8H7qtbLVzX1a9G5gaRuXlkbh6Z25ulb0uZkJ6erpEjR7ru5+Xllbng1K9eWVv+5v7baLhyIcFBmvtgO6vHCChkbh6Zm0fm9lauyk3t2rV14MCBUo8dOHBAVapUUXh4+AW3CQ0NVWhoqInxAACAHyhXb0u1bdtWixcvLvVYZmam2rZta9FEAADA31habo4fP66srCxlZWVJOvtR76ysLGVnZ0s6+5ZSv379XOs/8MAD2rFjh/7yl7/oxx9/1N///nfNmTNHI0aMsGJ8AADghywtN+vWrVNycrKSk5MlSSNHjlRycrLGjh0rScrJyXEVHUlKTEzUJ598oszMTLVo0UKTJk3SG2+8YeRj4AAAoHxwOJ1Op9VDmJSXl6eoqCjl5uaqSpUqVo8DAADc4Mm/3+XqnBsAAIDLodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbCbF6ANOcTqckKS8vz+JJAACAu879u33u3/FLCbhyk5+fL0mKj4+3eBIAAOCp/Px8RUVFXXIdh9OdCmQjJSUl2rdvnyIjI+VwODzePi8vT/Hx8dqzZ4+qVKnigwn9E6+b1x0IeN287kBQXl+30+lUfn6+4uLiFBR06bNqAu7ITVBQkOrWrXvFz1OlSpVy9T8Kb+F1BxZed2DhdQeW8vi6L3fE5hxOKAYAALZCuQEAALZCufFQaGionnzySYWGhlo9ilG8bl53IOB187oDQSC87oA7oRgAANgbR24AAICtUG4AAICtUG4AAICtUG4AAICtUG48MGXKFCUkJCgsLEzXX3+91qxZY/VIPpeRkaHWrVsrMjJSMTEx6tGjh7Zs2WL1WEY9++yzcjgcGj58uNWj+NzevXt17733qnr16goPD1ezZs20bt06q8fyqeLiYj3xxBNKTExUeHi4rrrqKv31r3916/o15c3y5cuVmpqquLg4ORwOLViwoNTPnU6nxo4dq9jYWIWHh6tz58766aefrBnWiy71uouKijRmzBg1a9ZMlStXVlxcnPr166d9+/ZZN7CXXO73/b8eeOABORwOvfTSS8bm8yXKjZtmz56tkSNH6sknn9SGDRvUokULde3aVQcPHrR6NJ9atmyZ0tLStHr1amVmZqqoqEhdunRRQUGB1aMZsXbtWv3jH/9Q8+bNrR7F544ePar27durQoUK+uyzz7R582ZNmjRJ1apVs3o0n5owYYKmTp2qV199VT/88IMmTJigiRMn6pVXXrF6NK8rKChQixYtNGXKlAv+fOLEiXr55Zf12muv6ZtvvlHlypXVtWtXnTp1yvCk3nWp133ixAlt2LBBTzzxhDZs2KB58+Zpy5Yt6t69uwWTetflft/nzJ8/X6tXr1ZcXJyhyQxwwi1t2rRxpqWlue4XFxc74+LinBkZGRZOZd7BgwedkpzLli2zehSfy8/PdyYlJTkzMzOdt9xyi/Ohhx6yeiSfGjNmjPPGG2+0egzjunXr5hw0aFCpx37/+98777nnHosmMkOSc/78+a77JSUlztq1azufe+4512PHjh1zhoaGOt977z0LJvSNX7/uC1mzZo1TknP37t1mhjLgYq/7559/dtapU8e5adMmZ/369Z0vvvii8dl8gSM3bjh9+rTWr1+vzp07ux4LCgpS586dtWrVKgsnMy83N1eSFB0dbfEkvpeWlqZu3bqV+r3b2cKFC9WqVSv17NlTMTExSk5O1uuvv271WD7Xrl07LV68WFu3bpUkffvtt1qxYoVSUlIsnsysnTt3av/+/aX+9x4VFaXrr78+IP/OORwOVa1a1epRfKqkpER9+/bV6NGj1aRJE6vH8aqAu3BmWRw6dEjFxcWqVatWqcdr1aqlH3/80aKpzCspKdHw4cPVvn17NW3a1OpxfGrWrFnasGGD1q5da/UoxuzYsUNTp07VyJEj9eijj2rt2rUaNmyYKlasqP79+1s9ns888sgjysvLU+PGjRUcHKzi4mI988wzuueee6wezaj9+/dL0gX/zp37WSA4deqUxowZoz59+pS7i0p6asKECQoJCdGwYcOsHsXrKDdwW1pamjZt2qQVK1ZYPYpP7dmzRw899JAyMzMVFhZm9TjGlJSUqFWrVho/frwkKTk5WZs2bdJrr71m63IzZ84czZgxQzNnzlSTJk2UlZWl4cOHKy4uztavG+crKipSr1695HQ6NXXqVKvH8an169dr8uTJ2rBhgxwOh9XjeB1vS7mhRo0aCg4O1oEDB0o9fuDAAdWuXduiqcwaMmSIPv74Yy1ZskR169a1ehyfWr9+vQ4ePKiWLVsqJCREISEhWrZsmV5++WWFhISouLjY6hF9IjY2Vtdee22px6655hplZ2dbNJEZo0eP1iOPPKK7775bzZo1U9++fTVixAhlZGRYPZpR5/6WBerfuXPFZvfu3crMzLT9UZuvv/5aBw8eVL169Vx/53bv3q1Ro0YpISHB6vGuGOXGDRUrVtR1112nxYsXux4rKSnR4sWL1bZtWwsn8z2n06khQ4Zo/vz5+uqrr5SYmGj1SD5366236vvvv1dWVpbr1qpVK91zzz3KyspScHCw1SP6RPv27c/7mP/WrVtVv359iyYy48SJEwoKKv2nMDg4WCUlJRZNZI3ExETVrl271N+5vLw8ffPNN7b/O3eu2Pz000/68ssvVb16datH8rm+ffvqu+++K/V3Li4uTqNHj9aiRYusHu+K8baUm0aOHKn+/furVatWatOmjV566SUVFBRo4MCBVo/mU2lpaZo5c6Y+/PBDRUZGut57j4qKUnh4uMXT+UZkZOR55xRVrlxZ1atXt/W5RiNGjFC7du00fvx49erVS2vWrNG0adM0bdo0q0fzqdTUVD3zzDOqV6+emjRpoo0bN+qFF17QoEGDrB7N644fP65t27a57u/cuVNZWVmKjo5WvXr1NHz4cP3tb39TUlKSEhMT9cQTTyguLk49evSwbmgvuNTrjo2N1V133aUNGzbo448/VnFxsevvXHR0tCpWrGjV2Ffscr/vX5e4ChUqqHbt2mrUqJHpUb3P6o9rlSevvPKKs169es6KFSs627Rp41y9erXVI/mcpAve3n77batHMyoQPgrudDqdH330kbNp06bO0NBQZ+PGjZ3Tpk2zeiSfy8vLcz700EPOevXqOcPCwpwNGjRwPvbYY87CwkKrR/O6JUuWXPC/5/79+zudzrMfB3/iiSectWrVcoaGhjpvvfVW55YtW6wd2gsu9bp37tx50b9zS5YssXr0K3K53/ev2emj4A6n04ZfwwkAAAIW59wAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAAABbodwAMG7AgAGWfqV/3759XVc/v1KnT59WQkKC1q1b55XnA3Dl+IZiAF7lcDgu+fMnn3xSI0aMkNPpVNWqVc0M9T++/fZbderUSbt371ZERIRXnvPVV1/V/PnzS110EoB1KDcAvOrcRQclafbs2Ro7dmypq41HRER4rVSUxeDBgxUSEqLXXnvNa8959OhR1a5dWxs2bFCTJk289rwAyoa3pQB4Ve3atV23qKgoORyOUo9FRESc97ZUhw4dNHToUA0fPlzVqlVTrVq19Prrr6ugoEADBw5UZGSkGjZsqM8++6zUvjZt2qSUlBRFRESoVq1a6tu3rw4dOnTR2YqLi/XBBx8oNTW11OMJCQkaP368Bg0apMjISNWrV6/U1dBPnz6tIUOGKDY2VmFhYapfv74yMjJcP69WrZrat2+vWbNmXWF6ALyBcgPAL7zzzjuqUaOG1qxZo6FDh+rBBx9Uz5491a5dO23YsEFdunRR3759deLECUnSsWPH1KlTJyUnJ2vdunX6/PPPdeDAAfXq1eui+/juu++Um5urVq1anfezSZMmqVWrVtq4caP+/Oc/68EHH3QdcXr55Ze1cOFCzZkzR1u2bNGMGTOUkJBQavs2bdro66+/9l4gAMqMcgPAL7Ro0UKPP/64kpKSlJ6errCwMNWoUUN//OMflZSUpLFjx+rw4cP67rvvJJ09zyU5OVnjx49X48aNlZycrLfeektLlizR1q1bL7iP3bt3Kzg4WDExMef97I477tCf//xnNWzYUGPGjFGNGjW0ZMkSSVJ2draSkpJ04403qn79+rrxxhvVp0+fUtvHxcVp9+7dXk4FQFlQbgD4hebNm7uWg4ODVb16dTVr1sz1WK1atSRJBw8elHT2xOAlS5a4zuGJiIhQ48aNJUnbt2+/4D5Onjyp0NDQC570/L/7P/dW2rl9DRgwQFlZWWrUqJGGDRumL7744rztw8PDXUeVAFgrxOoBAECSKlSoUOq+w+Eo9di5QlJSUiJJOn78uFJTUzVhwoTznis2NvaC+6hRo4ZOnDih06dPq2LFipfd/7l9tWzZUjt37tRnn32mL7/8Ur169VLnzp31wQcfuNY/cuSIatas6e7LBeBDlBsA5VLLli01d+5cJSQkKCTEvT9lv/nNbyRJmzdvdi27q0qVKurdu7d69+6tu+66S7fffruOHDmi6OhoSWdPbk5OTvboOQH4Bm9LASiX0tLSdOTIEfXp00dr167V9u3btWjRIg0cOFDFxcUX3KZmzZpq2bKlVqxY4dG+XnjhBb333nv68ccftXXrVr3//vuqXbt2qe/p+frrr9WlS5creUkAvIRyA6BciouL08qVK1VcXKwuXbqoWbNmGj58uKpWraqgoIv/aRs8eLBmzJjh0b4iIyM1ceJEtWrVSq1bt9auXbv06aefuvazatUq5ebm6q677rqi1wTAO/gSPwAB5eTJk2rUqJFmz56ttm3beuU5e/furRYtWujRRx/1yvMBuDIcuQEQUMLDw/Xuu+9e8sv+PHH69Gk1a9ZMI0aM8MrzAbhyHLkBAAC2wpEbAABgK5QbAABgK5QbAABgK5QbAABgK5QbAABgK5QbAABgK5QbAABgK5QbAABgK5QbAABgK/8Pk8sYW3mqBqIAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import RepetitionPT\n", + "\n", + "repetition_pt = RepetitionPT(first_point_pt, 'n_rep')\n", + "\n", + "print(\"repetition parameters: {}\".format(repetition_pt.parameter_names))\n", + "print(\"repetition measurements: {}\".format(repetition_pt.measurement_names))\n", + "\n", + "# let's plot to see the results\n", + "parameters['n_rep'] = 5 # add a value for our n_rep parameter\n", + "_ = plot(repetition_pt, parameters, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same remarks that were made about `SequencePT` also hold for `RepetitionPT`: it will expose all parameters and measurements defined by its subtemplate and will be defined on the same channels.\n", + "\n", + "## ForLoopPulseTemplate: Repeat a Pulse with a Varying Loop Parameter\n", + "\n", + "The `RepetitionPT` simple repeats the exact same subtemplate a given number of times. Sometimes, however, it is rather required to vary the parameters of a subtemplate in a loop, for example when trying to determine the best value for a parameter of a given pulse. This is what the `ForLoopPulseTemplate` is intended for. As the name suggests, its behavior mimics that for `for-loop` constructs in programming languages by repeating its content - the subtemplate - for a number of times while at the same time supplying a loop parameter that iterates over a range of values.\n", + "\n", + "In the following we make use of this to vary the value of parameter `t` in `first_point_pt` over several iterations. More specifically, we will have all a `first_point_pt` pulse for all even values of `t` between `t_start` and `t_end` which are new parameters. For the plot we will set them to `t_start = 4` and `t_end = 13`, i.e., `t = 4, 6, 8, 10, 12`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "for loop parameters: {'v_0', 'v_1', 't_end', 't_start'}\n", + "for loop measurements: {'M'}\n" + ] + }, + { + "data": { + "image/png": "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oDo8TnReeOEFvfzyyxo7dqxr39VXX62uXbvqscceI9EBAAB1hsdNV9nZ2br44ovP2X/xxRcrOzvbK0EBAAB4g8eJTvv27fXee++ds3/u3LkVLqoJAABgFo+brqZOnarRo0dr2bJlrj46K1as0KJFiypMgAAAAMzido3O5s2bJUnXXnutvv32WzVv3lwLFy7UwoUL1bx5c61evVq/+93vfBYoAACAp9yu0enRo4f69Omj2267TX/84x/1n//8x5dxAQAA1JjbNTpLly5V165ddf/99ysqKkrjx4/XN99848vYAAAAasTtROfSSy/VG2+8oezsbL3wwgvKzMzU5Zdfrg4dOuipp57S/v37fRknAACAxzweddW4cWPdfPPNWrp0qbZt26brrrtOL730ktq0aaOrr77aFzECAABUS43Wumrfvr0efvhhPfLIIwoNDdWnn37qrbgAAABqzOPh5U7Lli3TG2+8ofnz58vPz0+jRo3Srbfe6s3YAAAAasSjROfnn39WWlqa0tLStH37dl188cV6/vnnNWrUKDVu3NhXMQIAAFSL24lOUlKSvvrqKzVv3lxjx47VLbfcoo4dO/oyNgAAgBpxO9Fp2LCh3n//ff2///f/1KBBA1/GBAAA4BVuJzofffSRL+MAAADwuhqNugIAAKjLSHQAAIBtkegAAADbItEBAAC2RaIDAABsi0QHAADYFokOAACwLRIdAABgWyQ6AADAtkh0AACAbZHoAAAA2yLRAQAAtmVqorNs2TKNGDFC0dHRcjgcWrhwodvnrlixQv7+/rrooot8Fh8AALA2UxOdgoICJSQk6KWXXvLovGPHjmns2LEaPHiwjyIDAAB24G/mmyclJSkpKcnj8+68805df/31atCggUe1QAAAoH6xXB+dN998Uzt37tSjjz7q1vFFRUXKzc0t9/CGUsPwynVQd1HG5jtxssTsEOBjxylj+JilEp2ffvpJf/nLX/Sf//xH/v7uVUalpqYqLCzM9YiJifFKLF/+cECSdb8MD+UXSZJKLBp/bfjv5v2SrFvGdrA+65gkysDONu87/eOTzyL4imUSnZKSEl1//fWaOnWqOnTo4PZ5KSkpysnJcT327NnjlXh+zD79x/lLXrFXrlfb1u0+Kknis6VymYcKJEmHC6xZxnYS3NDUVnb4iFHmA6hJUEMTI4GdWebTIy8vT2vX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NdeYEk9tOHjwoCHJWLp0qWEYp8u0YcOGxrx581zH/Pjjj4YkY+XKlWaF6TW/vl/DMIzLL7/cuPfee80LqhY0a9bMeP31121fvk7O+zUM+5ZvXl6eER8fb6Snp5e7R2+Wcb2v0SkuLta6des0ZMgQ1z4/Pz8NGTJEK1euNDEy3/rpp58UHR2tdu3a6YYbblBWVpbZIdWKzMxM7d+/v1x5h4WFqV+/frYub0lasmSJIiIi1LFjR9111106fPiw2SF5TU5OjiQpPDxckrRu3TqdPHmyXDl36tRJbdq0sUU5//p+nd5++201b95c3bp1U0pKigoLC80Iz+tKSko0Z84cFRQUqH///rYv31/fr5Mdyzc5OVnDhw8vV5aSd/+G692inr926NAhlZSUqGXLluX2t2zZUlu2bDEpKt/q16+f0tLS1LFjR2VnZ2vq1Km69NJLtXnzZoWGhpodnk/t379fkiosb+drdnTllVfq97//veLi4rRjxw49/PDDSkpK0sqVK9WgQQOzw6uR0tJSTZo0SQMGDFC3bt0knS7ngIAANW3atNyxdijniu5Xkq6//nq1bdtW0dHR2rhxox566CFt3bpVH3zwgYnR1symTZvUv39/nThxQiEhIVqwYIG6dOmijIwMW5ZvZfcr2bN858yZo/Xr12vNmjXnvObNv+F6n+jUR0lJSa7tHj16qF+/fmrbtq3ee+893XrrrSZGBl/54x//6Nru3r27evTooQsvvFBLlizR4MGDTYys5pKTk7V582Zb9TM7n8ru909/+pNru3v37oqKitLgwYO1Y8cOXXjhhbUdpld07NhRGRkZysnJ0fvvv69x48Zp6dKlZoflM5Xdb5cuXWxXvnv27NG9996r9PR0BQUF+fS96n3TVfPmzdWgQYNzenIfOHBAkZGRJkVVu5o2baoOHTpo+/btZofic84yrc/lLUnt2rVT8+bNLV/mEyZM0CeffKLFixerdevWrv2RkZEqLi7WsWPHyh1v9XKu7H4r0q9fP0mydBkHBASoffv26tWrl1JTU5WQkKCZM2fatnwru9+KWL18161bp4MHD6pnz57y9/eXv7+/li5dqueff17+/v5q2bKl18q43ic6AQEB6tWrlxYtWuTaV1paqkWLFpVrG7Wz/Px87dixQ1FRUWaH4nNxcXGKjIwsV965ubn69ttv6015S9LevXt1+PBhy5a5YRiaMGGCFixYoK+//lpxcXHlXu/Vq5caNmxYrpy3bt2qrKwsS5ZzVfdbkYyMDEmybBlXpLS0VEVFRbYr38o477ciVi/fwYMHa9OmTcrIyHA9evfurRtuuMG17bUy9l7faeuaM2eOERgYaKSlpRk//PCD8ac//clo2rSpsX//frND84n777/fWLJkiZGZmWmsWLHCGDJkiNG8eXPj4MGDZofmFXl5ecaGDRuMDRs2GJKMZ5991tiwYYOxe/duwzAM48knnzSaNm1qfPjhh8bGjRuNa665xoiLizOOHz9ucuTVd757zsvLMx544AFj5cqVRmZmpvHVV18ZPXv2NOLj440TJ06YHXq13HXXXUZYWJixZMkSIzs72/UoLCx0HXPnnXcabdq0Mb7++mtj7dq1Rv/+/Y3+/fubGHX1VXW/27dvNx5//HFj7dq1RmZmpvHhhx8a7dq1My677DKTI6++v/zlL8bSpUuNzMxMY+PGjcZf/vIXw+FwGF9++aVhGPYqX8M4//3asXwr8uuRZd4qYxKdM1544QWjTZs2RkBAgNG3b19j1apVZofkM6NHjzaioqKMgIAAo1WrVsbo0aON7du3mx2W1yxevNiQdM5j3LhxhmGcHmL+t7/9zWjZsqURGBhoDB482Ni6dau5QdfQ+e65sLDQGDp0qNGiRQujYcOGRtu2bY3bb7/d0ol8RfcqyXjzzTddxxw/fty4++67jWbNmhmNGjUyfve73xnZ2dnmBV0DVd1vVlaWcdlllxnh4eFGYGCg0b59e+PBBx80cnJyzA28Bm655Rajbdu2RkBAgNGiRQtj8ODBriTHMOxVvoZx/vu1Y/lW5NeJjrfK2GEYhlHNmicAAIA6rd730QEAAPZFogMAAGyLRAcAANgWiQ4AALAtEh0AAGBbJDoAAMC2SHQAAIBtkegAAADbItEBUOvGjx+vkSNHmvb+N910k6ZNm+aVaxUXFys2NlZr1671yvUAeBczIwPwKofDcd7XH330Ud13330yDENNmzatnaDK+O677zRo0CDt3r1bISEhXrnmiy++qAULFpRbgBBA3UCiA8Cr9u/f79qeO3eupkyZoq1bt7r2hYSEeC3BqI7bbrtN/v7+euWVV7x2zaNHjyoyMlLr169X165dvXZdADVH0xUAr4qMjHQ9wsLC5HA4yu0LCQk5p+lq4MCBmjhxoiZNmqRmzZqpZcuWeu2111RQUKCbb75ZoaGhat++vf773/+We6/NmzcrKSlJISEhatmypW666SYdOnSo0thKSkr0/vvva8SIEeX2x8bGatq0abrlllsUGhqqNm3a6NVXX3W9XlxcrAkTJigqKkpBQUFq27atUlNTXa83a9ZMAwYM0Jw5c2r4rwfA20h0ANQJb731lpo3b67Vq1dr4sSJuuuuu3Tdddfp4osv1vr16zV06FDddNNNKiwslCQdO3ZMgwYNUmJiotauXavPP/9cBw4c0KhRoyp9j40bNyonJ0e9e/c+57UZM2aod+/e2rBhg+6++27dddddrpqo559/Xh999JHee+89bd26VW+//bZiY2PLnd+3b19988033vsHAeAVJDoA6oSEhAQ98sgjio+PV0pKioKCgtS8eXPdfvvtio+P15QpU3T48GFt3LhR0ul+MYmJiZo2bZo6deqkxMREvfHGG1q8eLG2bdtW4Xvs3r1bDRo0UERExDmvXXXVVbr77rvVvn17PfTQQ2revLkWL14sScrKylJ8fLwuueQStW3bVpdcconGjBlT7vzo6Gjt3r3by/8qAGqKRAdAndCjRw/XdoMGDXTBBReoe/furn0tW7aUJB08eFDS6U7FixcvdvX5CQkJUadOnSRJO3bsqPA9jh8/rsDAwAo7TJd9f2dzm/O9xo8fr4yMDHXs2FH33HOPvvzyy3PODw4OdtU2Aag7/M0OAAAkqWHDhuWeOxyOcvucyUlpaakkKT8/XyNGjNBTTz11zrWioqIqfI/mzZursLBQxcXFCggIqPL9ne/Vs2dPZWZm6r///a+++uorjRo1SkOGDNH777/vOv7IkSNq0aKFu7cLoJaQ6ACwpJ49e2r+/PmKjY2Vv797H2UXXXSRJOmHH35wbburSZMmGj16tEaPHq0//OEPuvLKK3XkyBGFh4dLOt0xOjEx0aNrAvA9mq4AWFJycrKOHDmiMWPGaM2aNdqxY4e++OIL3XzzzSopKanwnBYtWqhnz55avny5R+/17LPP6t1339WWLVu0bds2zZs3T5GRkeXmAfrmm280dOjQmtwSAB8g0QFgSdHR0VqxYoVKSko0dOhQde/eXZMmTVLTpk3l51f5R9ttt92mt99+26P3Cg0N1fTp09W7d2/16dNHu3bt0meffeZ6n5UrVyonJ0d/+MMfanRPALyPCQMB1CvHjx9Xx44dNXfuXPXv398r1xw9erQSEhL08MMPe+V6ALyHGh0A9UpwcLBmz5593okFPVFcXKzu3bvrvvvu88r1AHgXNToAAMC2qNEBAAC2RaIDAABsi0QHAADYFokOAACwLRIdAABgWyQ6AADAtkh0AACAbZHoAAAA2yLRAQAAtvX/ATmezirBcyO9AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import ForLoopPT\n", + "\n", + "for_loop_pt = ForLoopPT(first_point_pt, 't', ('t_start', 't_end', 2))\n", + "\n", + "print(\"for loop parameters: {}\".format(for_loop_pt.parameter_names))\n", + "print(\"for loop measurements: {}\".format(for_loop_pt.measurement_names))\n", + "\n", + "# plot it\n", + "parameters['t_start'] = 4\n", + "parameters['t_end'] = 13\n", + "_ = plot(for_loop_pt, parameters, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The second argument to `ForLoopPT`'s constructor is the name of the loop parameter. This has to be a parameter that is defined by the subtemplate. The third argument defined the range of the loop. The syntax of the range is similar to that of the `range()` command in Python, i.e., a tuple `(start_value, end_value, step)`. As seen above, inserting parameter values or even expressions is okay. As in `range()`, the `end_value` is exclusive.\n", + "\n", + "As for `SequencePT` and `RepetitionPT`, `ForLoopPT` exposes all parameters defined by the subtemplate except for the loop parameter, `t` in the above example. If expressions are used in the range definition and they make use of additional parameters, these are also exposed by `ForLoopPT`. \n", + "\n", + "`ForLoopPT` also exposes measurements defined by subtemplates.\n", + "\n", + "## AtomicMultiChannelPulseTemplate: Run Pulses in Parallel on Different Channels\n", + "\n", + "So far we have only looked at pulses that affect the time-domain aspect of combining pulses. Another way to combine pulses is to parallelise them by executing them on different channels at the same time. This is of course already supported by simply creating atomic pulse templates (`TablePT`, `PointPT`, `FunctionPT`) on multiple channels. However, sometimes it is necessary to put already existing pulses in parallel. Instead of having to define a new atomic pulse template for this, we can make use of the `AtomicMuliChannelPulseTemplate` class. To learn more about how this works, see [Multi-Channel Pulses](00MultiChannelTemplates.ipynb).\n", + "\n", + "## Combining Combined Pulses\n", + "\n", + "Our examples above have build combined higher-level pulses (`SequencePT`, `RepetitionPT`, `ForLoopPT`) on atomic subtemplates only. However, this is not a requirement. We can use `SequencePT`, `RepetitionPT` and `ForLoopPT` using any `PulseTemplate` objects as subtemplates allowing us to build arbitrarily complex pulses out of only a handful of primitives." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/00ConstantPulseTemplate.ipynb b/doc/source/examples/00ConstantPulseTemplate.ipynb new file mode 100644 index 000000000..0dafbe501 --- /dev/null +++ b/doc/source/examples/00ConstantPulseTemplate.ipynb @@ -0,0 +1,72 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The ConstantPulseTemplate: Efficient constant voltage description.\n", + "\n", + "The `ConstantPulseTemplate`(or short `ConstantPT`) can be used to define pulse templates with all channels a constant value. The template is easy to define and allows backends to optimize the waveforms on an AWG." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'B', 'A'}\n", + "{'A': ExpressionScalar('10.0000000000000'), 'B': ExpressionScalar('1.0*b')}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import ConstantPT\n", + "\n", + "constant_template = ConstantPT(10, {'A': 1., 'B': 'b * 0.1'})\n", + "\n", + "print(constant_template.defined_channels)\n", + "print(constant_template.integral)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The pulse template has two channels." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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8vA43Gzbtq3Eez8/P9WrV08zZsy47pVUAAAAFc3jcLNu3bqKqAMAAMAruIkfAAAwitfCzZgxYzgtBQAAfM5rD848evSojhw54q3hAAC4LofDoYsXL/q6DHhJYGCgVx7C7bVw8/rrr3trKAAArsmyLOXm5urMmTO+LgVe5Ofnp8TERAUGBt7QOF4LNwAAVJYrwSYqKkohISGy2Wy+Lgk3yOl06tixYzp+/LgaNGhwQ79pucJNYWGhPv30Ux0+fFjFxcUlPhsxYkS5iwEA4HocDocr2NStW9fX5cCL6tWrp2PHjunSpUuqUaNGuccp131u7rzzTp0/f16FhYWqU6eOTp06pZCQEEVFRRFuAAAV6socm5CQEB9XAm+7cjrK4XDcULjxeNbOyJEjlZGRoR9//FHBwcH68ssv9f3336tdu3Z6+eWXy10IAACe4FSUebz1m3ocbnJycvTHP/5Rfn5+8vf3V1FRkeLj4zVt2jSNGTPGK0UBAACUl8fhpkaNGq7LtKKionT48GFJUkREBJeCAwBQTocOHZLNZlNOTo6vS3HLbbfdpszMTF+XUSaPw01KSoo2b94sSeratavGjx+vN998U5mZmWrZsqXXCwQAANXPkiVLZLPZXK/Q0FC1a9dO77zzToWv2+NwM3nyZMXGxkqSJk2apNq1a+uxxx7TyZMnNX/+fK8XCAAAqqfw8HAdP35cx48f17Zt25Senq4+ffpoz549Fbpej8NNamqqunXrJunyaanVq1eroKBAW7ZsUXJystcLBADAFE6nU9OmTVPjxo1lt9vVoEEDTZo0qUSfAwcOqFu3bgoJCVFycrI2btzo+uyHH35Qv379VL9+fYWEhKhVq1Z66623Six/2223acSIEXr66adVp04dxcTE6LnnnivRx2azaeHChbrnnnsUEhKipKQkrVq1qkSfHTt2qFevXgoNDVV0dLQGDBigU6dOefR9bTabYmJiFBMTo6SkJL344ovy8/PT9u3bPRrHUzw4EwBQ7VmWpfPFl3zysizL7TpHjx6tl156SePGjdPOnTu1dOlSRUdHl+jz7LPP6qmnnlJOTo6aNGmifv366dKlS5Kkn376Se3atdP777+vHTt26NFHH9WAAQO0adOmEmO8/vrrqlmzpr766itNmzZNzz//vNauXVuiz8SJE9WnTx9t375dd955px544AGdPn1aknTmzBl1795dKSkp+vrrr7V69Wrl5eWpT58+5fl5JF2+vPvK0wzatm1b7nHc4dZ9bu644w4999xz+tWvfnXNfmfPntVrr72m0NBQDRs2zCsFAgBwPRcuOtR8/BqfrHvn8+kKCbz+7vTs2bN69dVXNWfOHA0aNEiSdPPNN6tLly4l+j311FO66667JF0OIC1atNC+ffvUrFkz1a9fX0899ZSr7xNPPKE1a9ZoxYoVat++vau9devWmjBhgiQpKSlJc+bMUXZ2tm6//XZXnwcffFD9+vWTdHnKyezZs7Vp0ybdcccdmjNnjlJSUjR58mRX/8WLFys+Pl579+5VkyZN3No2+fn5Cg0NlSRduHBBNWrU0Pz583XzzTe7tXx5uRVu7r//ft17772KiIhQRkaGUlNTFRcXp6CgIP3444/auXOn1q9frw8++EB33XWXpk+fXqFFAwBQ3ezatUtFRUXq0aPHNfu1bt3a9feVOa4nTpxQs2bN5HA4NHnyZK1YsUJHjx5VcXGxioqKSt3Q8OdjXBnnxIkTV+1Ts2ZNhYeHu/p88803WrdunSuY/Nz+/fvdDjdhYWHaunWrJOn8+fP6+OOPNXToUNWtW1cZGRlujVEeboWbhx9+WP3799df/vIXLV++XPPnz1d+fr6ky+fTmjdvrvT0dG3evFm33HJLhRULAEBZgmv4a+fz6T5bt1v9goPd6vfzO/Neuamd0+mUJE2fPl2vvvqqZs2apVatWqlmzZrKzMws9Sikf727r81mc43hTp9z584pIyNDU6dOLVXflcDlDj8/PzVu3Nj1vnXr1vroo480depU34cbSbLb7erfv7/69+8v6fKhpgsXLqhu3bo3dItkAABulM1mc+vUkC8lJSUpODhY2dnZGjJkSLnG2LBhg37729+69sVOp1N79+5V8+bNvVmq2rZtq5UrVyohIUEBAd7drv7+/rpw4YJXx/xX5Z5QHBERoZiYGIINAABuCAoK0qhRo/T000/rjTfe0P79+/Xll19q0aJFbo+RlJSktWvX6osvvtCuXbv0hz/8QXl5eV6vddiwYTp9+rT69eunzZs3a//+/VqzZo0GDx4sh8Ph9jiWZSk3N1e5ubk6ePCg5s+frzVr1ui3v/2t12v+uaodcwEAMMi4ceMUEBCg8ePH69ixY4qNjdXQoUPdXn7s2LE6cOCA0tPTFRISokcffVS9e/d2TRXxlri4OG3YsEGjRo1Sz549VVRUpIYNG+qOO+5wPaXAHQUFBa7TWHa7XQ0bNtTzzz+vUaNGebXef2WzPLmGzQAFBQWKiIhQfn6+wsPDfV0OAMBDP/30kw4ePKjExEQFBQX5uhx40bV+W0/239znBgAAGIVwAwAAjFKucHPmzBktXLhQo0ePdt3NcOvWrTp69KhXiwMAAPCUxxOKt2/frrS0NEVEROjQoUN65JFHVKdOHb3zzjs6fPiw3njjjYqoEwAAwC0eH7nJysrSgw8+qO+++67EZJ8777xTn332mVeLAwAA8JTH4Wbz5s36wx/+UKq9fv36ys3N9biAuXPnKiEhQUFBQerQoUOph3/9qzNnzmjYsGGKjY2V3W5XkyZN9MEHH3i8XgAAYCaPT0vZ7XYVFBSUat+7d6/q1avn0VjLly9XVlaW5s2bpw4dOmjWrFlKT0/Xnj17FBUVVap/cXGxbr/9dkVFRentt99W/fr19f3336tWrVqefg0AAGAoj4/c3H333Xr++ed18eJFSZdveX348GGNGjVK9957r0djzZw5U4888ogGDx6s5s2ba968eQoJCdHixYvL7L948WKdPn1a7733njp37qyEhAR17dpVycnJnn4NAABgKI/DzYwZM3Tu3DlFRUXpwoUL6tq1qxo3bqywsDBNmjTJ7XGKi4u1ZcsWpaWl/bMYPz+lpaVp48aNZS6zatUqdezYUcOGDVN0dLRatmypyZMnX/NW0EVFRSooKCjxAgAA5vL4tFRERITWrl2r9evXa/v27Tp37pzatm1bIqS449SpU3I4HIqOji7RHh0drd27d5e5zIEDB/T3v/9dDzzwgD744APt27dPjz/+uC5evKgJEyaUucyUKVM0ceJEj2oDAKCyHTp0SImJidq2bZvatGnj63Ku67bbblObNm00a9YsX5dSSrmfLdWlSxd16dLFm7Vcl9PpVFRUlObPny9/f3+1a9dOR48e1fTp068abkaPHq2srCzX+4KCAsXHx1dWyQAA/KJduHBB9evXl5+fn44ePSq73V7h6/Q43MyePbvMdpvNpqCgIDVu3Fj/7//9P/n7+19znMjISPn7+5d6mmleXp5iYmLKXCY2NlY1atQoMfYtt9yi3NxcFRcXKzAwsNQydru9UjYkAAAobeXKlWrRooUsy9J7772nvn37Vvg6PZ5z88orr2jMmDHKzMzUxIkTNXHiRGVmZmr06NEaN26cevTooaZNm+rIkSPXHCcwMFDt2rVTdna2q83pdCo7O1sdO3Ysc5nOnTtr3759cjqdrra9e/cqNja2zGADAEBV4nQ6NW3aNDVu3Fh2u10NGjQoNV/1wIED6tatm0JCQpScnFxiHuoPP/ygfv36qX79+goJCVGrVq301ltvlVj+tttu04gRI/T000+rTp06iomJ0XPPPVeij81m08KFC3XPPfcoJCRESUlJWrVqVYk+O3bsUK9evRQaGqro6GgNGDBAp06d8vg7L1q0SP3791f//v21aNEij5cvF8tDS5cutW677TZr3759rrbvvvvO6t69u7Vs2TLryJEjVufOna177733umMtW7bMstvt1pIlS6ydO3dajz76qFWrVi0rNzfXsizLGjBggPXMM8+4+h8+fNgKCwuzhg8fbu3Zs8f629/+ZkVFRVkvvvii2/Xn5+dbkqz8/HwPvjUAoKq4cOGCtXPnTuvChQv/bHQ6LavonG9eTqfbtT/99NNW7dq1rSVLllj79u2zPv/8c2vBggWWZVnWwYMHLUlWs2bNrL/97W/Wnj17rPvuu89q2LChdfHiRcuyLOsf//iHNX36dGvbtm3W/v37rdmzZ1v+/v7WV1995VpH165drfDwcOu5556z9u7da73++uuWzWazPvroI1cfSdZNN91kLV261Pruu++sESNGWKGhodYPP/xgWZZl/fjjj1a9evWs0aNHW7t27bK2bt1q3X777Va3bt1KrOfJJ5+85vfdt2+fZbfbrdOnT1s//PCDFRQUZB06dMiz3/b/eLL/tv3fl3TbzTffrJUrV5aa7LRt2zbde++9OnDggL744gvde++9On78+HXHmzNnjqZPn67c3Fy1adNGs2fPVocOHSRdTp8JCQlasmSJq//GjRs1cuRI5eTkqH79+nr44Yc1atSo654Gu8KTR6YDAKqen376SQcPHlRiYuI/75RfXChNjvNNQWOOSYE1r9vt7NmzqlevnubMmaMhQ4aU+vzKhOKFCxfq4YcfliTt3LlTLVq00K5du9SsWbMyx/3Nb36jZs2a6eWXX5Z0ed/pcDj0+eefu/q0b99e3bt310svvSTp8pGbsWPH6oUXXpAkFRYWKjQ0VB9++KHuuOMOvfjii/r888+1Zs0a1xj/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8EHl5OSoadOmGjFihD766KNSywcHB7uOKgHwrQBfFwAAklSjRo0S7202W4m2K4HE6XRKks6dO6eMjAxNnTq11FixsbFlriMyMlLnz59XcXGxAgMDr7v+K+tq27atDh48qA8//FAff/yx+vTpo7S0NL399tuu/qdPn1a9evXc/boAKhDhBkC11LZtW61cuVIJCQkKCHDvn7I2bdpIknbu3On6213h4eHq27ev+vbtq/vuu0933HGHTp8+rTp16ki6PLk5JSXFozEBVAxOSwGoloYNG6bTp0+rX79+2rx5s/bv3681a9Zo8ODBcjgcZS5Tr149tW3bVuvXr/doXTNnztRbb72l3bt3a+/evfrLX/6imJiYEvfp+fzzz9WzZ88b+UoAvIRwA6BaiouL04YNG+RwONSzZ0+1atVKmZmZqlWrlvz8rv5P25AhQ/Tmm296tK6wsDBNmzZNqampuvXWW3Xo0CF98MEHrvVs3LhR+fn5uu+++27oOwHwDm7iB+AX5cKFC2ratKmWL1+ujh07emXMvn37Kjk5WWPGjPHKeABuDEduAPyiBAcH64033rjmzf48UVxcrFatWmnkyJFeGQ/AjePIDQAAMApHbgAAgFEINwAAwCiEGwAAYBTCDQAAMArhBgAAGIVwAwAAjEK4AQAARiHcAAAAoxBuAACAUf4/vUa+J2Znxp4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses.plotting import plot\n", + "\n", + "_ = plot(constant_template, parameters={'b': 2.2}, sample_rate=100)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/doc/source/examples/00FunctionPulse.ipynb b/doc/source/examples/00FunctionPulse.ipynb new file mode 100644 index 000000000..1bb33ff91 --- /dev/null +++ b/doc/source/examples/00FunctionPulse.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modelling Pulses Using Functions And Expressions\n", + "\n", + "Assume we want to model a pulse that represents a damped sine function. While we could, in theory, do this using `TablePulseTemplate`s by piecewise linear approximation (cf. [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb)), this would be a tedious endeavor. A much simpler approach presents itself in the form of the `FunctionPulseTemplate` class of qupulse. Like the `TablePulseTemplate`, a `FunctionPulseTemplate` represents an atomic pulse which will be converted into a waveform for execution. The difference between both is that `FunctionPulseTemplate` accepts a mathematical expression which is parsed and evaluated using `sympy` to sample the waveform instead of the linear interpolation between specified supporting points as it is done in `TablePulseTemplate`.\n", + "\n", + "To define the sine function pulse template, we can thus do the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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0tJSlZeXKzAw8LKvX/VavXv31qFDh/Tvf/9b7733nu644w4lJyfr73//u2X/U6dOqVWrVra+XQBugiAEwCP17t1ba9asUVxcnJo0se2rrGfPnpKkffv2Wf62VXh4uFJTU5WamqrbbrtNN998s06dOqXIyEhJP3Tc7tWrl13HBOB6XBoD4JHuu+8+nTp1SiNGjNC2bduUl5endevWKT09XRUVFbU+p1WrVurdu7c2bdpk12vNnz9ff/vb3/T555/r4MGDev311xUTE2M1D9JHH32km266qTFvCYALEIQAeKS2bdtq8+bNqqio0E033aTu3btr0qRJatGihfz96/5qGzt2rF599VW7XissLExz5sxRYmKi+vbtq8OHD+vdd9+1vE5ubq6Kiop02223Neo9AXA+JlQE4FPOnz+vTp06afXq1erfv78px0xNTVWPHj30yCOPmHI8AM5DixAAn9KsWTO9/PLL9U68aI/y8nJ1795dkydPNuV4AJyLFiEAAOCzaBECAAA+iyAEAAB8FkEIAAD4LIIQAADwWQQhAADgswhCAADAZxGEAACAzyIIAQAAn0UQAgAAPuv/AHgd3ndcu7PEAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import FunctionPT\n", + "from qupulse.plotting import plot\n", + "\n", + "template = FunctionPT('exp(-t/2)*sin(2*t / pi)', '2')\n", + "\n", + "_ = plot(template, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first argument to `FunctionPulseTemplate`'s constructor is the string representation of the formula that the pulse represents. The second argument is used to compute the length of the pulse. In this case, this is simply a constant expression. Refer to [sympy's documentation](http://docs.sympy.org/latest/index.html) to read about the usable operators and functions in the expressions.\n", + "\n", + "The `t` is reserved as the free variable of the time domain in the first argument and must be present. Other variables can be used at will and corresponding values have to be passed in as a parameter when instantiating a pulse for execution from the created `FunctionPulseTemplate` object:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Simon\\Documents\\git\\qupulse\\qupulse\\plotting.py:186: UserWarning: Sample count 6288/5 is not an integer. Will be rounded (this changes the sample rate).\n", + " times, voltages, measurements = render(program,\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAksAAAGwCAYAAAC5ACFFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAACRS0lEQVR4nO3dd3xT9foH8E/SvQfdrFJWQcqGslSEXuYVuS70hyKIoCh6Ab0iXkFFBcGN1yuK4roO3FsEKkORDWXIXmV1UEo3XUl+fyTn5KTNOElOVvt5v159cZqcnHMS2ubJ9/t8n0el0+l0ICIiIiKz1J6+ACIiIiJvxmCJiIiIyAoGS0RERERWMFgiIiIisoLBEhEREZEVDJaIiIiIrGCwRERERGSFv6cvoCnQarW4cOECIiIioFKpPH05REREJINOp0N5eTlSUlKgVlseP2KwpIALFy6gdevWnr4MIiIicsDZs2fRqlUri/czWFJAREQEAP2LHRkZ6eGrISIiIjnKysrQunVr8X3cEgZLChCm3iIjIxksERER+RhbKTRM8CYiIiKygsESERERkRUMloiIiIisYM4SERG5lUajQV1dnacvg5qBgIAA+Pn5OX0cBktEROQWOp0O+fn5KCkp8fSlUDMSHR2NpKQkp+ogMlgiIiK3EAKlhIQEhIaGsogvuZROp0NVVRUKCwsBAMnJyQ4fi8ESERG5nEajEQOlFi1aePpyqJkICQkBABQWFiIhIcHhKTkmeBMRkcsJOUqhoaEevhJqboSfOWfy5BgsERGR23DqjdxNiZ85BktEREREVjBYIiIiIrKCwRIREZGDTp8+DZVKhZycHE9fiixDhw7FrFmz7HrMU089hZ49e9r1mMOHD2PAgAEIDg62+7HWOHL9SmCwRERERIp68sknERYWhiNHjiA7O9tl50lNTcWrr77qsuMLWDqAiIiIFHXixAmMHTsWbdu29fSlKIIjS0RE5BE6nQ5VtfUe+dLpdLKvU6vVYunSpejQoQOCgoLQpk0bPPfccyb7nDx5Etdddx1CQ0PRo0cPbNmyRbzv0qVLuP3229GyZUuEhoYiIyMDn376qcnjhw4dioceegiPPvooYmNjkZSUhKeeespkH5VKhXfeeQf/+Mc/EBoaio4dO+L777832efAgQMYPXo0wsPDkZiYiDvvvBNFRUWynysAPP/880hMTERERASmTp2K6urqRvu888476NKlC4KDg5Geno7//ve/Jte5a9cuLFy4ECqVSnwec+fORadOnRAaGoq0tDTMnz/fZDn/5MmTMX78eJPzzJo1C0OHDjV7nUOHDkVubi5mz54NlUrl0pWWHFkiIiKPuFKnQdcFv3rk3AcXjkRooLy3wHnz5mHFihV45ZVXMGTIEOTl5eHw4cMm+/z73//Giy++iI4dO+Lf//43br/9dhw/fhz+/v6orq5Gnz59MHfuXERGRuKnn37CnXfeifbt26N///7iMT744APMmTMH27Ztw5YtWzB58mQMHjwYf/vb38R9nn76aSxduhQvvPACXn/9dUycOBG5ubmIjY1FSUkJhg0bhnvuuQevvPIKrly5grlz5+LWW2/Fb7/9Juu5fv7553jqqafwxhtvYMiQIfjoo4+wbNkypKWlift8/PHHWLBgAf7zn/+gV69e2LNnD6ZNm4awsDDcddddyMvLQ1ZWFkaNGoVHHnkE4eHhAICIiAi8//77SElJwf79+zFt2jRERETg0UcflXVtDX399dfo0aMHpk+fjmnTpjl0DLl8amRp06ZNuP7665GSkgKVSoVvv/3W5mM2bNiA3r17IygoCB06dMD777/faJ833ngDqampCA4ORmZmJrZv3678xRMRkc8pLy/Ha6+9hqVLl+Kuu+5C+/btMWTIENxzzz0m+z3yyCMYO3YsOnXqhKeffhq5ubk4fvw4AKBly5Z45JFH0LNnT6SlpeHBBx/EqFGj8Pnnn5sco3v37njyySfRsWNHTJo0CX379m2U7zN58mTcfvvt6NChAxYtWoSKigrxPUsIXhYtWoT09HT06tULK1euxPr163H06FFZz/fVV1/F1KlTMXXqVHTu3BnPPvssunbtarLPk08+iZdeegk33ngj2rVrhxtvvBGzZ8/GW2+9BQBISkqCv78/wsPDkZSUJAZLTzzxBAYNGoTU1FRcf/31eOSRRxq9BvaIjY2Fn58fIiIikJSUhKSkJIePZYtPjSxVVlaiR48euPvuu3HjjTfa3P/UqVMYO3Ys7rvvPnz88cfIzs7GPffcg+TkZIwcORIAsGrVKsyZMwfLly9HZmYmXn31VYwcORJHjhxBQkKCq58SEVGzFRLgh4MLR3rs3HIcOnQINTU1GD58uNX9unfvLm4LPcgKCwuRnp4OjUaDRYsW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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "param_template = FunctionPT('exp(-t/tau)*sin(phi*t)', 'duration')\n", + "\n", + "_ = plot(param_template, {'tau': 4, 'phi': 8, 'duration': 4*3.1415}, sample_rate=100)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/doc/source/examples/00MappingTemplate.ipynb b/doc/source/examples/00MappingTemplate.ipynb new file mode 100644 index 000000000..b9fb1f9d1 --- /dev/null +++ b/doc/source/examples/00MappingTemplate.ipynb @@ -0,0 +1,284 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mapping with the MappingPulseTemplate\n", + "\n", + "We will now have a look on how to remap parameters, channel ids and measurements. The definition of measurements is illustrated in [Definition of Measurements](01Measurements.ipynb). The `MappingPulseTemplate` class allows us to take any already existing `PulseTemplate` and specify a mapping for its parameters, channel ids and measurements.\n", + "\n", + "This can be useful for simply renaming things, e.g., to avoid name collisions of parameters or change the name of a channel a pulse should be executed on, but can also be employed to derive the value of certain parameters from other parameters.\n", + "\n", + "## Mapping Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2*pi/omega\n", + "{'omega', 'a'}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import MappingPT, FunctionPT, AtomicMultiChannelPT\n", + "\n", + "sine = FunctionPT('a*sin(omega*t)', 't_duration')\n", + "\n", + "my_parameter_mapping = dict(t_duration='2*pi/omega', omega='omega', a='a')\n", + "\n", + "single_period_sine = MappingPT(sine, parameter_mapping=my_parameter_mapping)\n", + "\n", + "print(single_period_sine.duration)\n", + "print(single_period_sine.parameter_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that we had to give mappings for all parameters, not only for the ones which changed. If we omit some of the encapsulated pulse tempaltes parameters an `MissingMappingException` is raised. This is done to enforce active thinking.\n", + "\n", + "You can, however, allow partial parameter mappings by passing `allow_partial_paramter_mappings=True` to the constructor." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "we expect an exception here:\n", + "\n", + "no exception with allow_partial_parameter_mapping=True\n", + "2*pi/omega\n", + "{'omega', 'a'}\n" + ] + } + ], + "source": [ + "partial_parameter_mapping = dict(t_duration='2*pi/omega')\n", + "print('we expect an exception here:')\n", + "try:\n", + " single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping)\n", + "except Exception as exception:\n", + " print(type(exception).__name__, ':', exception)\n", + "print('')\n", + "\n", + "print('no exception with allow_partial_parameter_mapping=True')\n", + "single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping, allow_partial_parameter_mapping=True)\n", + "print(single_period_sine.duration)\n", + "print(single_period_sine.parameter_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mapping of Channel Ids and Measurement Names\n", + "\n", + "Sometimes it is necessary to rename channels or measurements. Here we see a case where we want to play a sine and a cosine in parallel by using the `AtomicMultiChannelPulseTemplate` (for a more in depth explanation of multi-channel pulse template, see [Multi-Channel Pulses](00MultiChannelTemplates.ipynb)). Of course, this doesn't work as both pulses are by default defined on the 'default' channel." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ChannelMappingException : Channel is defined in subtemplate 1 and subtemplate 2\n" + ] + } + ], + "source": [ + "sine_measurements = [('M', 't_duration/2', 't_duration')]\n", + "sine = FunctionPT('a*sin(omega*t)', 't_duration', measurements=sine_measurements)\n", + "\n", + "cos_measurements = [('M', 0, 't_duration/2')]\n", + "cos = FunctionPT('a*cos(omega*t)', 't_duration', measurements=cos_measurements)\n", + "\n", + "try:\n", + " both = AtomicMultiChannelPT(sine, cos)\n", + "except Exception as exception:\n", + " print(type(exception).__name__, ':', exception)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The solution is to use the `MappingPT` and rename the channels as we see in the next cell. Additionally, we want to distinguish between the measurements, so we rename them, too. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "remapped_cos channels: {'cos_channel'}\n", + "remapped_cos measurements: {'M_cos'}\n", + "\n", + "remapped_sine channels: {'sin_channel'}\n", + "remapped_sine measurements: {'M_sin'}\n", + "\n", + "{'cos_channel', 'sin_channel'}\n", + "{'M_sin', 'M_cos'}\n" + ] + } + ], + "source": [ + "cos_channel_mapping = dict(default='cos_channel')\n", + "cos_measurement_mapping = dict(M='M_cos')\n", + "remapped_cos = MappingPT(cos, channel_mapping=cos_channel_mapping, measurement_mapping=cos_measurement_mapping)\n", + "print('remapped_cos channels:', remapped_cos.defined_channels)\n", + "print('remapped_cos measurements:', remapped_cos.measurement_names)\n", + "print()\n", + "\n", + "sine_channel_mapping = dict(default='sin_channel')\n", + "sine_measurement_mapping = dict(M='M_sin')\n", + "remapped_sine = MappingPT(sine, measurement_mapping=sine_measurement_mapping, channel_mapping=sine_channel_mapping)\n", + "print('remapped_sine channels:', remapped_sine.defined_channels)\n", + "print('remapped_sine measurements:', remapped_sine.measurement_names)\n", + "print()\n", + "\n", + "both = AtomicMultiChannelPT(remapped_sine, remapped_cos)\n", + "print(both.defined_channels)\n", + "print(both.measurement_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also plot it to see if it looks like expected with some dummy values for our parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Simon\\Documents\\git\\qupulse\\qupulse\\plotting.py:186: UserWarning: Sample count 6293/10 is not an integer. Will be rounded (this changes the sample rate).\n", + " times, voltages, measurements = render(program,\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses.plotting import plot\n", + "\n", + "parameter_values = dict(omega=1.0, a=1.0, t_duration=2*3.1415)\n", + "\n", + "_ = plot(both, parameters=parameter_values, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Automatically created mapping templates\n", + "\n", + "Besides the explicit usage of the template it is also used implicitly in some cases. All implicit uses make use of the static member function `MappingPulseTemplate.from_tuple`. This 'constructor' automatically decides which mapping belongs to which entity." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "channels: {'default'}\n", + "measurements {'M_sin'}\n", + "parameters {'omega', 't_duration', 'a'}\n", + "\n", + "channels: {'default'}\n", + "measurements {'M_sin'}\n", + "parameters {'omega', 'a'}\n", + "\n" + ] + } + ], + "source": [ + "auto_mapped = MappingPT.from_tuple((sine, sine_measurement_mapping))\n", + "print('channels:', auto_mapped.defined_channels)\n", + "print('measurements', auto_mapped.measurement_names)\n", + "print('parameters', auto_mapped.parameter_names)\n", + "print()\n", + "\n", + "auto_mapped = MappingPT.from_tuple((sine, sine_measurement_mapping, partial_parameter_mapping))\n", + "print('channels:', auto_mapped.defined_channels)\n", + "print('measurements', auto_mapped.measurement_names)\n", + "print('parameters', auto_mapped.parameter_names)\n", + "print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In many cases, you do not need to create the MappingPT yourself. Most PulseParameters accept a mapping tuple like the ones used in the last cell. We could create our combined pulse also by using this implicit conversion:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'cos_channel', 'sin_channel'}\n", + "{'M_sin', 'M_cos'}\n" + ] + } + ], + "source": [ + "both_implicit = AtomicMultiChannelPT((sine, sine_channel_mapping, sine_measurement_mapping), \n", + " (cos, cos_measurement_mapping, cos_channel_mapping))\n", + "print(both_implicit.defined_channels)\n", + "print(both_implicit.measurement_names)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/00MultiChannelTemplates.ipynb b/doc/source/examples/00MultiChannelTemplates.ipynb new file mode 100644 index 000000000..0084aea70 --- /dev/null +++ b/doc/source/examples/00MultiChannelTemplates.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-Channel Pulses\n", + "\n", + "Usually there is a need to define pulses for multiple control channels simulateously. While this would be possible by simply defining several separate pulse templates (one for each channel), qupulse also allows to define pulse templates directly for multiple channels or combine existing templates in a multi-channel way. This tutorial explores these possibilities.\n", + "\n", + "## A Multi-Channel Table Pulse\n", + "`TablePulseTemplate` allows to model multiple channels in a straighforward way: In its constructor entries are given as time-voltage sequences in a dictionary where each key specifies a channel id (which can be an identifier string or a number). In the first few examples we have mostly ignored this but here we are making use of it.\n", + "\n", + "The following example constructs a 2-channel table pulse template with shared parameters and plots it." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number of channels in table_template is 2.\n" + ] + }, + { + "data": { + "image/png": "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9EKkq66IjFLaJc/ZfeXG8uXLBT8/P0EulwvFixcXAgMDhf3796uXly9fXmjTpk2W+w4MDFS/fvPmjTBs2DChdOnSgqWlpVC/fn3h5MmTWuulXb68adMmje3FxcUJAIQVK1Zo7MPHx0dr3yEhIUL58uU1+lJTU4Vp06YJPj4+6vfi7+8vTJgwQUhISNB4P7m5pFsQBGHSpElCmTJlBBMTE43Lu3fs2CFUr15dsLCwENzd3YVp06YJy5cv17oEPO3Y7d27V6hevbogl8sFLy8vrfee+ZLuNBcuXBDat28vlChRQpDL5UL58uWFTp06CeHh4e+t/d27d8KAAQOEUqVKCTKZTOv3YfHixYK/v79gaWkp2NraCr6+vsKIESOEe/fuadWfGQChX79+Gn1pP78ZM2ao+0JCQgRra2shNjZWaNGihWBlZSU4OzsLoaGhWpf/I9Ml3c+fPxd69uwplCxZUrCxsRGCgoKEa9euZfnzW7JkieDh4SGYmppqHceIiAghKChIsLe3FywsLISKFSsKPXr0EM6ePfveY0hUUDJB0NEsMyIiElWPHj2wefPmLE+hERUFnFNDREREksBQQ0RERJLAUENERESSwDk1REREJAkcqSEiIiJJYKghIiIiSShSN99TKpW4d+8ebG1t83RrdyIiIhKPIAh4+fIlXF1dYWKS/XhMkQo19+7dy/ZBe0RERFS43blzB2XLls12eZEKNba2tgBUB8XOzk7kaoiIiCg3EhMT4ebmpv4cz06RCjVpp5zs7OwYaoiIiIzM+6aOcKIwERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJAkMNERERSQJDDREREUkCQw0RERFJgtGGmqlTp0Imk2Hw4MFil0JERESFgFGGmsjISCxatAjVq1cXuxQiIiIqJIqJXUBeJSUl4YsvvsCSJUvw008/iV2OUXv8MgUp7xRil0FERsbFzgLFTI3y/4lJ4owu1PTr1w9t2rRBs2bN3htqUlJSkJKSon6dmJio7/KMxqoTtxC64x+xyyAiI1SjrD3+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import TablePT\n", + "from qupulse.plotting import plot\n", + "\n", + "table_template = TablePT(identifier='2-channel-table-template',\n", + " entries={'first_channel' : [(0, 0),\n", + " (1, 4),\n", + " ('foo', 'bar'),\n", + " (10, 0)],\n", + " 'second_channel': [(0, 0),\n", + " ('foo', 2.7, 'linear'),\n", + " (9, 'bar', 'linear')]}\n", + " )\n", + "\n", + "parameters = dict(\n", + " foo=7,\n", + " bar=-1.3\n", + ")\n", + "_ = plot(table_template, parameters, sample_rate=100)\n", + "print(\"The number of channels in table_template is {}.\".format(table_template.num_channels))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Combining Templates: `AtomicMultiChannelPulseTemplate`\n", + "\n", + "`AtomicMultiChannelPulseTemplate`(`AtomicMultiChannelPT`) allows to compose a multi-channel template out of atomic (i.e., no control flow) templates of equal duration. It allows to reassign channel indices of the channels of its subtemplates. The constructor is similar to the one of `SequencePulseTemplate` and expects subtemplates (including parameter and channel mappings if required).\n", + "\n", + "The following example will combine the two-channel table pulse template `table_template` from above and a function pulse template `function_template` to a three-channel template `template`. We reassign indices such that channel 'rectangle' of the new `template` is channel 'first_channel' and 'triangle' is channel 'second_channel' of `table_template`. Furthermore the parameters get remapped. `function_template` doesn't get changed at all." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number of channels in function_template is 1.\n", + "The number of channels in template is 3.\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import FunctionPT, AtomicMultiChannelPT\n", + "\n", + "function_template = FunctionPT('-sin(t)**2', '10', identifier='function-template', channel='wavy')\n", + "\n", + "template = AtomicMultiChannelPT(\n", + " function_template,\n", + " (table_template, dict(foo='5', bar='2 * hugo'), {'first_channel': 'rectangle ', 'second_channel': 'triangle'}),\n", + " identifier='3-channel-combined-template'\n", + ")\n", + "\n", + "_ = plot(template, dict(hugo=-1.3), sample_rate=100)\n", + "print(\"The number of channels in function_template is {}.\".format(function_template.num_channels))\n", + "print(\"The number of channels in template is {}.\".format(template.num_channels))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The constructor of `AtomicMultiChannelPulseTemplate` expects its subtemplates as positional arguments. Each of positional arguments is required to be either a `AtomicPulseTemplate`, a `MappingPulseTemplate` that wraps an `AtomicPulseTemplate` or a tuple that can be passed to `MappingPulseTemplate.from_tuple`(more examples in [Mapping with the MappingPulseTemplate](00MappingTemplate.ipynb)). The sets of channels on which the subtemplates are defined has to be distinct.\n", + "Note that an exception will be raised during the sampling of the waveforms (i.e., during the sequencing process) if the subtemplates have different length." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantionation duration check\n", + "By default the AtomicMultiChannelPulseTemplate checks whether the durations are equal on construction. It is possible to do this check during instantiation (when create_program is called) by providing the `duration` keyword argument. This can either be an expression or `True`. If it is an expression all subwaveforms have to have a duration equal to it. If it is `True` all waveforms have to have an unspecified equal duration." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Instantionation duration check with specified value\n", + "The duration does not equal the expected duration 4\n" + ] + } + ], + "source": [ + "from qupulse.pulses import FunctionPT, AtomicMultiChannelPT\n", + "\n", + "template_a = FunctionPT('-sin(t)**2', 'duration_a', channel='a')\n", + "template_b = FunctionPT('-cos(t)**2', 'duration_b', channel='b')\n", + "\n", + "try:\n", + " # instantiation duration check\n", + " template = AtomicMultiChannelPT(\n", + " template_a,\n", + " template_b,\n", + " identifier='3-channel-combined-template'\n", + " )\n", + "except ValueError as err:\n", + " print('Instantiation duration check:')\n", + " print(err)\n", + "\n", + "# instantiation duration check with specified value\n", + "template_specified = AtomicMultiChannelPT(\n", + " template_a,\n", + " template_b,\n", + " duration='my_duration'\n", + ")\n", + "template_specified.create_program(parameters=dict(duration_a=3, duration_b=3, my_duration=3))\n", + "try:\n", + " template_specified.create_program(parameters=dict(duration_a=3, duration_b=3, my_duration=4))\n", + "except ValueError as err:\n", + " print()\n", + " print('Instantionation duration check with specified value')\n", + " print(err.args[0], err.args[1])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multiple Channels in Non-Atomic Templates\n", + "\n", + "All higher order template, i.e., `SequencePulseTemplate` and `ForLoopPulseTemplate` and `RepetitionPulseTemplate`, also support multiple channels insofar as that they can be composed using multi-channel atomic templates as subtemplates. They require that all these subtemplates define the same channels and raise an exception if that is not the case. The following example constructs a `SequencePulseTempate` `sequence_template` by chaining the above defined two-channel `table_template`. In the second instance of `table_template` in the sequence, we swap the channels by wrapping a `MappingPulseTemplate` around it." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number of channels in sequence_template is 2.\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import SequencePT\n", + "\n", + "sequence_template = SequencePT(\n", + " (table_template, dict(foo='1.2 * hugo', bar='hugo ** 2')),\n", + " (table_template, dict(foo='1.2 * hugo', bar='hugo ** 2'), {'first_channel': 'second_channel', \n", + " 'second_channel': 'first_channel'}),\n", + " identifier='2-channel-sequence-template'\n", + ")\n", + "\n", + "plot(sequence_template, dict(hugo=2), sample_rate=100)\n", + "print(\"The number of channels in sequence_template is {}.\".format(sequence_template.num_channels))" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/doc/source/examples/00PointPulse.ipynb b/doc/source/examples/00PointPulse.ipynb new file mode 100644 index 000000000..e99cbc0a9 --- /dev/null +++ b/doc/source/examples/00PointPulse.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The PointPulseTemplate\n", + "\n", + "The `PointPulseTemplate`(or short `PointPT`) can be understood as a specialization of the `TablePulseTemplate`. It restricts the channels to all having the same time points in their entries and the same expression for their voltages.\n", + "\n", + "Let us first have a look at an simple example: " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'A', 'B'}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import PointPT\n", + "\n", + "point_template = PointPT([(0, 'v_0'),\n", + " (1, 'v_1', 'linear'),\n", + " ('t', 'v_0+v_1', 'jump')],\n", + " channel_names=('A', 'B'))\n", + "\n", + "print(point_template.defined_channels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see the pulse template has two channels although we only provided one expression for the voltage per time point. The value of this expression can either be scalar as we will see now for `v_0` or be a `numpy` array of the same length as the number of channels is like `v_1`. A value of the wrong length will result in an exception." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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qMuODQAAvFtdTxcQEBCguLg4SVKXLl20ZcsWzZ07V/PmzbusbXR0tI4fP2637fjx44qOjq7w+IGBgQoMDHRt0QAAwCd4vEeorJKSElmt1nJfS0pKUnp6ut22VatWVTimCAAAoDIe7RFKTU1V37591axZM507d07vvvuu1qxZo5UrV0qShg4dqqZNmyotLU2S9Nhjj6lbt26aPXu2+vfvr/fee09bt27V/PnzPXkaAADAS3k0CJ04cUJDhw5Vdna2wsPD1bFjR61cuVK33367JCkrK0t+fr92WiUnJ+vdd9/V5MmTNWnSJMXHx2v58uW69tprPXUKAADAi9W6+wjVNO4jBJ/HfYQA+CCfv48QAACAuxGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAaRGEAACAadV1dger1arNmzfryJEjKiwsVOPGjZWYmKiWLVvWRH0AAAA1xuEgtGHDBs2dO1f//Oc/deHCBYWHhys4OFinT5+W1WpVq1at9NBDD2n06NGqX79+TdYMAADgEg59NXbHHXdo8ODBatGihb788kudO3dOp06d0g8//KDCwkL95z//0eTJk5Wenq42bdpo1apVNV03AABAtTnUI9S/f38tXbpU/v7+5b7eqlUrtWrVSsOGDdPevXuVnZ3t0iIBAABqgkNBaNSoUQ4fsF27dmrXrl2VCwIAAHAXZo0BAADTclkQGjZsmHr06OGqwwEAANQ4p6fPV6Rp06by86ODCQAAeA+XBaHp06e76lAAAABuQRcOAAAwLad7hO6///5KX1+0aJHDx0pLS9NHH32k7777TsHBwUpOTtaMGTOUkJBQ4T6LFy/WiBEj7LYFBgbq559/dvh9AQAApCoEoTNnztg9v3Dhgnbv3q2zZ886PVh67dq1Gjt2rK6//nr98ssvmjRpknr1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Vfv379dvf/tbp948LS1N119/verXr6/IyEgNHDhQ+/fvv+J+H3zwgdq2baugoCB16NBBn332mVPvC1Rb2anyLKgKAF7J6X+5Dx06pEaNGrnkzdeuXauxY8dq06ZNWrVqlS5cuKBevXqpoKCgwn2++eYbpaSk6IEHHtCOHTs0cOBADRw4ULt373ZJTcAVMVUeAHyGxTAM40qNXnzxRYcP+Oijj1a5mJ9++kmRkZFau3atbrnllnLbDB48WAUFBfr0009t22688UZdd911Dk3lz8vLU3h4uHJzcxUWFlblWmFS5U2VTz0mBYZ6rqYyCot+UbspKyVJe6f1VkiA03MiAKDWqanPb4f+hZwzZ45DB7NYLNUKQrm5uZKkiIiICtts3LhR48ePt9vWu3dvLV++vNz2VqtVVqvV9jwvL6/K9QFMlQcA3+JQEDp06FBN16GSkhKNGzdON910k6699toK2+Xk5CgqKspuW1RUlHJycsptn5aWpqlTp7q0VphU2XFBTJUHAK9XrdGdhmHIgW/WHDJ27Fjt3r1b7733nkuOVyo1NVW5ubm2x9GjR116fJhI2QVVCUEA4PWqFITefPNNdejQQcHBwQoODlbHjh311ltvVbmIhx9+WJ9++qlWr16tq6++utK20dHROn78uN2248ePKzo6utz2gYGBCgsLs3sATmNBVQDwSU4HoRdeeEFjxoxRv379tGTJEi1ZskR9+vTR6NGjHR5LVMowDD388MNatmyZvv76a7Vs2fKK+yQlJSk9Pd1u26pVq5SUlOTUewNOKdsbxLggAPAJTk8neemll/Tqq69q6NChtm133HGH2rdvr7/85S96/PHHHT7W2LFj9e677+rjjz9W/fr1beN8wsPDFRwcLEkaOnSomjZtqrS0NEnSY489pm7dumn27Nnq37+/3nvvPW3dulXz58939lSAKzOMiyHo0mU06A0CAJ/hdI9Qdna2kpOTL9uenJys7Oxsp4716quvKjc3V927d1dMTIzt8f7779vaZGVl2R03OTlZ7777rubPn69OnTrpww8/1PLlyysdYA1USelU+bSm9sto0BsEAD7D6R6huLg4LVmyRJMmTbLb/v777ys+Pt6pYzky0HrNmjWXbbv77rt19913O/VegNPKTpWP7sAyGgDgY5wOQlOnTtXgwYO1bt063XTTTZKkDRs2KD09XUuW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1q2NoKAgIyIiwujevbvx9ddfe6b4KirvfCXZXT9f/P2uynn7wu/3/fffbzRv3twICAgwGjdubNx22222MGAYvnmtDcP583bltbYYhmE4348EAADg/bx2jBAAAEB1EYQAAIBpEYQAAIBpEYQAAIBpEYQAAIBpEYQAAIBpEYQAAIBpEYQAAIBpEYQAuN3w4cM1cOBAj73/kCFDNH36dJccq6ioSC1atNDWrVtdcjwA7sWdpQG4lMViqfT1Z555Ro8//rgMw1CDBg3cU9Ql/v3vf6tHjx46cuSIQkNDXXLMl19+WcuWLbts8UsAtR9BCIBL5eTk2H5+//33NWXKFO3fv9+2LTQ01GUBpCpGjhypunXr6rXXXnPZMc+cOaPo6Ght375d7du3d9lxAdQ8vhoD4FLR0dG2R3h4uCwWi9220NDQy74a6969ux555BGNGzdODRs2VFRUlP7+97+roKBAI0aMUP369RUXF6fPP//c7r12796tvn37KjQ0VFFRURoyZIhOnjxZYW3FxcX68MMPNWDAALvtLVq00PTp03X//ferfv36atasmebPn297vaioSA8//LBiYmIUFBSk5s2bKy0tzfZ6w4YNddNNN+m9996r5p8eAHcjCAGoFd544w01atRI3377rR555BGNGTNGd999t5KTk7V9+3b16tVLQ4YMUWFhoSTp7Nmz6tGjhxITE7V161Z98cUXOn78uAYNGlThe+zcuVO5ubnq2rXrZa/Nnj1bXbt21Y4dO/THP/5RY8aMsfVkvfjii/rkk0+0ZMkS7d+/X++8845atGhht/8NN9ygf/3rX677AwHgFgQhALVCp06dNHnyZMXHxys1NVVBQUFq1KiRHnzwQcXHx2vKlCk6deqUdu7cKeniuJzExERNnz5dbdu2VWJiohYtWqTVq1frwIED5b7HkSNHVKdOHUVGRl72Wr9+/fTHP/5RcXFxmjhxoho1aqTVq1dLkrKyshQfH6+bb75ZzZs3180336yUlBS7/Zs0aaIjR464+E8FQE0jCAGoFTp27Gj7uU6dOrrqqqvUoUMH27aoqChJ0okTJyRdHPS8evVq25ij0NBQtW3bVpKUmZlZ7nucP39egYGB5Q7ovvT9S7/OK32v4cOHKyMjQwkJCXr00Uf15ZdfXrZ/cHCwrbcKgPeo6+kCAECS/P397Z5bLBa7baXhpaSkRJKUn5+vAQMGaMaMGZcdKyYmptz3aNSokQoLC1VUVKSAgIArvn/pe3Xu3FmHDh3S559/rq+++kqDBg1Sz5499eGHH9ranz59Wo0bN3b0dAHUEgQhAF6pc+fOWrp0qVq0aKG6dR37p+y6666TJO3du9f2s6PCwsI0ePBgDR48WH/4wx/Up08fnT59WhEREZIuDtxOTEx06pgAPI+vxgB4pbFjx+r06dNKSUnRli1blJmZqZUrV2rEiBEqLi4ud5/GjRurc+fOWr9+vVPv9cILL+gf//iHvvvuOx04cEAffPCBoqOj7e6D9K9//Uu9evWqzikB8ACCEACv1KRJE23YsEHFxcXq1auXOnTooHHjxqlBgwby86v4n7aRI0fqnXfeceq96tevr5kzZ6pr1666/vrrdfjwYX322We299m4caNyc3P1hz/8oVrnBMD9uKEiAFM5f/68EhIS9P777yspKcklxxw8eLA6deqkSZMmueR4ANyHHiEAphIcHKw333yz0hsvOqOoqEgdOnTQ448/7pLjAXAveoQAAIBp0SMEAABMiyAEAABMiyAEAABMiyAEAABMiyAEAABMiyAEAABMiyAEAABMiyAEAABMiyAEAABM6/8AlmJrNdWIpWQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses.plotting import plot\n", + "import numpy as np\n", + "\n", + "parameters = dict(t=3,\n", + " v_0=1,\n", + " v_1=np.array([1.2, 2.5]))\n", + "\n", + "_ = plot(point_template, parameters, sample_rate=100)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/00RetrospectiveConstantChannelAddition.ipynb b/doc/source/examples/00RetrospectiveConstantChannelAddition.ipynb new file mode 100644 index 000000000..0f934c535 --- /dev/null +++ b/doc/source/examples/00RetrospectiveConstantChannelAddition.ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ParallelConstantChannelPulseTemplate\n", + "One reoccuring problem is to add a constant channel to an already existing possibly complex pulse. The setting in this example requires us to put a trigger pulse before the example pulse written in [03FreeInductionDecayExample](03FreeInductionDecayExample.ipynb). Unfortunately, the trigger pulse has to be played on a seperate marker channel that is not included in the example pulse. Therefore, we will add this channel to the pulse with the constant value 0.\n", + "\n", + "Let us start with loading the experiment and defining the trigger pulse" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Defined channels of loaded pulse: {'RFY', 'RFX'}\n", + "Defined channels of trigger pulse: {'RFY', 'RFX', 'Marker'}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import TablePT\n", + "from qupulse.serialization import FilesystemBackend, PulseStorage\n", + "\n", + "pulse_storage = PulseStorage(FilesystemBackend('./serialized_pulses'))\n", + "free_induction_decay = pulse_storage['free_induction_decay']\n", + "print('Defined channels of loaded pulse:', free_induction_decay.defined_channels)\n", + "\n", + "trig_pulse = TablePT({'RFX': [(0, 0), ('t_trig', 0)],\n", + " 'RFY': [(0, 0), ('t_trig', 0)],\n", + " 'Marker': [(0, 1), ('t_trig', 1)]})\n", + "print('Defined channels of trigger pulse:', trig_pulse.defined_channels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we now try to concatenate the pulses we get an error as they differ in their defined channels." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ValueError(\"The subtemplates are defined for different channels: defined {'RFY', 'RFX', 'Marker'} vs. subtemplate {'RFY', 'RFX'}\")\n" + ] + } + ], + "source": [ + "try:\n", + " experiment = trig_pulse @ free_induction_decay\n", + "except ValueError as err:\n", + " print(repr(err))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now add an extra channel with a constant value to the `free_induction_decay` pulse. This allows us to concatenate the pulses." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.pulses.multi_channel_pulse_template import ParallelConstantChannelPulseTemplate\n", + "extended_free_induction_decay = ParallelConstantChannelPulseTemplate(free_induction_decay, {'Marker': 0})\n", + "\n", + "experiment = trig_pulse @ extended_free_induction_decay" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Read example parameters from file and plot complete pulse" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import json\n", + "from qupulse.pulses.plotting import plot\n", + "\n", + "with open('parameters/free_induction_decay.json', 'r') as parameter_file:\n", + " example_values = json.load(parameter_file)\n", + "\n", + "_ = plot(experiment, {**example_values, 't_trig': 100, 'N_fid_steps': 2})" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/00SimpleTablePulse.ipynb b/doc/source/examples/00SimpleTablePulse.ipynb index 8f603d42e..6c7c313c5 100644 --- a/doc/source/examples/00SimpleTablePulse.ipynb +++ b/doc/source/examples/00SimpleTablePulse.ipynb @@ -65,791 +65,9 @@ "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAGwCAYAAABVdURTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA5f0lEQVR4nO3de1xUdeL/8TcgVwW8clHxCok3EMULamlqmvm12G+Z63dLNG3T1Uqpr34xV6vdlcrMtFzNyrXLmlqmtVYqkpdUzCulmZlXvADeQVBBYX5/9HO2WcFmcOAMh9fz8ZjHg/nMOWfeMxW8O+czn3GzWCwWAQAAmIS70QEAAACciXIDAABMhXIDAABMhXIDAABMhXIDAABMhXIDAABMhXIDAABMpZrRASpacXGxTp06JX9/f7m5uRkdBwAA2MFisejSpUuqX7++3N1vfW6mypWbU6dOKSwszOgYAACgDI4fP66GDRvecpsqV278/f0l/fLmBAQEGJwGAADYIzc3V2FhYda/47dS5crNjUtRAQEBlBsAACoZe6aUMKEYAACYCuUGAACYCuUGAACYSpWbcwMAMJeioiJdu3bN6BhwAi8vr9/8mLc9KDcAgErJYrEoKytLFy9eNDoKnMTd3V1NmzaVl5fXbR2HcgMAqJRuFJugoCD5+fmxMGsld2OR3czMTDVq1Oi2/nlSbgAAlU5RUZG12NSpU8foOHCSevXq6dSpU7p+/bo8PT3LfBwmFAMAKp0bc2z8/PwMTgJnunE5qqio6LaOQ7kBAFRaXIoyF2f986TcAAAAU6HcAAAAU6HcAADgIo4ePSo3Nzelp6cbHcUuPXv21Lhx44yOcRPKDQAAKDfr169X+/bt5e3trfDwcC1cuLDcn5NyAwAAysWRI0c0YMAA3X333UpPT9e4ceM0cuRIrV69ulyfl3IDADAFi8Wiy4XXDblZLBa7cxYXF+uVV15ReHi4vL291ahRI/3tb3+z2ebw4cO6++675efnp+joaKWlpVkfO3funIYMGaIGDRrIz89Pbdu21UcffWSzf8+ePfXUU09pwoQJql27tkJCQvT888/bbOPm5qZ33nlHv/vd7+Tn56eIiAh9/vnnNtvs3btX/fv3V40aNRQcHKxHH31UZ8+etfu1zps3T02bNtWMGTPUsmVLjR07Vg899JBmzpxp9zHKgkX8AACmcOVakVpNKd8zAqXZ92I/+XnZ9yc1KSlJb7/9tmbOnKnu3bsrMzNT+/fvt9nmueee06uvvqqIiAg999xzGjJkiA4ePKhq1arp6tWr6tChgyZOnKiAgAB98cUXevTRR9W8eXN16tTJeoz33ntPiYmJ+vbbb5WWlqZhw4apW7duuueee6zbvPDCC3rllVc0ffp0vfHGG/rDH/6gY8eOqXbt2rp48aJ69eqlkSNHaubMmbpy5YomTpyohx9+WF9//bVdrzUtLU19+vSxGevXr1+5z9Oh3AAAUEEuXbqkWbNm6c0331RCQoIkqXnz5urevbvNds8++6wGDBgg6ZcC0rp1ax08eFCRkZFq0KCBnn32Weu2Tz75pFavXq2lS5falJuoqChNnTpVkhQREaE333xTqampNuVm2LBhGjJkiCRp2rRpmj17trZt26Z7771Xb775pmJiYjRt2jTr9gsWLFBYWJgOHDigO+644zdfb1ZWloKDg23GgoODlZubqytXrsjX19eu981RlBsAgCn4enpo34v9DHtue/z4448qKChQ7969b7ldVFSU9efQ0FBJ0unTpxUZGamioiJNmzZNS5cu1cmTJ1VYWKiCgoKbVmv+9TFuHOf06dOlblO9enUFBARYt/nuu++0bt061ahR46Z8hw4dsqvcGIVyAwAwBTc3N7svDRnF3jMVv/5epRur9hYXF0uSpk+frlmzZun1119X27ZtVb16dY0bN06FhYWlHuPGcW4cw55t8vLyNHDgQL388ss35btRuH5LSEiIsrOzbcays7MVEBBQbmdtJMoNAAAVJiIiQr6+vkpNTdXIkSPLdIzNmzfrgQce0COPPCLpl9Jz4MABtWrVyplR1b59ey1btkxNmjRRtWplqwtxcXH68ssvbcZSUlIUFxfnjIil4tNSAABUEB8fH02cOFETJkzQ+++/r0OHDmnr1q1699137T5GRESEUlJStGXLFv3444964oknbjo74gxjxozR+fPnNWTIEG3fvl2HDh3S6tWrNXz4cLu/2HLUqFE6fPiwJkyYoP379+vvf/+7li5dqvHjxzs9769x5gYAgAr05z//WdWqVdOUKVN06tQphYaGatSoUXbvP3nyZB0+fFj9+vWTn5+f/vjHPyo+Pl45OTlOzVm/fn1t3rxZEydOVN++fVVQUKDGjRvr3nvvlbu7fedGmjZtqi++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AwIAADjC4TM3sbGx1p+DgoK0atUqpwYCAAC4HSziBwAATMWucnPvvfdq69atv7ndpUuX9PLLL2vOnDm3HQwAAKAs7LosNWjQID344IMKDAzUwIEDFRsbq/r168vHx0cXLlzQvn37tGnTJn355ZcaMGCApk+fXt65AQAASmRXuRkxYoQeeeQRffzxx1qyZInmz5+vnJwcSZKbm5tatWqlfv36afv27WrZsmW5BgYAALgVuycUe3t765FHHtEjjzwiScrJydGVK1dUp04deXp6lltAAAAAR5TpizOlXxbtCwwMdGYWAACA28anpQAAgKlQbgAAgKlQbgAAgKkYWm42btyogQMHqn79+nJzc9OKFStuuf369evl5uZ20y0rK6tiAgMAAJdXpnJz8eJFvfPOO0pKStL58+clSbt27dLJkycdOk5+fr6io6MdXvTvp59+UmZmpvUWFBTk0P4AAMC8HP601Pfff68+ffooMDBQR48e1eOPP67atWvr008/VUZGht5//327j9W/f3/179/f0QgKCgpSzZo1Hd4PAACYn8NnbhITEzVs2DD9/PPP8vHxsY7fd9992rhxo1PDlaZdu3YKDQ3VPffco82bN99y24KCAuXm5trcAACAeTlcbrZv364nnnjipvEGDRqU+9yX0NBQzZs3T8uWLdOyZcsUFhamnj17ateuXaXuk5ycbF2TJzAwUGFhYeWaEQAAGMvhy1Le3t4lnv04cOCA6tWr55RQpWnRooVatGhhvd+1a1cdOnRIM2fO1AcffFDiPklJSUpMTLTez83NpeAAAGBiDp+5uf/++/Xiiy/q2rVrkn75bqmMjAxNnDhRDz74oNMD/pZOnTrp4MGDpT7u7e2tgIAAmxsAADAvh8vNjBkzlJeXp6CgIF25ckU9evRQeHi4/P399be//a08Mt5Senq6QkNDK/x5AQCAa3L4slRgYKBSUlK0adMmff/998rLy1P79u3Vp08fh588Ly/P5qzLkSNHlJ6ertq1a6tRo0ZKSkrSyZMnrZ/Aev3119W0aVO1bt1aV69e1TvvvKOvv/5aa9ascfi5AQCAOZX5izO7d++u7t2739aT79ixQ3fffbf1/o25MQkJCVq4cKEyMzOVkZFhfbywsFDPPPOMTp48KT8/P0VFRWnt2rU2xwAAAFWbw+Vm9uzZJY67ubnJx8dH4eHhuuuuu+Th4fGbx+rZs6csFkupjy9cuNDm/oQJEzRhwgSH8gIAgKrF4XIzc+ZMnTlzRpcvX1atWrUkSRcuXJCfn59q1Kih06dPq1mzZlq3bh2fSgIAABXO4QnF06ZNU8eOHfXzzz/r3LlzOnfunA4cOKDOnTtr1qxZysjIUEhIiMaPH18eeQEAAG7J4TM3kydP1rJly9S8eXPrWHh4uF599VU9+OCDOnz4sF555RVDPhYOAADg8JmbzMxMXb9+/abx69evW1corl+/vi5dunT76QAAABzkcLm5++679cQTT2j37t3Wsd27d2v06NHq1auXJGnPnj1q2rSp81ICAADYyeFy8+6776p27drq0KGDvL295e3trdjYWNWuXVvvvvuuJKlGjRqaMWOG08MCAAD8Fofn3ISEhCglJUX79+/XgQMHJN38nU+sOwMAAIxS5kX8IiMjFRkZ6cwsAAAAt61M5ebEiRP6/PPPlZGRocLCQpvHXnvtNacEAwAAKAuHy01qaqruv/9+NWvWTPv371ebNm109OhRWSwWtW/fvjwyAgAA2M3hCcVJSUl69tlntWfPHvn4+GjZsmU6fvy4evTooUGDBpVHRgAAALs5XG5+/PFHDR06VJJUrVo1XblyRTVq1NCLL76ol19+2ekBAQAAHOFwualevbp1nk1oaKgOHTpkfezs2bPOSwYAAFAGDs+56dKlizZt2qSWLVvqvvvu0zPPPKM9e/bo008/VZcuXcojIwAAgN0cLjevvfaa8vLyJEkvvPCC8vLytGTJEkVERPBJKQAAYDiHy02zZs2sP1evXl3z5s1zaiAAAIDb4fCcm2bNmuncuXM3jV+8eNGm+AAAABjB4XJz9OhRFRUV3TReUFCgkydPOiUUAABAWdl9Werzzz+3/rx69WoFBgZa7xcVFSk1NVVNmjRxajgAAABH2V1u4uPjJUlubm5KSEiweczT01NNmjThm8ABAIDh7C43xcXFkqSmTZtq+/btqlu3brmFAgAAKCuHPy115MiR8sgBAADgFHaVm9mzZ9t9wKeeeqrMYQAAAG6XXeVm5syZdh3Mzc2NcgMAAAxlV7nhUhQAAKgsHF7n5tcsFossFouzsgAAANy2MpWb999/X23btpWvr698fX0VFRWlDz74wNnZAAAAHFamL87885//rLFjx6pbt26SpE2bNmnUqFE6e/asxo8f7/SQAAAA9nK43LzxxhuaO3euhg4dah27//771bp1az3//POUGwAAYCiHL0tlZmaqa9euN4137dpVmZmZTgkFAABQVg6Xm/DwcC1duvSm8SVLligiIsIpoQAAAMrK4ctSL7zwggYPHqyNGzda59xs3rxZqampJZYeAACAimT3mZu9e/dKkh588EF9++23qlu3rlasWKEVK1aobt262rZtm373u9+VW1AAAAB72H3mJioqSh07dtTIkSP1+9//Xh9++GF55gIAACgTu8/cbNiwQa1bt9Yzzzyj0NBQDRs2TN988015ZgMAAHCY3eXmzjvv1IIFC5SZmak33nhDR44cUY8ePXTHHXfo5ZdfVlZWVnnmBAAAsIvDn5aqXr26hg8frg0bNujAgQMaNGiQ5syZo0aNGun+++8vj4wAAAB2u63vlgoPD9ekSZM0efJk+fv764svvnBWLgAAgDJx+KPgN2zcuFELFizQsmXL5O7urocfflgjRoxwZjYAAACHOVRuTp06pYULF2rhwoU6ePCgunbtqtmzZ+vhhx9W9erVyysjAACA3ey+LNW/f381btxYb7zxhn73u9/pxx9/1KZNmzR8+PAyF5uNGzdq4MCBql+/vtzc3LRixYrf3Gf9+vVq3769vL29FR4eroULF5bpuQEAgDnZXW48PT31ySef6MSJE3r55ZfVokWL237y/Px8RUdHa86cOXZtf+TIEQ0YMEB333230tPTNW7cOI0cOVKrV6++7SwAAMAc7L4s9fnnnzv9yfv376/+/fvbvf28efPUtGlTzZgxQ5LUsmVLbdq0STNnzlS/fv2cng8AAFQ+t/VpqYqWlpamPn362Iz169dPaWlppe5TUFCg3NxcmxsAADCvSlVusrKyFBwcbDMWHBys3NxcXblypcR9kpOTFRgYaL2FhYVVRFQAAGCQSlVuyiIpKUk5OTnW2/Hjx42OBAAAylGZ17kxQkhIiLKzs23GsrOzFRAQIF9f3xL38fb2lre3d0XEAwAALqBSnbmJi4tTamqqzVhKSori4uIMSgQAAFyNoeUmLy9P6enpSk9Pl/TLR73T09OVkZEh6ZdLSkOHDrVuP2rUKB0+fFgTJkzQ/v379fe//11Lly7V+PHjjYgPAABckKHlZseOHYqJiVFMTIwkKTExUTExMZoyZYokKTMz01p0JKlp06b64osvlJKS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2rXTqlWrrJOGMzIy5O7+7xNMXbt21aJFizR58mRNmjRJERERWrFihdq0aWPUSwAAAC7E8HVuKporrXMDAADs48jf78r3+S4AAIBboNwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTodwAAABTqWZ0gIpmsVgkSbm5uQYnAQAA9rrxd/vG3/FbqXLl5tKlS5KksLAwg5MAAABHXbp0SYGBgbfcxs1iTwUykeLiYp06dUr+/v5yc3MzOo5yc3MVFham48ePKyAgwOg4LoX3pmS8L6XjvSkd703peG9K50rvjcVi0aVLl1S/fn25u996Vk2VO3Pj7u6uhg0bGh3jJgEBAYb/i+OqeG9KxvtSOt6b0vHelI73pnSu8t781hmbG5hQDAAATIVyAwAATIVyYzBvb29NnTpV3t7eRkdxObw3JeN9KR3vTel4b0rHe1O6yvreVLkJxQAAwNw4cwMAAEyFcgMAAEyFcgMAAEyFcgMAAEyFcmOgOXPmqEmTJvLx8VHnzp21bds2oyO5hI0bN2rgwIGqX7++3NzctGLFCqMjuYTk5GR17NhR/v7+CgoKUnx8vH766SejY7mEuXPnKioqyrrQWFxcnL766iujY7mcl156SW5ubho3bpzRUVzC888/Lzc3N5tbZGSk0bFcwsmTJ/XII4+oTp068vX1Vdu2bbVjxw6jY9mNcmOQJUuWKDExUVOnTtWuXbsUHR2tfv366fTp00ZHM1x+fr6io6M1Z84co6O4lA0bNmjMmDHaunWrUlJSdO3aNfXt21f5+flGRzNcw4YN9dJLL2nnzp3asWOHevXqpQceeEA//PCD0dFcxvbt2/XWW28pKirK6CgupXXr1srMzLTeNm3aZHQkw124cEHdunWTp6envvrqK+3bt08zZsxQrVq1jI5mPwsM0alTJ8uYMWOs94uKiiz169e3JCcnG5jK9UiyLF++3OgYLun06dMWSZYNGzYYHcUl1apVy/LOO+8YHcMlXLp0yRIREWFJSUmx9OjRw/L0008bHcklTJ061RIdHW10DJczceJES/fu3Y2OcVs4c2OAwsJC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", "text/plain": [ - "" + "
" ] }, "metadata": {}, @@ -1741,791 +176,9 @@ "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib notebook\n", - "from qupulse.pulses.plotting import plot\n", - "from qupulse.pulses import TablePT\n", - "\n", - "param_entries = {'A': [(0, 0),\n", - " ('ta', 'va', 'hold'),\n", - " ('tb', 'vb', 'linear'),\n", - " ('tend', 0, 'jump')],\n", - " 'B': [(0, 0),\n", - " ('ta', '-va', 'hold'),\n", - " ('tb', '-vb', 'linear'),\n", - " ('tend', 0, 'jump')]}\n", - "mirror_pulse = TablePT(param_entries)\n", - "\n", - "parameters = {'ta': 2,\n", - " 'va': 2,\n", - " 'tb': 4,\n", - " 'vb': 3,\n", - " 'tend': 6}\n", - "\n", - "_ = plot(mirror_pulse, parameters, sample_rate=100)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You may have noticed that we already used an expression in the entry list: `'-va'` and `'-vb'`. Of course we can also do a bit more complex things with these than a simple negation. Let's have a look at the next example where we use some simple mathematical oeprators and built-in functions:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "param_entries = {'A': [(0, 0),\n", - " ('t_A/2', 'va', 'hold'),\n", - " ('t_A', 'vb', 'linear')],\n", - " 'B': [(0, 0),\n", - " ('t_B / 2', 'va', 'hold'),\n", - " ('t_B', 'vb', 'linear')]}\n", - "\n", - "c_pulse = TablePT(param_entries)\n", - "print(c_pulse.duration)\n", - "_ = plot(c_pulse, dict(t_A=4, t_B=5, va=1, vb=2, t_wait = 2), sample_rate=100)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you see channel `'A'` only was defined until 4ns and holds this level to the end of the pulse." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/doc/source/examples/08Measurements.ipynb b/doc/source/examples/01Measurements.ipynb similarity index 80% rename from doc/source/examples/08Measurements.ipynb rename to doc/source/examples/01Measurements.ipynb index 22bd3b1e3..2701692b3 100644 --- a/doc/source/examples/08Measurements.ipynb +++ b/doc/source/examples/01Measurements.ipynb @@ -21,7 +21,7 @@ "output_type": "stream", "text": [ "{'N', 'M'}\n", - "[('M', 0, 't_meas'), ('N', 0, 't_meas/2')]\n" + "[('M', ExpressionScalar(0), ExpressionScalar('t_meas')), ('N', ExpressionScalar(0), ExpressionScalar('t_meas/2'))]\n" ] } ], @@ -47,7 +47,7 @@ "Note that measurement definitions may not exceed the duration of the pulse they are defined in. Doing so will result in an exception being raised during pulse instantiation.\n", "Note further that measurements for pulse templates that are empty, e.g. because their length as given by parameters turns out equal to zero, will be discarded during instantiation (without raising an exception).\n", "\n", - "When using non-atomic/composite pulse templates such as for example `SequencePulseTemplate`, they will \"inherit\" all the measurements from the subtemplates they are created with (see [Combining PulseTemplates](03xComposedPulses.ipynb) to learn more about composite pulse templates). To avoid name conflicts of measurements from different subtemplates, we can make use of mapping (via [MappingPulseTemplate](05MappingTemplate.ipynb)) to rename the measurements, as the example below demonstrates." + "When using non-atomic/composite pulse templates such as for example `SequencePulseTemplate`, they will \"inherit\" all the measurements from the subtemplates they are created with (see [Combining PulseTemplates](00ComposedPulses.ipynb) to learn more about composite pulse templates). To avoid name conflicts of measurements from different subtemplates, we can make use of mapping (via [MappingPulseTemplate](00MappingTemplate.ipynb)) to rename the measurements, as the example below demonstrates." ] }, { @@ -59,7 +59,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'dbz_fid', 'N', 'charge_scan'}\n" + "{'N', 'dbz_fid', 'charge_scan'}\n" ] } ], @@ -73,22 +73,8 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" + "name": "python" } }, "nbformat": 4, diff --git a/doc/source/examples/01ParameterConstraints.ipynb b/doc/source/examples/01ParameterConstraints.ipynb new file mode 100644 index 000000000..ea35fc08b --- /dev/null +++ b/doc/source/examples/01ParameterConstraints.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Constraining Parameters\n", + "\n", + "Often, it is useful to constrain parameters. Either to be in a specific range or even that some relation between parameters is fulfilled. Many pulse templates allow that and accept `parameter_constraints` as a keyword argument. In this example we look at a simple table pulse that ramps a voltage from `v_a` to `v_b` with the ramp time `t_ramp`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import TablePT\n", + "from qupulse.plotting import plot\n", + "\n", + "table_pulse = TablePT({'A': [(0, 'v_a'),\n", + " ('t_ramp', 'v_b', 'linear')]})\n", + "_ = plot(table_pulse, dict(t_ramp=10, v_a=-1, v_b=1), sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we want to restrict the ramp rate of the pulse to some maximum ramp rate `max_rate` and the ramp time to be larger than 1:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'v_b', 'max_rate', 'v_a', 't_ramp'}\n", + "Abs(v_a - v_b)/t_ramp < max_rate\n", + "t_ramp > 1\n" + ] + } + ], + "source": [ + "table_pulse = TablePT({'A': [(0, 'v_a'),\n", + " ('t_ramp', 'v_b', 'linear')]},\n", + " parameter_constraints=['Abs(v_a-v_b)/t_ramp < max_rate', 't_ramp>1'])\n", + "print(table_pulse.parameter_names)\n", + "print(table_pulse.parameter_constraints[0])\n", + "print(table_pulse.parameter_constraints[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the pulse got the extra parameter `max_rate`. We cannot instantiate this pulse without providing this parameter." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ParameterNotProvidedException: No value was provided for parameter 'max_rate'.\n" + ] + } + ], + "source": [ + "try:\n", + " _ = plot(table_pulse, dict(t_ramp=10, v_a=-1, v_b=1), sample_rate=100)\n", + "except Exception as exception:\n", + " print('{}: {}'.format(type(exception).__name__, exception))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If one of the constraints is violated an exception is raised:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ParameterConstraintViolation: The constraint 'Abs(v_a - v_b)/t_ramp < max_rate' is not fulfilled.\n", + "Parameters: DictScope(values=frozendict.frozendict({'t_ramp': 10, 'v_a': -1, 'v_b': 1, 'max_rate': 0.1}))\n" + ] + } + ], + "source": [ + "try:\n", + " _ = plot(table_pulse, dict(t_ramp=10, v_a=-1, v_b=1, max_rate=0.1), sample_rate=100)\n", + "except Exception as exception:\n", + " print('{}: {}'.format(type(exception).__name__, exception))" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/01PulseStorage.ipynb b/doc/source/examples/01PulseStorage.ipynb new file mode 100644 index 000000000..b0889b321 --- /dev/null +++ b/doc/source/examples/01PulseStorage.ipynb @@ -0,0 +1,395 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Storing Pulse Templates: `PulseStorage` and Serialization\n", + "\n", + "So far, we have constructed new pulse templates in code for each session (which were discarded afterwards). We now want to store them persistently in the file system to be able to reuse them in later sessions. For this, qupulse offers us serialization and deserialization using the `PulseStorage` and `StorageBackend` classes.\n", + "\n", + "The pulse storage manages the (de-)serialization to JSON and requires a storage backend to persistently store the serialized data. This can for example be a `FilesystemBackend` or a `DictBackend`. Let us first use a `DictBackend` to inspect the serialized pulse.\n", + "\n", + "__Attention:__ Due to the fact that PulseStorage enforces unique identifiers, executing the cells in this notebook out of order or rerunning them will likely result in errors. You will have to restart the Kernel in that case.\n", + "\n", + "## Single Pulses\n", + "First we will have a look at how to store pulses that do not contain other pulse templates. To store a pulse, __the pulse needs to have an identifier__. If you forgot to give the pulse an identifier one can use the `rename` method which returns a new pulse with the requested identifier.\n", + "\n", + "### Storing" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'my_pulse': '{\\n'\n", + " ' \"#identifier\": \"my_pulse\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.table_pulse_template.TablePulseTemplate\",\\n'\n", + " ' \"entries\": {\\n'\n", + " ' \"default\": [\\n'\n", + " ' [\\n'\n", + " ' \"t_begin\",\\n'\n", + " ' \"v_begin\",\\n'\n", + " ' \"hold\"\\n'\n", + " ' ],\\n'\n", + " ' [\\n'\n", + " ' \"t_end\",\\n'\n", + " ' \"v_end\",\\n'\n", + " ' \"linear\"\\n'\n", + " ' ]\\n'\n", + " ' ]\\n'\n", + " ' },\\n'\n", + " ' \"measurements\": [],\\n'\n", + " ' \"parameter_constraints\": []\\n'\n", + " '}'}\n" + ] + } + ], + "source": [ + "import pprint\n", + "from qupulse.pulses import TablePT\n", + "from qupulse.serialization import PulseStorage, DictBackend\n", + "\n", + "dict_backend = DictBackend()\n", + "dict_pulse_storage = PulseStorage(dict_backend)\n", + "\n", + "table_pulse = TablePT({'default': [('t_begin', 'v_begin', 'hold'),\n", + " ('t_end', 'v_end', 'linear')]}, identifier='my_pulse')\n", + "\n", + "dict_pulse_storage['my_pulse'] = table_pulse\n", + "\n", + "pprint.pprint(dict_backend.storage)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now to store this in a file system we need to replace the `DictBackend` with a `FilesystemBackend`. The following code will create the file `'./serialized_pulses/my_pulse.json'`." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.serialization import FilesystemBackend\n", + "\n", + "filesystem_backend = FilesystemBackend('./serialized_pulses')\n", + "file_pulse_storage = PulseStorage(filesystem_backend)\n", + "\n", + "if 'my_pulse' in file_pulse_storage:\n", + " del file_pulse_storage['my_pulse']\n", + "\n", + "file_pulse_storage['my_pulse'] = table_pulse" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Loading\n", + "Now we will load a pulse that is shipped only as a JSON file. It is a single sine with frequency `omega`. Note that loading the same pulse multiple times will give you the same object." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading the same pulse multiple times gives you the same object\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import math\n", + "from qupulse.plotting import plot\n", + "\n", + "sine = file_pulse_storage['my_other_pulse']\n", + "\n", + "_ = plot(sine, {'omega': 2*math.pi}, sample_rate=1000, show=False)\n", + "\n", + "if sine is file_pulse_storage['my_other_pulse']:\n", + " print('Loading the same pulse multiple times gives you the same object')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Composed pulses and the role of identifiers\n", + "If we have a pulse that contains other pulses all pulses that have an identifier are stored seperatly. Each `PulseStorage` instance expects that identifiers are unique (see below). Anonymous subpulses are stored together with their parent.\n", + "\n", + "We will now only use a dictionary as a backend it is easier to see what happens.\n", + "\n", + "### Storing" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'combined': '{\\n'\n", + " ' \"#identifier\": \"combined\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.sequence_pulse_template.SequencePulseTemplate\",\\n'\n", + " ' \"subtemplates\": [\\n'\n", + " ' {\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.repetition_pulse_template.RepetitionPulseTemplate\",\\n'\n", + " ' \"body\": {\\n'\n", + " ' \"#identifier\": \"my_other_pulse\",\\n'\n", + " ' \"#type\": \"reference\"\\n'\n", + " ' },\\n'\n", + " ' \"repetition_count\": \"N_sine\"\\n'\n", + " ' },\\n'\n", + " ' {\\n'\n", + " ' \"#identifier\": \"my_pulse\",\\n'\n", + " ' \"#type\": \"reference\"\\n'\n", + " ' }\\n'\n", + " ' ]\\n'\n", + " '}',\n", + " 'my_other_pulse': '{\\n'\n", + " ' \"#identifier\": \"my_other_pulse\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.function_pulse_template.FunctionPulseTemplate\",\\n'\n", + " ' \"channel\": \"default\",\\n'\n", + " ' \"duration_expression\": \"2*pi/omega\",\\n'\n", + " ' \"expression\": \"sin(omega*t)\",\\n'\n", + " ' \"measurements\": [],\\n'\n", + " ' \"parameter_constraints\": []\\n'\n", + " '}',\n", + " 'my_pulse': '{\\n'\n", + " ' \"#identifier\": \"my_pulse\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.table_pulse_template.TablePulseTemplate\",\\n'\n", + " ' \"entries\": {\\n'\n", + " ' \"default\": [\\n'\n", + " ' [\\n'\n", + " ' \"t_begin\",\\n'\n", + " ' \"v_begin\",\\n'\n", + " ' \"hold\"\\n'\n", + " ' ],\\n'\n", + " ' [\\n'\n", + " ' \"t_end\",\\n'\n", + " ' \"v_end\",\\n'\n", + " ' \"linear\"\\n'\n", + " ' ]\\n'\n", + " ' ]\\n'\n", + " ' },\\n'\n", + " ' \"measurements\": [],\\n'\n", + " ' \"parameter_constraints\": []\\n'\n", + " '}'}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import RepetitionPT, SequencePT\n", + "\n", + "# anonymous pulse template\n", + "repeated_sine = RepetitionPT(sine, 'N_sine')\n", + "\n", + "my_sequence = SequencePT(repeated_sine, table_pulse, identifier='combined')\n", + "\n", + "dict_pulse_storage['combined'] = my_sequence\n", + "\n", + "pprint.pprint(dict_backend.storage)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you see, the serialization of 'combined' explicitly contains the anonymous `RepetitionPulseTemplate` but references to 'my_pulse' and 'my_other_pulse' which are stored as separate entries.\n", + "\n", + "## Pulse registry and unique identifiers\n", + "There is the possibility to store pulse templates on construction into a pulse registry. This can be a `PulseStorage`. To set a pulse storage as the default pulse registry call `set_to_default_registry`" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'combined': '{\\n'\n", + " ' \"#identifier\": \"combined\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.sequence_pulse_template.SequencePulseTemplate\",\\n'\n", + " ' \"subtemplates\": [\\n'\n", + " ' {\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.repetition_pulse_template.RepetitionPulseTemplate\",\\n'\n", + " ' \"body\": {\\n'\n", + " ' \"#identifier\": \"my_other_pulse\",\\n'\n", + " ' \"#type\": \"reference\"\\n'\n", + " ' },\\n'\n", + " ' \"repetition_count\": \"N_sine\"\\n'\n", + " ' },\\n'\n", + " ' {\\n'\n", + " ' \"#identifier\": \"my_pulse\",\\n'\n", + " ' \"#type\": \"reference\"\\n'\n", + " ' }\\n'\n", + " ' ]\\n'\n", + " '}',\n", + " 'my_other_pulse': '{\\n'\n", + " ' \"#identifier\": \"my_other_pulse\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.function_pulse_template.FunctionPulseTemplate\",\\n'\n", + " ' \"channel\": \"default\",\\n'\n", + " ' \"duration_expression\": \"2*pi/omega\",\\n'\n", + " ' \"expression\": \"sin(omega*t)\",\\n'\n", + " ' \"measurements\": [],\\n'\n", + " ' \"parameter_constraints\": []\\n'\n", + " '}',\n", + " 'my_pulse': '{\\n'\n", + " ' \"#identifier\": \"my_pulse\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.table_pulse_template.TablePulseTemplate\",\\n'\n", + " ' \"entries\": {\\n'\n", + " ' \"default\": [\\n'\n", + " ' [\\n'\n", + " ' \"t_begin\",\\n'\n", + " ' \"v_begin\",\\n'\n", + " ' \"hold\"\\n'\n", + " ' ],\\n'\n", + " ' [\\n'\n", + " ' \"t_end\",\\n'\n", + " ' \"v_end\",\\n'\n", + " ' \"linear\"\\n'\n", + " ' ]\\n'\n", + " ' ]\\n'\n", + " ' },\\n'\n", + " ' \"measurements\": [],\\n'\n", + " ' \"parameter_constraints\": []\\n'\n", + " '}',\n", + " 'new_pulse': '{\\n'\n", + " ' \"#identifier\": \"new_pulse\",\\n'\n", + " ' \"#type\": '\n", + " '\"qupulse.pulses.function_pulse_template.FunctionPulseTemplate\",\\n'\n", + " ' \"channel\": \"default\",\\n'\n", + " ' \"duration_expression\": 1,\\n'\n", + " ' \"expression\": 0,\\n'\n", + " ' \"measurements\": [],\\n'\n", + " ' \"parameter_constraints\": []\\n'\n", + " '}'}\n" + ] + } + ], + "source": [ + "from qupulse.pulses import FunctionPT\n", + "\n", + "dict_pulse_storage.set_to_default_registry()\n", + "\n", + "new_pulse = FunctionPT(0, 1, identifier='new_pulse')\n", + "\n", + "pprint.pprint(dict_backend.storage)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you see each newly created pulse is put into the pulse storage. Creating a new pulse with the same name will fail:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Oh No!!!\n", + "('Pulse with name already exists', 'new_pulse')\n", + "\n" + ] + } + ], + "source": [ + "try:\n", + " new_pulse = FunctionPT(0, 1, identifier='new_pulse')\n", + "except RuntimeError as err:\n", + " print('Oh No!!!')\n", + " print(err)\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have to either explicitly overwrite the registry or delete the old pulse from it:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting the registry works!\n", + "Deleting the pulse works, too!\n" + ] + } + ], + "source": [ + "try:\n", + " new_pulse = FunctionPT(0, 1, identifier='new_pulse', registry=dict())\n", + "except:\n", + " raise\n", + "else:\n", + " print('Overwriting the registry works!')\n", + "\n", + "del dict_pulse_storage['new_pulse']\n", + "try:\n", + " new_pulse = FunctionPT(0, 1, identifier='new_pulse')\n", + "except:\n", + " raise\n", + "else:\n", + " print('Deleting the pulse works, too!')" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/02CreatePrograms.ipynb b/doc/source/examples/02CreatePrograms.ipynb new file mode 100644 index 000000000..6e65cbb27 --- /dev/null +++ b/doc/source/examples/02CreatePrograms.ipynb @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Instantiating Pulses: Obtaining Pulse Instances From Pulse Templates\n", + "\n", + "In the previous examples, we have modelled pulses using the basic members of qupulse's `PulseTemplate` class hierarchy. However, these are only templates (or classes) of pulses and may contain parameters so that they cannot be run directly on hardware (this is also the reason why we always have to provide some parameters during plotting). First, we have to instantiate a concrete pulse in a process we call *instantiating*. We achieve this by making use of the `create_program()` method and will need to provide concrete parameter values.\n", + "\n", + "The example should be mostly self-contained and easy to follow, however, if you started here and don't know what pulse templates are and how to create them, maybe it's best to have a look at [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb) first.\n", + "\n", + "To start, let us first create a pulse template with a few parameters and two channels.\n", + "## Instantiating a TablePulse" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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1FRJV445161bVx07dtTmzZtVp06dEg0M4Bb4Bl7ZY2LUexdBQEBA0Tbn6+v42WKxSLoyF0eSXnrpJU2dOlWvv/66GjRooKCgIA0dOvSa27r8cRtXt3N1G0VZ5+LFi+rWrZsmT558Tb6rRetGli9frqNHj6pXr175lufm5l6z1wjA9RX5lG6r1eqYxCZJqampysrKUrly5a75Sw/ATVksRToEZKT4+HgFBARo5cqVevzxx29qG+vXr9e9997r+L7Ky8vTvn37VLduXWdGVePGjbVw4UJVq1ZNPj43dSs9zZo1S3/961/13HPP5Vs+YcIEzZo1i1IDFMNN79cMCwtTVFQUhQaAU/n7+2vUqFF65plnNG/ePKWkpOinn34q1hlB8fHxWrFihX788Uf9+uuveuqpp3Ty5EmnZx00aJDOnTun3r17a/PmzUpJSdHy5cv1yCOPKDc394avP336tL788kv169dP9evXz/fo27evFi9e7JiUDODGOFgLwO288MILGjFihMaMGaM6deqoV69e18x1uZ7nn39ejRs3VseOHdWmTRtFRUWpe/fuTs8ZHR2t9evXKzc3Vx06dFCDBg00dOhQlSlTpkhzYebNm6egoKAC5w+1b99eAQEB+uCDD5yeGzAri91ejPMsPVxaWprCwsKUmpqq0NBQQ7NkZmZq7ZotCgmprICAos01QOnmm3lU9b9rp1wvP9lGHrpm0uv/unTpkg4cOKDq1avL39/fRSnhCsX6s908S1o6XGfLNVde6xkKLOKcJZRumVlZSjl9VAnNm97wu8YVivrvN3tqAACAKXhcqXnjjTdUrVo1+fv76/bbb7/mYloAAKB0uqlSc+HCBb377rtKSkpyTGLbtm2bjh496tRw/2v+/PkaPny4xo4dq23btqlhw4bq2LFjsY61AwAAcyr2OYg7d+7UXXfdpbCwMB08eFBPPPGEwsPD9fnnn+vw4cOaN29eSeSUJL366qt64okn9Mgjj0iS3nzzTS1dulSzZ8/Ws88+W2LvWxLOnjisrLQTslzO02Xuxosi8Lc5/+wdlB65ly/p7JnD8vfj+wY3dinbposXTisz/YJbzKkpqmKXmuHDh6t///6aMmWKQkJCHMu7dOmiBx980Knh/ig7O1tbt25VUlKSY5mXl5fuuuuufDey+yObzSabzeZ4npaWVmL5iiv3/fvV3f4f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NDTfAwAAmJOhc2pGjBih/v37X3ed2NhY14QBAAAezdBSExkZqcjISCMjAAAAk/CYs58OHz6sc+fO6fDhw8rNzdWOHTskXbn/VHBwsLHhAACA4Tym1IwZM0Zz5851PG/UqJEkadWqVWrTpo1BqQAAgLvwmLOf5syZI7vdfs2DQgMAACQPKjUAAADXQ6kBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACmQKkBAACm4BGl5uDBg3rsscdUvXp1BQQEqEaNGho7dqyys7ONjgYAANyEj9EBimLv3r3Ky8vTW2+9pbi4OO3evVtPPPGEMjIy9PLLLxsdDwAAuAGPKDWdOnVSp06dHM9jY2P122+/aebMmZQalDqX8yRbTq4CjQ4CAG7GI0pNQVJTUxUeHn7ddWw2m2w2m+N5WlpaSccCSoyXxeL4udHENZKk13vdpntvi5blD2MAUFp5xJya/7V//35Nnz5dTz311HXXS05OVlhYmOMRExPjooSA85UL8FVc2YB8y4bO36HqSV+rRfJKbT983qBkAOAeDC01zz77rCwWy3Ufe/fuzfeao0ePqlOnTurRo4eeeOKJ624/KSlJqampjseRI0dK8j8HKFEWi0UvtqqmV1sGq3vDqHxjx1Iv6b7/+1HVnl2qPrM26kTqJYNSAoBxDD38NGLECPXv3/+668TGxjp+PnbsmNq2basWLVro7bffvuH2rVarrFbrrcYE3EqQr0UT762j13s30YEzGRr4wVbtPZHuGF/77zO6I3mlJKlv86oa3aWO/H29jYoLAC5jaKmJjIxUZGRkkdY9evSo2rZtqyZNmui9996Tl5dHHjkDnKp6RJCWDf2TJGnVb6f01Lytys7Nc4zP23BI8zYckiRNvK+B/to0Rl5ezL8BYE4eMVH46NGjatOmjapWraqXX35Zp0+fdoxFRUVd55VA6dG2Vnntm9BZuXl2vbv2dyV/k//Q7ehFuzR60S6F+vvovUeaqknV60+0BwBP4xGlZsWKFdq/f7/279+vypUr5xuz2+0GpQLck7eXRU+1rqGnWtdQ+qXLGrvkF32+7ahjPO1Sju6fuUGS1Kx6uF7rdZsqlQkobHMA4DE84hhO//79ZbfbC3wAKFyIv69e7XmbDk7qqh9GtlGTqmXzjW86cE4tJ32vas8u1Ytf7lGGLcegpABw6zxiTw2AW1ctIkgLB7aQJK3ff0YD3t+q9D+UmNnrD2j2+gOSpOS/NFCvRObfAPAsHrGnBoBztYyL0K7xHfX7xC76V/f614wnfb5LsaO/VuK/VmjzwXMGJASA4mNPDVCKeXlZ9PAdVfXwHVWVmZ2jCUt/1YcbDzvGz1zMVo83r8y/SaxaVlN7N2L+DQC3xZ4aAJKkQD8fTbivgQ5O6qr1z7ZTQuWwfONbDp13zL955rOflZWda1BSACgYe2oAXKNSmQAtGdxKkvRjyhk99f5WpV/67/ybBVv+owVb/iNJGtetrvo2r8b8GwCGo9QAuK4WNSK0a1xH5eXZ9f5PhzR2yS/5xsd9uUfjvtwjPx8vzenfVC3iIgxKCqC0o9QAKBIvL4v6taimfi2qKcOWo+RvftUHP/13/k12Tp4efHejJKlhTBm93us2VY8IMiougFKIOTUAii3I6qN/db8y/2btM23Voka5fOM/H7mgti//oGrPLtXoRbuUmnXZoKQAShP21AC4JTHhgfroiTskXbmY31Pvb9H5zP+WmI82HtZH//+MqjF/rqu+zavKx5vfpwA4H6UGgNM0qx6u7WM6yG6367Ot/9E/PtuZb/zFr/boxa/2KMTqozceaqw/1SzaDW0BoCgoNQCczmKxqEdijHokxsiWk6vJ3/zmuFqxJKXbctR39iZJUv1KoZr5UBPFhAcaFReASVBqAJQoq4+3xnSrqzHd6up0uk1/+3CrNh887xjffTRNd05ZJUm697ZoJf+lgQL9+GoCUHx8cwBwmcgQqz4dcOX+U9sOn9dT72/V6XSbY/yLHcf0xY5jkqSkzrX1+J2x8ub6NwCKiFIDwBCNq5TV5ufuUl6eXZ9uPaJRC3flG0/+Zq+Sv9krSXqvf1O1rV3eiJgAPAilBoChvLws6tW0ino1raLM7By9+u0+vbvuQL51HpmzWZJUp2Kopv31NsVXCDEiKgA3R6kB4DYC/Xz0/J/r6vk/19WxC1l6fvFufb/3lGP81+Npuvu1NZKkvzSupOe71lV4kJ9RcQG4GUoNALcUXSZAs/s3lSTtOHJBA97fqhNplxzjn287qs+3HZUk/aNjLT1xZ6z8fLj+DVCaUWoAuL3bYsrop9HtZbfbteTnY/r7Jzvyjb+0/De9tPw3+Xl7acaDjXR33QqyWJhgDJQ2lBoAHsNiseje2yrp3tsqKTsnT6+s+E1vrf7dMZ6dm6cn398qSaoRGaS3+yaqRmSwUXEBuBilBoBH8vPxUlLnOkrqXEepmZc1+ONtWvvvM47xlNMZav/KaklSp3pRerlnQwVb+coDzIy/4QA8Xligr95/7HZJ0i/HUvW3D7fp0NlMx/iyX05o2dgTkqQRd9fUwDY1uP8UYEKUGgCmUi86TKv/0bbQ+TevrNinV1bskyS9+XATdazH/BvALCg1AEzpj/NvLl3O1Rur9mv69/vzrTPgg//Ov5neu7HqRocaERWAk1BqAJiev6+3RnSopREdaulU+iWNW/KLvt51wjGecjpDXaatlSR1aRCl8ffUV2SI1ai4AG4SpQZAqVI+xF//91ATSQXPv/l61wlH4RnUtoaGtI+X1cfbkKwAiodSA6DU+uP8m2W7T2jgh9vyjb+xKkVvrEqRJE3r3UjdEioy/wZwY0z/B1DqWSwWdW5QUQcnddX+CZ01pH38NesM+Xi7qid9rZaTvtcvx1INSAngRthTAwB/4OPtpeF319Twu2sq7dJljVjws1bsOekYP3ohS12nrZMkta0VqVd63sb9pwA3QakBgEKE+vvqnb6JkqT9p9L1tw+3ad/Ji47xVb+dVuN/rpAkDWkXp6fbx8uX698AhqHUAEARxJUP0bfDWstut+u7X09p4AdblZNnd4xP+36/pv3/U8an926kPzP/BnA5fqUAgGKwWCy6u24F7Z/YRfv+1VmjOtW+Zp2n///8mzunfK+fj1xwfUiglGJPDQDcJD8fLw1sU0MD29TQuYxs/fOrPVq0/ahj/Mi5LN37xnpJUrva5TXxvgaKCvM3Ki5geuypAQAnCA/y02u9btPBSV21YtifFFc+/93Bv997Snckr1S1Z5fqn1/t0aXLuQYlBcyLPTUA4GTxFUL03fDWkqSVv57UY3O35Bufte6AZq07IEmacn+CeiRWZv4N4ATsqQGAEtS+TgUdnNRVKRO76B8da10z/szCnaqe9LWa/HOFth8+b0BCwDzYUwMALuDtZdGgtnEa1DZOaZcu67lFu/Xlz8cc42czsnXf//0oSWpRo5xe63WbKoQy/wYoDvbUAICLhfr7anrvRjo4qau+H9FaCZXD8o3/mHJWt0+8Mv8m+etfmX8DFBF7agDAQLGRwVoyuJUkae2/T+up97cqM/u/JeatNb/rrTW/S5Je7tFQ9zeuxPwboBDsqQEAN3FnfKT2vNhJKRO7aFy3uteMj/z0Z1VP+lq3T/xOWw+dMyAh4N7YUwMAbsbby6L+Laurf8vqSrt0WRO++lXztxxxjJ9Ms+n+mRskSc1jy+mVng0VXSbAqLiA22BPDQC4sVB/X01+IEEHJ3XVmn+0Vb3o0HzjG34/qxaTvle1Z5dq9KJdzL9BqeYxpeaee+5RlSpV5O/vr4oVK6pPnz46duzYjV8IACZRpVyglg65UwcnddX7jzVTgK93vvGPNh5W7ReWqdqzS/X+hoPK+8O9qYDSwGNKTdu2bbVgwQL99ttvWrhwoVJSUvTAAw8YHQsADHFnfKR+/eeV+TfPd61zzfgLX/yi2NFf6/nFuw1IBxjDY+bUDBs2zPFz1apV9eyzz6p79+66fPmyfH19C3yNzWaTzWZzPE9LSyvxnADgSt5eFj1+Z6wevzNWF205evHLX7Rgy3+MjgUYwmP21PzRuXPn9OGHH6pFixaFFhpJSk5OVlhYmOMRExPjwpQA4FrBVh9NeaChY/5Ns2rhkqQQq48SIz3md1jgpnlUqRk1apSCgoJUrlw5HT58WF988cV1109KSlJqaqrjceTIkeuuDwBmUaVcoBYMaK6Dk7pq46g79afown8BBMzC0FLz7LPPymKxXPexd+9ex/r/+Mc/tH37dn377bfy9vZW3759ZbcXPhHOarUqNDQ03wMAAJiTofsjR4wYof79+193ndjYWMfPERERioiIUM2aNVWnTh3FxMTop59+UvPmzUs4KQAAcHeGlprIyEhFRkbe1Gvz8vIkKd9EYAAAUHp5xMyxjRs3avPmzWrVqpXKli2rlJQUvfDCC6pRowZ7aQAAgCQPmSgcGBiozz//XO3bt1etWrX02GOPKSEhQatXr5bVajU6HgAAcAMesaemQYMG+v77742OAQAA3JhH7KkBAAC4EUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBUoNAAAwBR+jA7iS3W6XJKWlpRmcRMrMzFRGRoZycs4qIyPd6DjwENnZ2bLZMpSWlqacnByj48BDXP2+Oe11Rv5Wq9Fx4AEu2WzKyHCf75qr/25f/Xe8MKWq1KSnXykPMTExBicBAADFlZ6errCwsELHLfYb1R4TycvL07FjxxQSEiKLxWJolrS0NMXExOjIkSMKDQ01NIu74bMpHJ9N4fhsCsdnUzA+l8K522djt9uVnp6u6OhoeXkVPnOmVO2p8fLyUuXKlY2OkU9oaKhb/A/jjvhsCsdnUzg+m8Lx2RSMz6Vw7vTZXG8PzVVMFAYAAKZAqQEAAKZAqTGI1WrV2LFjZeVMhGvw2RSOz6ZwfDaF47MpGJ9L4Tz1sylVE4UBAIB5sacGAACYAqUGAACYAqUGAACYAqUGAACYAqXGIG+88YaqVasmf39/3X777dq0aZPRkQy3Zs0adevWTdHR0bJYLFq8eLHRkdxGcnKymjZtqpCQEJUvX17du3fXb7/9ZnQsw82cOVMJCQmOC4Q1b95c33zzjdGx3NKkSZNksVg0dOhQo6MYbty4cbJYLPketWvXNjqW2zh69KgefvhhlStXTgEBAWrQoIG2bNlidKwiodQYYP78+Ro+fLjGjh2rbdu2qWHDhurYsaNOnTpldDRDZWRkqGHDhnrjjTeMjuJ2Vq9erUGDBumnn37SihUrdPnyZXXo0EEZGRlGRzNU5cqVNWnSJG3dulVbtmxRu3btdO+99+qXX34xOppb2bx5s9566y0lJCQYHcVt1KtXT8ePH3c81q1bZ3Qkt3D+/Hm1bNlSvr6++uabb7Rnzx698sorKlu2rNHRisYOl2vWrJl90KBBjue5ubn26Ohoe3JysoGp3Isk+6JFi4yO4bZOnTpll2RfvXq10VHcTtmyZe3vvvuu0THcRnp6uj0+Pt6+YsUKe+vWre1///vfjY5kuLFjx9obNmxodAy3NGrUKHurVq2MjnHT2FPjYtnZ2dq6davuuusuxzIvLy/ddddd2rBhg4HJ4ElSU1MlSeHh4QYncR+5ubn65JNPlJGRoebNmxsdx20MGjRIXbt2zfedA+nf//63oqOjFRsbq4ceekiHDx82OpJbWLJkiRITE9WjRw+VL19ejRo10jvvvGN0rCKj1LjYmTNnlJubqwoVKuRbXqFCBZ04ccKgVPAkeXl5Gjp0qFq2bKn69esbHcdwu3btUnBwsKxWqwYMGKBFixapbt26RsdyC5988om2bdum5ORko6O4ldtvv11z5szRsmXLNHPmTB04cEB33nmn0tPTjY5muN9//10zZ85UfHy8li9froEDB2rIkCGaO3eu0dGKpFTdpRswg0GDBmn37t3MAfj/atWqpR07dig1NVWfffaZ+vXrp9WrV5f6YnPkyBH9/e9/14oVK+Tv7290HLfSuXNnx88JCQm6/fbbVbVqVS1YsECPPfaYgcmMl5eXp8TERE2cOFGS1KhRI+3evVtvvvmm+vXrZ3C6G2NPjYtFRETI29tbJ0+ezLf85MmTioqKMigVPMXgwYP11VdfadWqVapcubLRcdyCn5+f4uLi1KRJEyUnJ6thw4aaOnWq0bEMt3XrVp06dUqNGzeWj4+PfHx8tHr1ak2bNk0+Pj7Kzc01OqLbKFOmjGrWrKn9+/cbHcVwFStWvOYXgjp16njM4TlKjYv5+fmpSZMmWrlypWNZXl6eVq5cyTwAFMput2vw4MFatGiRvv/+e1WvXt3oSG4rLy9PNpvN6BiGa9++vXbt2qUdO3Y4HomJiXrooYe0Y8cOeXt7Gx3RbVy8eFEpKSmqWLGi0VEM17Jly2suF7Fv3z5VrVrVoETFw+EnAwwfPlz9+vVTYmKimjVrptdff10ZGRl65JFHjI5mqIsXL+b7TenAgQPasWOHwsPDVaVKFQOTGW/QoEH66KOP9MUXXygkJMQx/yosLEwBAQEGpzNOUlKSOnfurCpVqig9PV0fffSRfvjhBy1fvtzoaIYLCQm5Zs5VUFCQypUrV+rnYo0cOVLdunVT1apVdezYMY0dO1be3t7q3bu30dEMN2zYMLVo0UITJ05Uz549tWnTJr399tt6++23jY5WNEafflVaTZ8+3V6lShW7n5+fvVmzZvaffvrJ6EiGW7VqlV3SNY9+/foZHc1wBX0ukuzvvfee0dEM9eijj9qrVq1q9/Pzs0dGRtrbt29v//bbb42O5bY4pfuKXr162StWrGj38/OzV6pUyd6rVy/7/v37jY7lNr788kt7/fr17Var1V67dm3722+/bXSkIrPY7Xa7QX0KAADAaZhTAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSAwAATIFSA8Bl+vfvr+7duxv2/n369HHcffhWZWdnq1q1atqyZYtTtgfg1nFFYQBOYbFYrjs+duxYDRs2THa7XWXKlHFNqD/4+eef1a5dOx06dEjBwcFO2eaMGTO0aNGifDeoBWAcSg0Ap7h6k01Jmj9/vsaMGZPvbr/BwcFOKxM34/HHH5ePj4/efPNNp23z/PnzioqK0rZt21SvXj2nbRfAzeHwEwCniIqKcjzCwsJksVjyLQsODr7m8FObNm309NNPa+jQoSpbtqwqVKigd955x3HX+pCQEMXFxembb77J9167d+9W586dFRwcrAoVKqhPnz46c+ZModlyc3P12WefqVu3bvmWV6tWTRMnTtSjjz6qkJAQValSJd/diLOzszV48GBVrFhR/v7+qlq1qpKTkx3jZcuWVcuWLfXJJ5/c4qcHwBkoNQAMNXfuXEVERGjTpk16+umnNXDgQPXo0UMtWrTQtm3b1KFDB/Xp00eZmZmSpAsXLqhdu3Zq1KiRtmzZomXLlunkyZPq2bNnoe+xc+dOpaamKjEx8ZqxV155RYmJidq+fbv+9re/aeDAgY49TNOmTdOSJUu0YMEC/fbbb/rwww9VrVq1fK9v1qyZ1q5d67wPBMBNo9QAMFTDhg31/PPPKz4+XklJSfL391dERISeeOIJxcfHa8yYMTp79qx27twp6co8lkaNGmnixImqXbu2GjVqpNmzZ2vVqlXat29fge9x6NAheXt7q3z58teMdenSRX/7298UFxenUaNGKSIiQqtWrZIkHT58WPHx8WrVqpWqVq2qVq1aqXfv3vleHx0drUOHDjn5UwFwMyg1AAyVkJDg+Nnb21vlypVTgwYNHMsqVKggSTp16pSkKxN+V61a5ZijExwcrNq1a0uSUlJSCnyPrKwsWa3WAicz//H9rx4yu/pe/fv3144dO1SrVi0NGTJE33777TWvDwgIcOxFAmAsH6MDACjdfH198z23WCz5ll0tInl5eZKkixcvqlu3bpo8efI126pYsWKB7xEREaHMzExlZ2fLz8/vhu9/9b0aN26sAwcO6JtvvtF3332nnj176q677tJnn33mWP/cuXOKjIws6n8ugBJEqQHgURo3bqyFCxeqWrVq8vEp2lfYbbfdJknas2eP4+eiCg0NVa9evdSrVy898MAD6tSpk86dO6fw8HBJVyYtN2rUqFjbBFAyOPwEwKMMGjRI586dU+/evbV582alpKRo+fLleuSRR5Sbm1vgayIjI9W4cWOtW7euWO/16quv6uOPP9bevXu1b98+ffrpp4qKisp3nZ21a9eqQ4cOt/KfBMBJKDUAPEp0dLTWr1+v3NxcdejQQQ0aNNDQoUNVpkwZeXkV/pX2+OOP68MPPyzWe4WEhGjKlClKTExU06ZNdfDgQX399deO99mwYYNSU1P1wAMP3NJ/EwDn4OJ7AEqFrKws1apVS/Pnz1fz5s2dss1evXqpYcOGGj16tFO2B+DWsKcGQKkQEBCgefPmXfcifcWRnZ2tBg0aaNiwYU7ZHoBbx54aAABgCuypAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApkCpAQAApvD/ALK8f8/LDUTiAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.plotting import plot\n", + "from qupulse.pulses import TablePT\n", + "\n", + "template = TablePT(entries={'A': [(0, 0),\n", + " ('ta', 'va', 'hold'),\n", + " ('tb', 'vb', 'linear'),\n", + " ('tend', 0, 'jump')],\n", + " 'B': [(0, 0),\n", + " ('ta', '-va', 'hold'),\n", + " ('tb', '-vb', 'linear'),\n", + " ('tend', 0, 'jump')]}, measurements=[('m', 0, 'ta'),\n", + " ('n', 'tb', 'tend-tb')])\n", + "\n", + "parameters = {'ta': 2,\n", + " 'va': 2,\n", + " 'tb': 4,\n", + " 'vb': 3,\n", + " 'tc': 5,\n", + " 'td': 11,\n", + " 'tend': 6}\n", + "_ = plot(template, parameters, sample_rate=100, show=False, plot_measurements={'m', 'n'})\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `HardwareSetup` class represents the actual hardware and interfaces to the devices in qupulse. It is thus responsible for uploading to and executing pulses on the hardware. To do so it currently expects an instantiated pulse which is represented by `Loop` objects. These can be obtained by plugging the desired parameters into the `create_program` method of your `PulseTemplate` object." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "LOOP 1 times:\n", + " ->EXEC MultiChannelWaveform((TableWaveform(channel='A', waveform_table=(TableWaveformEntry(t=0.0, v=0, interp=), TableWaveformEntry(t=2, v=2, interp=), TableWaveformEntry(t=4, v=3, interp=), TableWaveformEntry(t=6, v=0, interp=))), TableWaveform(channel='B', waveform_table=(TableWaveformEntry(t=0.0, v=0, interp=), TableWaveformEntry(t=2, v=-2, interp=), TableWaveformEntry(t=4, v=-3, interp=), TableWaveformEntry(t=6, v=0, interp=))))) 1 times\n", + "Defined on frozenset({'B', 'A'})\n", + "{'m': (array([0.]), array([2.])), 'n': (array([4.]), array([2.]))}\n" + ] + } + ], + "source": [ + "program = template.create_program(parameters=parameters,\n", + " channel_mapping={'A': 'A', 'B': 'B'})\n", + "\n", + "print(program)\n", + "print('Defined on', program[0].waveform.defined_channels)\n", + "print(program.get_measurement_windows())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The output shows us that a simple `Loop` object was created which just executes a single waveform without repetitions, just as our `PulseTemplate` specifies. In the `Loop` object all parameter references from the template have been resolved and replaced by the values provided in the `parameters` dictionary, so this is our pulse ready to be executed on the hardware.\n", + "\n", + "### Mapping Channels and Measurements During Instantiation\n", + "\n", + "The `channel_mapping` keyword argument allows us to rename channels or to drop them by mapping them to `None`. We can do the same to measurements using the `measurement_mapping` keyword argument." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "LOOP 1 times:\n", + " ->EXEC TableWaveform(channel='Y', waveform_table=(TableWaveformEntry(t=0.0, v=0, interp=), TableWaveformEntry(t=2, v=-2, interp=), TableWaveformEntry(t=4, v=-3, interp=), TableWaveformEntry(t=6, v=0, interp=))) 1 times\n", + "Defined on {'Y'}\n", + "{'foo': (array([0.]), array([2.]))}\n" + ] + } + ], + "source": [ + "program = template.create_program(parameters=parameters,\n", + " channel_mapping={'A': None, 'B': 'Y'},\n", + " measurement_mapping={'m': 'foo', 'n': None})\n", + "print(program)\n", + "print('Defined on', program[0].waveform.defined_channels)\n", + "print(program.get_measurement_windows())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiating Composed Pulses\n", + "\n", + "Let's have a brief look at a slightly more complex pulse. Say we want to repeat our previous pulse a few times and follow it up with a brief sine wave on each channel." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "LOOP 1 times:\n", + " ->LOOP 4 times:\n", + " ->EXEC MultiChannelWaveform((TableWaveform(channel='A', waveform_table=(TableWaveformEntry(t=0.0, v=0, interp=), TableWaveformEntry(t=2, v=2, interp=), TableWaveformEntry(t=4, v=3, interp=), TableWaveformEntry(t=6, v=0, interp=))), TableWaveform(channel='B', waveform_table=(TableWaveformEntry(t=0.0, v=0, interp=), TableWaveformEntry(t=2, v=-2, interp=), TableWaveformEntry(t=4, v=-3, interp=), TableWaveformEntry(t=6, v=0, interp=))))) 1 times\n", + " ->EXEC MultiChannelWaveform((FunctionWaveform(duration=TimeType(6283, 1000), expression=ExpressionScalar('sin(t)'), channel='A'), FunctionWaveform(duration=TimeType(6283, 1000), expression=ExpressionScalar('2*sin(t)'), channel='B'))) 1 times\n", + "{'m': (array([ 0., 6., 12., 18.]), array([2., 2., 2., 2.])), 'n': (array([ 4., 10., 16., 22.]), array([2., 2., 2., 2.]))}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Simon\\Documents\\git\\qupulse\\qupulse\\plotting.py:186: UserWarning: Sample count 30293/10 is not an integer. Will be rounded (this changes the sample rate).\n", + " times, voltages, measurements = render(program,\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qupulse.pulses import FunctionPT, SequencePT, RepetitionPT, AtomicMultiChannelPT\n", + "\n", + "repeated_template = RepetitionPT(template, 'n_rep')\n", + "sine_template = FunctionPT('sin_a*sin(t)', '2*3.1415')\n", + "two_channel_sine_template = AtomicMultiChannelPT(\n", + " (sine_template, {'default': 'A'}), \n", + " (sine_template, {'default': 'B'}, {'sin_a': 'sin_b'})\n", + ")\n", + "sequence_template = SequencePT(repeated_template, two_channel_sine_template)\n", + "\n", + "sequence_parameters = dict(parameters) # we just copy our parameter dict from before\n", + "sequence_parameters['n_rep'] = 4 # and add a few new values for the new params from the sine wave\n", + "sequence_parameters['sin_a'] = 1\n", + "sequence_parameters['sin_b'] = 2\n", + "\n", + "_ = plot(sequence_template, parameters=sequence_parameters, sample_rate=100, show=False)\n", + "sequence_program = sequence_template.create_program(parameters=sequence_parameters, \n", + " channel_mapping={'A': 'A', 'B': 'B'})\n", + "print(sequence_program)\n", + "print(sequence_program.get_measurement_windows())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, our `Loop` now contains an inner `Loop` object which repeats a waveform four times and additionally executes another waveform. This reflects the structure of our pulse template. Note also that the single measurement window defined by our pulse template `template` is repeated four times as well in the `Loop` object, according to the number of repetitions of the corresponding pulse.\n", + "\n", + "Don't worry too much about the inner workings of the `Loop` objects, though. We were just taking a short look at them here. In practice it will be sufficient to just obtain them using the `create_program` method of `PulseTemplate` and pass them on to `HardwareSetup` when required." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/02FunctionPulse.ipynb b/doc/source/examples/02FunctionPulse.ipynb deleted file mode 100644 index 2d0d53edb..000000000 --- a/doc/source/examples/02FunctionPulse.ipynb +++ /dev/null @@ -1,1660 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Modelling Pulses Using Functions And Expressions\n", - "\n", - "Assume we want to model a pulse that represents a damped sine function. While we could, in theory, do this using `TablePulseTemplate`s by piecewise linear approximation (cf. [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb)), this would be a tedious endeavor. A much simpler approach presents itself in the form of the `FunctionPulseTemplate` class of qupulse. Like the `TablePulseTemplate`, a `FunctionPulseTemplate` represents an atomic pulse which will be converted into a waveform for execution. The difference between both is that `FunctionPulseTemplate` accepts a mathematical expression which is parsed and evaluated using `sympy` to sample the waveform instead of the linear interpolation between specified supporting points as it is done in `TablePulseTemplate`.\n", - "\n", - "To define the sine function pulse template, we can thus do the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "param_template = FunctionPT('exp(-t/tau)*sin(phi*t)', 'duration')\n", - "\n", - "_ = plot(param_template, {'tau': 4, 'phi': 8, 'duration': 4*3.1415}, sample_rate=100)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/doc/source/examples/03ConstantPulseTemplate.ipynb b/doc/source/examples/03ConstantPulseTemplate.ipynb deleted file mode 100644 index a2fffaacc..000000000 --- a/doc/source/examples/03ConstantPulseTemplate.ipynb +++ /dev/null @@ -1,104 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# The ConstantPulseTemplate\n", - "\n", - "The `ConstantPulseTemplate`(or short `ConstantPT`) can be used to define pulse templates with all channels a constant value. The template is easy to define and allows backends to optimize the waveforms on an AWG." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'A', 'B'}\n", - "{'A': Expression('10.0000000000000'), 'B': Expression('2.00000000000000')}\n" - ] - } - ], - "source": [ - "%matplotlib inline\n", - "from qupulse.pulses import ConstantPT\n", - "\n", - "constant_template = ConstantPT(10, {'A': 1., 'B': .2})\n", - "\n", - "print(constant_template.defined_channels)\n", - "print(constant_template.integral)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The pulse template has two channels." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\projects\\qupulse\\qupulse\\pulses\\plotting.py:236: UserWarning: Matplotlib is currently using module://ipykernel.pylab.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", - " axes.get_figure().show()\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "from qupulse.pulses.plotting import plot\n", - "\n", - "_ = plot(constant_template, sample_rate=100)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "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.8.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/doc/source/examples/03FreeInductionDecayExample.ipynb b/doc/source/examples/03FreeInductionDecayExample.ipynb new file mode 100644 index 000000000..365eff2aa --- /dev/null +++ b/doc/source/examples/03FreeInductionDecayExample.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Free Induction Decay - A Real Use Case\n", + "\n", + "The following will give an example of a complex pulse using many of the features discussed in the previous tutorial examles: We will use two channels, parameters and parameter constraints, parameterized measurements and atomic and non-atomic pulse templates. This is based on real experiments. To see another, a bit more artificial example for a pulse setup use case that offers more verbose explanations, see [Gate Configuration - A Full Use Case](03GateConfigurationExample.ipynb).\n", + "\n", + "We start by creating some atomic pulse templates using `PointPT` which will be the building blocks for the more complex pulse structure we have in mind." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.pulses import PointPT, SequencePT, ForLoopPT, RepetitionPT, MappingPT\n", + "import qupulse.pulses.plotting\n", + "import numpy as np\n", + "import sympy as sp\n", + "from sympy import sympify as S\n", + "\n", + "channel_names = ['RFX', 'RFY']\n", + "\n", + "S_init = PointPT([(0, 'S_init'),\n", + " ('t_init', 'S_init')],\n", + " channel_names=channel_names, identifier='S_init')\n", + "\n", + "meas_wait = PointPT([(0, 'meas'),\n", + " ('t_meas_wait', 'meas')],\n", + " channel_names=channel_names)\n", + "\n", + "adprep = PointPT([(0, 'meas'),\n", + " ('t_ST_prep', 'ST_plus - ST_jump/2', 'linear'),\n", + " ('t_ST_prep', 'ST_plus + ST_jump/2'),\n", + " ('t_op', 'op', 'linear')],\n", + " parameter_constraints=['Abs(ST_plus - ST_jump/2 - meas) <= Abs(ST_plus - meas)',\n", + " 'Abs(ST_plus - ST_jump/2 - meas)/t_ST_prep <= max_ramp_speed',\n", + " 'Abs(ST_plus + ST_jump/2 - op)/Abs(t_ST_prep-t_op) <= max_ramp_speed'],\n", + " channel_names=channel_names, identifier='adprep')\n", + "\n", + "adread = PointPT([(0, 'op'),\n", + " ('t_ST_read', 'ST_plus + ST_jump/2', 'linear'),\n", + " ('t_ST_read', 'ST_plus - ST_jump/2'),\n", + " ('t_meas_start', 'meas', 'linear'),\n", + " ('t_meas_start + t_meas_duration', 'meas')],\n", + " parameter_constraints=['Abs(ST_plus - ST_jump/2 - meas) <= Abs(ST_plus - meas)',\n", + " 'Abs(ST_plus - ST_jump/2 - meas)/t_ST_read <= max_ramp_speed',\n", + " 'Abs(ST_plus + ST_jump/2 - op)/Abs(t_ST_read-t_op) <= max_ramp_speed'],\n", + " channel_names=channel_names, identifier='adread',\n", + " measurements=[('m', 't_meas_start', 't_meas_duration')])\n", + "\n", + "free_induction = PointPT([(0, 'op-eps_J'),\n", + " ('t_fid', 'op-eps_J')], channel_names=channel_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the next step, we combine our building blocks into more complex pulses step by step.\n", + "We first define our core functionality pulse template `stepped_free_induction`.\n", + "The pulse template `pulse` surrounds our functionality with pulses to reset/initialize our qubit and allow for data acquisition.\n", + "We will use `pulse` in a `ForLoopPT` `looped_pulse` to perform a parameter sweep. Our final pulse template `experiment` repeats this whole thing a number of times to allow for statistical aggregating of measurement data and represents the complete pulse template for our experiment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "stepped_free_induction = MappingPT(free_induction, parameter_mapping={'t_fid': 't_start + i_fid*t_step'}, allow_partial_parameter_mapping=True)\n", + "\n", + "pulse = SequencePT(S_init, meas_wait, adprep, stepped_free_induction, adread)\n", + "\n", + "looped_pulse = ForLoopPT(pulse, loop_index='i_fid', loop_range='N_fid_steps')\n", + "\n", + "experiment = RepetitionPT(looped_pulse, 'N_repetitions', identifier='free_induction_decay')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(experiment.parameter_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's use some reasonable (but low) values for our parameters and plot our `experiment` pulse (we set the number of repeititions of `looped_pulse` only to 2 so that the plot does not get too stuffed).\n", + "\n", + "Note that we provide numpy arrays of length 2 for some parameters to assign different values for different channels (see also [The PointPulseTemplate](00PointPulse.ipynb))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib notebook\n", + "\n", + "example_values = dict(meas=[0, 0],\n", + " op=[5, -5],\n", + " eps_J=[1, -1],\n", + " ST_plus=[2.5, -2.5],\n", + " S_init=[-1, -1],\n", + " ST_jump=[1, -1],\n", + " max_ramp_speed=0.3,\n", + " \n", + " t_init=5,\n", + " \n", + " t_meas_wait = 1,\n", + " \n", + " t_ST_prep = 10,\n", + " t_op = 20,\n", + " \n", + " t_ST_read = 10,\n", + " t_meas_start = 20,\n", + " t_meas_duration=5,\n", + " \n", + " t_start=0,\n", + " t_step=5,\n", + " N_fid_steps=5, N_repetitions=2)\n", + "\n", + "from qupulse.pulses.plotting import plot\n", + "\n", + "_ = plot(experiment, example_values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can clearly make out the many repetitions of our basic functionality pulse and also the varying duration between the voltage peaks due to our parameter sweep (as well as the two-fold repetition of the sweep itself).\n", + "\n", + "Let's also quickly plot only a single repetition by setting according parameters for our `experiment` pulse template." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "example_values['N_fid_steps'] = 1\n", + "example_values['N_repetitions'] = 1\n", + "example_values['t_start'] = 5\n", + "\n", + "_ = plot(experiment, example_values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a last step we will save the pulse and some example parameters so we can use it in other examples." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "from qupulse.serialization import FilesystemBackend, PulseStorage\n", + "\n", + "pulse_storage = PulseStorage(FilesystemBackend('./serialized_pulses'))\n", + "\n", + "# overwrite all pulses explicitly\n", + "pulse_storage.overwrite('adprep', adprep)\n", + "pulse_storage.overwrite('S_init', S_init)\n", + "pulse_storage.overwrite('adread', adread)\n", + "pulse_storage.overwrite('free_induction_decay', experiment)\n", + "\n", + "with open('parameters/free_induction_decay.json', 'w') as parameter_file:\n", + " json.dump(example_values, parameter_file)\n", + "\n", + "print('Successfully saved pulse and example parameters')" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/source/examples/03GateConfigurationExample.ipynb b/doc/source/examples/03GateConfigurationExample.ipynb new file mode 100644 index 000000000..f20bf30d7 --- /dev/null +++ b/doc/source/examples/03GateConfigurationExample.ipynb @@ -0,0 +1,334 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Gate Configuration - A Full Use Case" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "An example for a real use case of qupulse is the search for and evaluation of parameters for pulses that represent quantum gate operations on a toy example. To see an example closer to reality but less verbose in explanations, please see [Free Induction Decay - A Real Use Case](03FreeInductionDecayExample.ipynb).\n", + "\n", + "## Description of the Experiment\n", + "The experiment will typically involve a set of gate pulses $G_j, 0 \\leq j < N_{Gates}$.\n", + "\n", + "The template for a gate pulse $G_j$ is a sequence of $\\epsilon_i, 0 \\leq i < N_{G_j}$ voltage levels held for time $\\Delta t = 1$ ns as illustrated in the figure below (with $N_{G_j} = 7$).\n", + "\n", + "![Template of a gate pulse](img/gate_pulse_scheme.png)\n", + "\n", + "The experiment defines a number of sequences $S_k, 0 \\leq k < N_{Sequences}$ of the $G_j$ as $$S_k = (G_{m_k(1)}, G_{m_k(2)}, \\dots, G_{m_k(N_{S_k})})$$ where $N_{S_k}$ is the length of sequence $k$ and $m_k(i): \\{0, \\dots, N_{S_k} - 1\\} \\rightarrow \\{0, \\dots, N_{Gates} - 1\\}$ is a function that maps an index $i$ to the $m_k(i)$-th gate of sequence $S_k$ and thus fully describes the sequence. (These sequences express the sequential application of the gates to the qubit. In terms of quantum mathematics they may rather be expressed as multiplication of the matrices describing the unitary transformations applied by the gates: $S_k = \\prod_{i=N_{S_k} - 1}^{0} G_{m_k(i)} = G_{(N_{S_k} - 1)} \\cdot \\dots \\cdot G_{1} \\cdot G_{0}$.)\n", + "\n", + "Measuring and analysing the effects of these sequences on the qubit's state to derive parameters $\\epsilon_i$ for gate pulses that achieve certain state transformations is the goal of the experiment.\n", + "\n", + "To this end, every sequence must be extended by some preceeding initialization pulse and a succeeding measurement pulse. Furthermore, due to hardware constraints in measuring, all sequences must be of equal length (which is typically 4 µs). Thus, some sequences require some wait time before initialization to increase their playback duration. These requirements give raise to extended sequences $S_k'$ of the form:\n", + "$$S_k' = I_{p(k)} | W_k | S_k | M_{q(k)}$$\n", + "where the functions $p(k)$ and $q(k)$ respectively select some initialization pulse $I_{p(k)} \\in \\{I_1, I_2, \\dots\\}$ and measurement pulse $M_{q(k)} \\in \\{M_1, M_2, \\dots\\}$ for sequence $k$ and $W_k$ is the aforementioned wait pulse. The '|' denote concatenation of pulses, i.e., sequential execution.\n", + "\n", + "Since measurement of quantum state is a probabilistic process, many measurements of the effect of a single sequence must be made to reconstruct the resulting state of the qubit. Thus, the experiment at last defines scanlines (typically of duration 1 second), which are sequences of the $S_k'$. (These simply represent batches of sequences to configure playback and measurement systems and have no meaning to the experiment beyond these practical considerations.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementation Using qupulse\n", + "\n", + "We now want to illustrate how to setup the experiment described above using qupulse. Let us assume the experiment considers only two different gates pulses ($N_{Gates} = 2$). We further assume that $N_{G_1} = 20$ and $N_{G_2} = 18$. We define them using instances of `TablePulseTemplate`:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.pulses import TablePT\n", + "\n", + "delta_t = 1 # assuming that delta_t is 1 elementary time unit long in pulse defintions, i.e. 1 time unit = 1 ns\n", + "\n", + "gate_0 = TablePT({0: [(i*delta_t, 'gate_0_eps_' + str(i))\n", + " for i in range(19)]})\n", + " \n", + "gate_1 = TablePT({0: [(i*delta_t, 'gate_2_eps_' + str(i))\n", + " for i in range(17)]})\n", + " \n", + "gates = [gate_0, gate_1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We thus obtain two `TablePulseTemplate` of the desired form with parameters 'gate_1_eps_1' to 'gate_1_eps_20' and 'gate_2_eps_1' to 'gate_2_eps_18'.\n", + "\n", + "Next, we will define sequences as `SequncePulseTemplate` objects. We assume that the mapping functions $m_k$ are given as a 2 dimensional array (which impilicitly also defines $N_{Sequences}$ and $N_{S_k}$), e.g.:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "m = [\n", + " [0, 1, 0, 0, 0, 1, 1, 0, 1], # m_0(i)\n", + " [1, 1, 0, 0, 1, 0], # m_1(i)\n", + " [1, 0, 0, 1, 1, 0, 0, 1] #m_2(i)\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `SequencePulseTemplate` objects can now easily be constructed:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.pulses import SequencePT\n", + "\n", + "# SequencePulseTemplate requires a definition of parameter mappings from parameters passed into the\n", + "# SequencePulseTemplate object to its subtemplates. In this case, we want parameters to map 1 to 1\n", + "# and thus create an identity mapping of parameter names for both gates using python list/set/dict comprehension\n", + "epsilon_mappings = [\n", + " {param_name: param_name for param_name in gates[0].parameter_names},\n", + " {param_name: param_name for param_name in gates[1].parameter_names}\n", + "]\n", + "all_epsilons = gates[0].parameter_names | gates[1].parameter_names\n", + "\n", + "sequences = []\n", + "for m_k in m:\n", + " subtemplates = []\n", + " \n", + " sequences.append(SequencePT(*(gates[g_ki] for g_ki in m_k)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We end up with a list `sequences` which contains the sequences described by our $m$ as qupulse pulse templates.\n", + "\n", + "To visualize our progress, let us plot our two gates and the second sequence with some random values between $-5$ and $5$ for the $\\epsilon_i$:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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AABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABLINQAAABL8JpQs3DhQl1//fUKDQ1VVFSURo4cqSNHjni6LAAA0Eh4TajZsmWLpk6dqu3btys9PV1lZWUaNGiQLl++7OnSAABAI9DM0wXY65NPPqnyfNWqVYqKitKePXv0m9/8psZlSkpKVFJSYnteUFDg0hoBAIDneM1IzS/l5+dLkiIiImpts3DhQoWFhdke8fHx7ioPAAC4mVeGmoqKCk2fPl033nijrr322lrbzZkzR/n5+bbHqVOn3FglAABwJ685/PRzU6dO1cGDB7V169Y62wUEBCggIMBNVQEAAE/yulAzbdo0/f3vf9fnn3+uNm3aeLocAADQSHhNqDFNUw888IDee+89bd68We3atfN0SQAAoBHxmlAzdepU/e///q8++OADhYaGKjc3V5IUFhamoKAgD1cHoDamaaq4rNwt6wry85VhGG5ZF4DGx2tCzfLlyyVJ/fv3rzL9tddeU1pamvsLAlAv0zR1+4pM7cm+4Jb1pSSEa+3kPgQboInymlBjmqanSwDgoOKycrcFGknanX1BxWXlCvb3mo82AE7EOx+AW+yem6pgf1+X9F1UWq6UJze6pG8A3oNQA8Atgv19GUEB4FJeefE9AACAXyLUAAAASyDUAAAASyDUAAAASyDUAAAASyDUAAAASyDUAAAAS3D4ohElJSXasWOHsrOzVVRUpFatWqlHjx7cYBIAAHiU3aFm27Ztev755/V///d/Kisrs91I8vvvv1dJSYmSkpJ03333afLkyQoNDXVlzQAAANXYdfhpxIgRGjNmjBITE/Xpp5+qsLBQ58+f17fffquioiJ9/fXXmjt3rjIyMnT11VcrPT3d1XUDAABUYddIzbBhw7Ru3Tr5+fnVOD8pKUlJSUkaP368Dh06pJycHKcWCQAAUB+7Qs39999vd4edO3dW586dG1wQAABAQ/DtJwAAYAlOCzXjx4/XwIEDndUdAACAQxz+SndtWrduLR8fBn4AAIBnOC3ULFiwwFldAQAAOIyhFQAAYAkOj9Tcc889dc5fuXJlg4sBAABoKIdDzYULF6o8Lysr08GDB3Xx4kVOFAYAAB7jcKh57733qk2rqKjQlClT1L59e6cUBQCNlWmaKi4rd8u6gvx8ZRiGW9YFWIFTThT28fHRzJkz1b9/fz388MPO6BIAGh3TNHX7ikztyb5Qf2MnSEkI19rJfQg2gJ2cdqLw8ePH9eOPPzqrOwBodIrLyt0WaCRpd/YFt40KAVbg8EjNzJkzqzw3TVM5OTlav369xo8f77TCmhqGtAHvsntuqoL9fV3Sd1FpuVKe3OiSvgErczjU7Nu3r8pzHx8ftWrVSs8880y934xCzRjSBrxPsL+vgv2ddqkvAE7g8Dty06ZNrqijSfPEkPb5y6Uu+y+zEiNCAAB34t+MRsZdQ9ruGNpmRAgA4E5OCzWPPPKIcnNzufjeFXLlkHaQn69SEsK1202jQpUnOTJEDwBwB6f9tTl9+rROnTrlrO7gAoZhaO3kPi4/IZmTHAEAnuC0UPP66687qyu4kGEYjJwAACyJG1oCAABLaNC/7JcvX9aWLVt08uRJlZaWVpn34IMPOqUwAAAARzToOjW33HKLioqKdPnyZUVEROjcuXMKDg5WVFQUoQYAAHiEw4efZsyYoeHDh+vChQsKCgrS9u3blZ2drV69emnJkiWuqBEAAKBeDoea/fv3a9asWfLx8ZGvr69KSkoUHx+vxYsX65FHHnFFjQAAAPVyONT4+fnJx+enxaKionTy5ElJUlhYGF/pBgAAHuPwOTU9evTQrl27lJycrJtuuknz5s3TuXPn9Ne//lXXXnutK2oEAACol8MjNQsWLFBsbKwk6amnnlJ4eLimTJmi7777Ti+//LLTCwQAALCHwyM1KSkptp+joqL0ySefOLUgAACAhuDiewAAwBLsCjVDhgzR9u3b621XWFioRYsW6cUXX7ziwgAAABxh1+GnUaNG6bbbblNYWJiGDx+ulJQUxcXFKTAwUBcuXNChQ4e0detWffTRRxo2bJiefvppV9cNAABQhV2h5t5779Vdd92ltWvXavXq1Xr55ZeVn58v6acbJHbu3FmDBw/Wrl27dM0117i0YAAAgJrYfaJwQECA7rrrLt11112SpPz8fBUXF+uqq66Sn5+fywoEAACwR4NuaCn9dLG9sLAwZ9YCAADQYHz7CQAAWAKhBgAAWAKhBgAAWEKDz6kBAKCxKiotd/k6gvx8ZRiGy9cD+zUo1Fy8eFHvvPOOjh8/rv/6r/9SRESE9u7dq+joaLVu3drZNQIA4JCUJze6fh0J4Vo7uQ/BphFxONR8+eWXSk1NVVhYmE6cOKFJkyYpIiJC7777rk6ePKk33njDFXUCAFCnID9fpSSEa3f2Bbesb3f2BRWXlSvYn4MejYXDv4mZM2cqLS1NixcvVmhoqG36Lbfcov/8z/90anEAANjLMAytndxHxWWuPfRUVFrulpEgOM7hULNr1y699NJL1aa3bt1aubm5TikKAICGMAyDkZMmzOFvPwUEBKigoKDa9KNHj6pVq1ZOKaouL774ohITExUYGKjevXtr586dLl8nAABo/BwONSNGjNATTzyhsrIyST+l4pMnT2r27Nm67bbbnF7gz61evVozZ87U/PnztXfvXnXv3l2DBw9WXl6eS9cLAAAaP4dDzTPPPKNLly4pKipKxcXFuummm9ShQweFhobqqaeeckWNNs8++6wmTZqkCRMmqHPnzlqxYoWCg4O1cuXKGtuXlJSooKCgygMAAFiTwwcew8LClJ6erq1bt+rLL7/UpUuX1LNnT6WmprqiPpvS0lLt2bNHc+bMsU3z8fFRamqqMjMza1xm4cKFevzxx11aFwAArmKapstPfK5khevuNPhsqn79+qlfv37OrKVO586dU3l5uaKjo6tMj46O1uHDh2tcZs6cOZo5c6bteUFBgeLj411aJwAAzmCapm5fkak9bvqKuhWuu+NwqFm6dGmN0w3DUGBgoDp06KDf/OY38vX1veLirlRAQIACAgI8XQYAAA4rLit3W6CRrHHdHYcrf+655/Tdd9+pqKhI4eHhkqQLFy4oODhYISEhysvLU1JSkjZt2uTUUZHIyEj5+vrq7NmzVaafPXtWMTExTlsPAACNze65qQr2d81ggZWuu+PwicILFizQ9ddfr6+//lrnz5/X+fPndfToUfXu3VvPP/+8Tp48qZiYGM2YMcOphfr7+6tXr17KyMiwTauoqFBGRob69Onj1HUBANCYBPv7Kti/mYsenj+y4iwOj9TMnTtX69atU/v27W3TOnTooCVLlui2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VatWyTCMKo/AwEA3Vex8jz32WLXX06lTpzqXsdI+UCkxMbHadjAMQ1OnTq2xvRX2g88//1zDhw9XXFycDMPQ+++/X2W+aZqaN2+eYmNjFRQUpNTUVH399df19uvoZ4on1bUNysrKNHv2bHXt2lXNmzdXXFyc7r77bp05c6bOPhvynvKk+vaDtLS0aq9nyJAh9fbrTfuBVP92qOnzwTAMPf3007X26e59ocmHmtWrV2vmzJmaP3++9u7dq+7du2vw4MHKy8ursf0//vEPjR07Vvfee6/27dunkSNHauTIkTp48KCbK3eOLVu2aOrUqdq+fbvS09NVVlamQYMG6fLly3Uu16JFC+Xk5Nge2dnZbqrYNbp06VLl9WzdurXWtlbbByrt2rWryjZIT0+XJI0aNarWZbx9P7h8+bK6d++uF198scb5ixcv1tKlS7VixQrt2LFDzZs31+DBg/XDDz/U2qejnymeVtc2KCoq0t69e/Xoo49q7969evfdd3XkyBGNGDGi3n4deU95Wn37gSQNGTKkyut566236uzT2/YDqf7t8PPXn5OTo5UrV8owDN1222119uvWfcFs4m644QZz6tSptufl5eVmXFycuXDhwhrbjx492hw2bFiVab179zbvv/9+l9bpLnl5eaYkc8uWLbW2ee2118ywsDD3FeVi8+fPN7t37253e6vvA5V+//vfm+3btzcrKipqnG+1/UCS+d5779meV1RUmDExMebTTz9tm3bx4kUzICDAfOutt2rtx9HPlMbkl9ugJjt37jQlmdnZ2bW2cfQ91ZjUtA3Gjx9v3nrrrQ714837gWnaty/ceuut5sCBA+ts4+59oUmP1JSWlmrPnj1KTU21TfPx8VFqaqoyMzNrXCYzM7NKe0kaPHhwre29TX5+viQpIiKiznaXLl1SQkKC4uPjdeutt+pf//qXO8pzma+//lpxcXFKSkrSnXfeqZMnT9ba1ur7gPTTe+PNN9/UPffcU+fNX622H/xcVlaWcnNzq/yuw8LC1Lt371p/1w35TPE2+fn5MgxDLVu2rLOdI+8pb7B582ZFRUWpY8eOmjJlis6fP19r26awH5w9e1br16/XvffeW29bd+4LTTrUnDt3TuXl5YqOjq4yPTo6Wrm5uTUuk5ub61B7b1JRUaHp06frxhtv1LXXXltru44dO2rlypX64IMP9Oab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jFADwKO6d++uuXPnKjk5WXPmzFFgYKAiIyM1adIkJScna968eTp//ry+/PJLST+dx9KjRw8tWLBAnTp1Uo8ePbRy5Upt2rRJR48erXEd2dnZ8vX1VVRUVLV5t9xyi373u9+pQ4cOmj17tiIjI7Vp0yZJ0smTJ5WcnKx+/fopISFB/fr109ixY6ssHxcXp+zsbCdvFQANQagB4FHdunWz/ezr66urrrpKXbt2tU2Ljo6WJOXl5Un66YTfTZs22c7RCQkJUadOnSRJx48fr3EdxcXFCggIqPFk5p+vv/KQWeW60tLStH//fnXs2FEPPvigPv3002rLBwUF2UaRAHhWM08XAKBp8/Pzq/LcMIwq0yqDSEVFhSTp0qVLGj58uBYtWlStr9jY2BrXERkZqaKiIpWWlsrf37/e9Veuq2fPnsrKytLHH3+sjRs3avTo0UpNTdU777xja//999+rVatW9r5cAC5EqAHgVXr27Kl169YpMTFRzZrZ9xF23XXXSZIOHTpk+9leLVq00JgxYzRmzBjdfvvtGjJkiL7//ntFRERI+umk5R49ejjUJwDX4PATAK8ydepUff/99xo7dqx27dql48ePa8OGDZowYYLKy8trXKZVq1bq2bOntm7d6tC6nn32Wb311ls6fPiwjh49qrVr1yomJqbKdXa++OILDRo06EpeEgAnIdQA8CpxcXHatm2bysvLNWjQIHXt2lXTp09Xy5Yt5eNT+0faxIkT9be//c2hdYWGhmrx4sVKSUnR9ddfrxMnTuijjz6yrSczM1P5+fm6/fbbr+g1AXAOLr4HoEkoLi5Wx44dtXr1avXp08cpfY4ZM0bdu3fXI4884pT+AFwZRmoANAlBQUF644036rxInyNKS0vVtWtXzZgxwyn9AbhyjNQAAABLYKQGAABYAqEGAABYAqEGAABYAqEGAABYAqEGAABYAqEGAABYAqEGAABYAqEGAABYAqEGAABYwv8DNsDFo106Ks8AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import random\n", + "\n", + "random.seed('Some seed such that numbers generated are predictable')\n", + "parameters = {parameter_name: random.random() * 10 - 5 for parameter_name in all_epsilons}\n", + "\n", + "from qupulse.pulses.plotting import plot\n", + "_ = plot(gates[0], parameters)\n", + "_ = plot(gates[1], parameters)\n", + "_ = plot(sequences[1], parameters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now must construct the $S_k'$. For simplicity, we assume that there is only one initialization and one measurement pulse which are defined somehow and define only stubs here. We also define a waiting pulse with a variable length:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# stub for an initialization pulse of length 4\n", + "init = TablePT({0: [(0, 5), (4, 0, 'linear')]})\n", + "\n", + "# stub for a measurement pulse of length 12\n", + "measure = TablePT({0: [(0, 0), (12, 5, 'linear')]})\n", + "\n", + "# a wating pulse\n", + "wait = TablePT({0: [(0, 0), ('wait_duration', 0)]})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For our example, let us assume that we want all $S_k'$ to take 200 ns (since we've chosen the $S_k$ to be rather short). We know that the duration of our gate pulses in nanoseconds is equal to the number of entries in the `TablePulseTemplate` objects (each voltage level is held for one unit of time in the tables which corresponds to $\\Delta t = 1$ ns by convention). Accordingly, the init pulse lasts for 4 ns and the measure pulse for 12 ns. The required length of the wait pulse can then be computed as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[175, 178, 176]\n" + ] + } + ], + "source": [ + "wait_times = []\n", + "desired_time = 200\n", + "\n", + "for m_k in m:\n", + " duration_k = 4 + 12 # init + measurement duration\n", + " for g_ki in m_k:\n", + " duration_k += len(gates[g_ki].entries) # add the number of entries of all gates in the sequence\n", + " wait_time_k = desired_time - duration_k\n", + " wait_times.append(wait_time_k)\n", + " \n", + "print(wait_times)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally we can construct the $S_k'$:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# an identity mapping for all epsilons\n", + "all_epsilons_map = {param_name: param_name for param_name in all_epsilons}\n", + "\n", + "gates_with_init_and_readout = [SequencePT((wait, {'wait_duration': wait_duration}),\n", + " init,\n", + " gate,\n", + " measure)\n", + " for gate, wait_duration in zip(sequences, wait_times)]\n", + "final_sequence = SequencePT(*gates_with_init_and_readout)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us plot $S_1'$ to see whether we've accomplished our goal:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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1dChQ7Vq1SqrS/J6f/7zn2Wz2Zp89ezZ0/n+oUOHNGXKFLVv316RkZG6/PLLtW/fPgsr9i5LlizRJZdcotTUVNlsNn344YdN3jcMQw888IBSUlIUFhamUaNGafv27U22KS4u1tVXX63o6GjFxsbqhhtuUEVFhYnfhXc41VxOmjTpmJ/VsWPHNtmGuWwwe/ZsnXHGGYqKilJiYqIuu+wybd26tck2rvzZzs7O1rhx4xQeHq7ExET94Q9/UF1dnZnfildwZT7PO++8Y34+J0+e3GQb5rP12kyomTt3rqZPn64HH3xQa9asUf/+/TVmzBgVFBRYXZrX6927t/Ly8pxfS5cudb43bdo0/fe//9W7776rxYsXa+/evfr1r39tYbXe5eDBg+rfv7+ef/75474/Z84cPfPMM3rxxRe1cuVKRUREaMyYMTp06JBzm6uvvlo//vij5s+fr08++URLlizRzTffbNa34DVONZeSNHbs2CY/q2+//XaT95nLBosXL9aUKVO0YsUKzZ8/X7W1tRo9erQOHjzo3OZUf7br6+s1btw41dTU6Ntvv9Ubb7yh119/XQ888IAV35KlXJlPSbrpppua/HzOmTPH+R7z6SZGGzFkyBBjypQpzuf19fVGamqqMXv2bAur8n4PPvig0b9//+O+V1JSYgQHBxvvvvuu87XNmzcbkozly5ebVKHvkGR88MEHzucOh8NITk42HnvsMedrJSUlht1uN95++23DMAxj06ZNhiRj9erVzm0+//xzw2azGbm5uabV7m2OnkvDMIyJEycav/zlL0/4GebyxAoKCgxJxuLFiw3DcO3P9meffWYEBAQY+fn5zm1eeOEFIzo62qiurjb3G/AyR8+nYRjGueeea/z+978/4WeYT/doE0dqampq9P3332vUqFHO1wICAjRq1CgtX77cwsp8w/bt25WamqouXbro6quvVnZ2tiTp+++/V21tbZN57dmzpzp16sS8uiArK0v5+flN5i8mJkZDhw51zt/y5csVGxurwYMHO7cZNWqUAgICtHLlStNr9naLFi1SYmKievTooVtvvVVFRUXO95jLEystLZX0801/XfmzvXz5cvXt21dJSUnObcaMGaOysjL9+OOPJlbvfY6ez0ZvvfWW4uPj1adPH82cOVOVlZXO95hP92gTN7QsLCxUfX19kx8WSUpKStKWLVss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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pl = plot(final_sequence.subtemplates[1], parameters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us also plot the whole sequence $S_1' | S_2' | S_3'$ as well" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "_ = plot(final_sequence, parameters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we construct a single scanline which just repeats all three sequences over and over again. Since our $S_k'$ are short, we just build a scanline with a duration of 0.6 microseconds. With a duration for each $S_k'$ of 200 ns, we can fit 1'000 repetitions of $S_1' | S_2' | S_3'$ in our scanline. We will, however, not plot our scanline because it will be quite large despite it's short duration." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.pulses import RepetitionPT\n", + "scanline = RepetitionPT(final_sequence, 1000)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/doc/source/examples/03PointPulse.ipynb b/doc/source/examples/03PointPulse.ipynb deleted file mode 100644 index 2eff02f84..000000000 --- a/doc/source/examples/03PointPulse.ipynb +++ /dev/null @@ -1,877 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# The PointPulseTemplate\n", - "\n", - "The `PointPulseTemplate`(or short `PointPT`) can be understood as a specialization of the `TablePulseTemplate`. It restricts the channels to all having the same time points in their entries and the same expression for their voltages.\n", - "\n", - "Let us first have a look at an simple example: " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'A', 'B'}\n" - ] - } - ], - "source": [ - "from qupulse.pulses import PointPT\n", - "\n", - "point_template = PointPT([(0, 'v_0'),\n", - " (1, 'v_1', 'linear'),\n", - " ('t', 'v_0+v_1', 'jump')],\n", - " channel_names=('A', 'B'))\n", - "\n", - "print(point_template.defined_channels)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you can see the pulse template has two channels although we only provided one expression for the voltage per time point. The value of this expression can either be scalar as we will see now for `v_0` or be a `numpy` array of the same length as the number of channels is like `v_1`. A value of the wrong length will result in an exception." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib notebook\n", - "from qupulse.pulses.plotting import plot\n", - "\n", - "parameters = dict(t=3,\n", - " t_2=2,\n", - " v_0=1,\n", - " v_1=1.4)\n", - "\n", - "_ = plot(first_point_pt, parameters, sample_rate=100)\n", - "_ = plot(second_point_pt, parameters, sample_rate=100)\n", - "_ = plot(sequence_pt, parameters, sample_rate=100)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## RepetitionPulseTemplate: Repeating a Pulse\n", - "\n", - "If we simply want to repeat some pulse template a fixed number of times, we can make use of the `RepetitionPulseTemplate`. In the following, we will reuse one of our `PointPT`s, `first_point_pt` and use it to create a new pulse template that repeats it `n_rep` times, where `n_rep` will be a parameter." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "repetition parameters: {'v_1', 'n_rep', 'v_0', 't'}\n", - "repetition measurements: {'M'}\n" - ] - }, - { - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from qupulse.pulses import ForLoopPT\n", - "\n", - "for_loop_pt = ForLoopPT(first_point_pt, 't', ('t_start', 't_end', 2))\n", - "\n", - "print(\"for loop parameters: {}\".format(for_loop_pt.parameter_names))\n", - "print(\"for loop measurements: {}\".format(for_loop_pt.measurement_names))\n", - "\n", - "# plot it\n", - "parameters['t_start'] = 4\n", - "parameters['t_end'] = 13\n", - "_ = plot(for_loop_pt, parameters, sample_rate=100)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The second argument to `ForLoopPT`'s constructor is the name of the loop parameter. This has to be a parameter that is defined by the subtemplate. The third argument defined the range of the loop. The syntax of the range is similar to that of the `range()` command in Python, i.e., a tuple `(start_value, end_value, step)`. As seen above, inserting parameter values or even expressions is okay. As in `range()`, the `end_value` is exclusive.\n", - "\n", - "As for `SequencePT` and `RepetitionPT`, `ForLoopPT` exposes all parameters defined by the subtemplate except for the loop parameter, `t` in the above example. If expressions are used in the range definition and they make use of additional parameters, these are also exposed by `ForLoopPT`. \n", - "\n", - "`ForLoopPT` also exposes measurements defined by subtemplates.\n", - "\n", - "## AtomicMultiChannelPulseTemplate: Run Pulses in Parallel on Different Channels\n", - "\n", - "So far we have only looked at pulses that affect the time-domain aspect of combining pulses. Another way to combine pulses is to parallelise them by executing them on different channels at the same time. This is of course already supported by simply creating atomic pulse templates (`TablePT`, `PointPT`, `FunctionPT`) on multiple channels. However, sometimes it is necessary to put already existing pulses in parallel. Instead of having to define a new atomic pulse template for this, we can make use of the `AtomicMuliChannelPulseTemplate` class. To learn more about how this works, see [Multi-Channel Pulses](07MultiChannelTemplates.ipynb).\n", - "\n", - "## Combining Combined Pulses\n", - "\n", - "Our examples above have build combined higher-level pulses (`SequencePT`, `RepetitionPT`, `ForLoopPT`) on atomic subtemplates only. However, this is not a requirement. We can use `SequencePT`, `RepetitionPT` and `ForLoopPT` using any `PulseTemplate` objects as subtemplates allowing us to build arbitrarily complex pulses out of only a handful of primitives." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/doc/source/examples/15DynamicNuclearPolarisation.ipynb b/doc/source/examples/04DynamicNuclearPolarisation.ipynb similarity index 78% rename from doc/source/examples/15DynamicNuclearPolarisation.ipynb rename to doc/source/examples/04DynamicNuclearPolarisation.ipynb index 5f02c1219..db4b03ab8 100644 --- a/doc/source/examples/15DynamicNuclearPolarisation.ipynb +++ b/doc/source/examples/04DynamicNuclearPolarisation.ipynb @@ -44,7 +44,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -66,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -89,20 +89,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "LOOP 1 times:\n", - " ->EXEC 3 times\n", - " ->EXEC 3 times\n", - " ->EXEC 3 times\n" - ] - } - ], + "outputs": [], "source": [ "hardware_setup.register_program('dnp', dnp_prog)\n", "hardware_setup.arm_program('dnp')\n", @@ -123,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -139,20 +128,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "LOOP 1 times:\n", - " ->EXEC 3 times\n", - " ->EXEC 1 times\n", - " ->EXEC 5 times\n" - ] - } - ], + "outputs": [], "source": [ "used_awg.run_current_program()\n", "\n", @@ -168,22 +146,11 @@ } ], "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.7.4" + "name": "python" + }, + "nbsphinx": { + "execute": "never" } }, "nbformat": 4, diff --git a/doc/source/examples/04PulseStorage.ipynb b/doc/source/examples/04PulseStorage.ipynb deleted file mode 100644 index 437778796..000000000 --- a/doc/source/examples/04PulseStorage.ipynb +++ /dev/null @@ -1,412 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Storing Pulse Templates: `PulseStorage` and Serialization\n", - "\n", - "So far, we have constructed new pulse templates in code for each session (which were discarded afterwards). We now want to store them persistently in the file system to be able to reuse them in later sessions. For this, qupulse offers us serialization and deserialization using the `PulseStorage` and `StorageBackend` classes.\n", - "\n", - "The pulse storage manages the (de-)serialization to JSON and requires a storage backend to persistently store the serialized data. This can for example be a `FilesystemBackend` or a `DictBackend`. Let us first use a `DictBackend` to inspect the serialized pulse.\n", - "\n", - "__Attention:__ Due to the fact that PulseStorage enforces unique identifiers, executing the cells in this notebook out of order or rerunning them will likely result in errors. You will have to restart the Kernel in that case.\n", - "\n", - "## Single Pulses\n", - "First we will have a look at how to store pulses that do not contain other pulse templates. To store a pulse, __the pulse needs to have an identifier__. If you forgot to give the pulse an identifier one can use the `rename` method which returns a new pulse with the requested identifier.\n", - "\n", - "### Storing" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'my_pulse': '{\\n'\n", - " ' \"#identifier\": \"my_pulse\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.table_pulse_template.TablePulseTemplate\",\\n'\n", - " ' \"entries\": {\\n'\n", - " ' \"default\": [\\n'\n", - " ' [\\n'\n", - " ' \"t_begin\",\\n'\n", - " ' \"v_begin\",\\n'\n", - " ' \"hold\"\\n'\n", - " ' ],\\n'\n", - " ' [\\n'\n", - " ' \"t_end\",\\n'\n", - " ' \"v_end\",\\n'\n", - " ' \"linear\"\\n'\n", - " ' ]\\n'\n", - " ' ]\\n'\n", - " ' },\\n'\n", - " ' \"measurements\": [],\\n'\n", - " ' \"parameter_constraints\": []\\n'\n", - " '}'}\n" - ] - } - ], - "source": [ - "import pprint\n", - "from qupulse.pulses import TablePT\n", - "from qupulse.serialization import PulseStorage, DictBackend\n", - "\n", - "dict_backend = DictBackend()\n", - "dict_pulse_storage = PulseStorage(dict_backend)\n", - "\n", - "table_pulse = TablePT({'default': [('t_begin', 'v_begin', 'hold'),\n", - " ('t_end', 'v_end', 'linear')]}, identifier='my_pulse')\n", - "\n", - "dict_pulse_storage['my_pulse'] = table_pulse\n", - "\n", - "pprint.pprint(dict_backend.storage)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now to store this in a file system we need to replace the `DictBackend` with a `FilesystemBackend`. The following code will create the file `'./serialized_pulses/my_pulse.json'`." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from qupulse.serialization import FilesystemBackend\n", - "\n", - "filesystem_backend = FilesystemBackend('./serialized_pulses')\n", - "file_pulse_storage = PulseStorage(filesystem_backend)\n", - "\n", - "if 'my_pulse' in file_pulse_storage:\n", - " del file_pulse_storage['my_pulse']\n", - "\n", - "file_pulse_storage['my_pulse'] = table_pulse" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Loading\n", - "Now we will load a pulse that is shipped only as a JSON file. It is a single sine with frequency `omega`. Note that loading the same pulse multiple times will give you the same object." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Loading the same pulse multiple times gives you the same object\n" - ] - }, - { - "data": { - "image/png": "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VYXPLVmyhPfff5/Zs2dz/PHHM3LkSOrUqcOLL75Io0aNWLFiBfvuuy/HH388APPmzeOZZ57hoYce4ic/+QnPP/88Z5xxBgDbtm1jypQpjB8/nuuvv56JEyfyyCOP0LhxYz7++GM2b97MAQccwJFHHlliw/eLL77InDlzmDFjBkuXLqVnz56cc845bN26lUsuuYRx48bRokULnn32Wa699loeffRRLrzwQho0aMBvf/tbAB599FGaNm3Kxo0b2XvvvTn55JNp1qxZmftx5MiR3HPPPdx+++3k5eUlvP+TQUVFRLLG22+/zciRI2nevDkATZs2LXzuhBNOoFq1avTs2ZOlS5cCwdHCNddcw6RJk6hWrRrfffdd4XMdO3akf//+AAwaNIiFCxcWbuukk07a5fEJEybw+eefFx4FrVmzhnnz5tG1a9dis06aNInTTjuN6tWr06ZNGw499FAA5syZwxdffMERRxwBBEdArVu3LnYbd911Fy+++CIA3377LfPmzUuoqEQp0qJiZo8CxwLL3H2Xli4L/gS4Ezga2ACMcvdP0ptSRIpT2hFFqrh7iUcGtWvX3mk9gKeffprly5czbdo0atasSYcOHQr7aMSvX7169Z1OEcWeq169Otu2bSvc5t13382wYcN2et/4YlRUcVndnV69ejF58uTSPirvvvsuEydOZPLkydSrV4+hQ4cWZo/fbqaNbhB1m8pjwFGlPD8c6BLeLgDuT0MmEclQhx12GM899xwrV64E2On0V3HWrFlDy5YtqVmzJu+88w6LFlV8dPdhw4Zx//33s3XrVgDmzp3L+vXrS1z/4IMPZsyYMWzfvp0lS5bwzjvvANCtWzeWL19eWFS2bt3KzJkzi83epEkT6tWrx+zZs/nwww8Ln2vVqhWzZs2ioKCg8EimqIYNG7J27doKf96KivRIxd0nmVmHUlYZATzhwZ8dH5rZbmbW2t2XpCWgZDR3Z9HKDSz9cRP1atWgfu3q7NmsPtWrqXNeVdWrVy+uvfZahgwZQvXq1RkwYACPPfZYieuffvrpHHfcceTl5dG/f3+6d+9e4fc+77zzWLhwIQMHDsTdadGiBS+99FKJ65944om8/fbb9OnTh65duzJkyBAAatWqxdixY7n00ktZs2YN27Zt4/LLL6dXr52P/I466igeeOAB+vbtS7du3dh3330Ln7vllls49thjadeuHb1792bdunW7vP+oUaO48MILqVu3LpMnT6Zu3boV/uzlEfkc9WFReaWE01+vALe4+/vh/beAK919apH1LiA4kqF9+/aDKvPXiGS+eUvXctHTnzB/2a7/kQCa1a/FP37an4O7VnoSOyli1qxZ9OjRI+oYUknF/Tua2TR3r3SrfqY31Bf3J+cuVdDdRwOjAfLy8qKtkpIyW7cX0P/6Cazfsr3wsZGD2rL/Xs2oV6sGk+Yt518ffcPK9Vs469EpAHx49WHs3rhOVJFFck6mF5V8oF3c/bZA+nvzSOQ++3Y1I+79X+H9R0flcWj3Vjutc1Tv3bnpxD7MWvIjw+8M+hbse/NbXHt0D84/uFNa84rkqqgb6svyMnCWBfYF1qg9JfeMn7Fkp4Ly9c1H71JQ4vVo3YiFtxxD8wa1ALhx/CyufmFGynPmiqhPmUvlpPrfL9KiYmbPAJOBbmaWb2bnmtmFZnZhuMp4YAEwH3gI+GVEUSUi781bzi+fDq4i7757QxbeckzCo6xO/f0RXDgkGOrimSnfcOOrX6YsZ66oU6cOK1euVGHJUrH5VOrUSd0p4aiv/jqtjOcd+FWa4kiGWfrjJs58JGgb2bdTU8ZcsF+5t3HV8O40q1+LG8fP4qH3vmZg+yYM71N8RzMpW9u2bcnPz2f58uVRR5EKis38mCqZ3qYiOaqgwNnnprcAaNmwdoUKSsz5B3fi2x828MTkRVz09Cd8+ocjaFK/VrKi5pSaNWumbMZAqRoyvU1FclSna8YXLk+59vBKb++GEb1p1SjoJT3gz29WensiUjwVFck4974zv3B5/o3Dk7bdj67ZUZxiV4eJSHKpqEhG2bhlO7e9MQeAp8/bhxrVk/sV/eyPRwIwa8mPfPHdmqRuW0RUVCTD9Pjj6wDssVtdDujcPOnbb1yvJhcNDa4IO/bu95O+fZFcp6IiGeP1L74vXH7/ykNS9j5XHrVj/KfLxnyasvcRyUUqKpIxLnxqGgD3nT4w4b4oFTXlmsMAGDd9MZu2bi9jbRFJlIqKZIQr/v1Z4fLRaehH0rJRHXq0bgRA3+snpPz9RHKFiopEbnuB8+9p+QB8nITLhxM1/tIDAdiyrYBvV21I2/uKVGUqKhK5k+4LxvVq1ag2LRrWLmPt5DEzfhEONHnQX99J2/uKVGUqKhKpzdu281l+cGnvpN+lrnG+JFcfvWNOiVlLfkz7+4tUNSoqEqnj7w6OUvq1243aNapHkuH644MZ99QhUqTyVFQkMlu3FzBnaTCH9gsX7R9ZjrP371C4PHdp+uf0FqlKVFQkMqc/9BEA/dvtFvm88rGjlSP/MSnSHCLZTkVFIuHuTFm4CoDnflHxEYiTJf5oZdnaTdEFEclyKioSiWte/AKAtk3qUqtGZnwNY8O36GhFpOIy43+z5JxnpnwDwKuXHhRxkh1+N6wbAKs3bGXzNvWyF6kIFRVJuxc+yS9cbly3ZoRJdmZmDO3WAoALnpgWcRqR7KSiImn3m+eCIVnGZ9BRSszoM/MA+O9cTZcrUhEqKpJW36zcMRxKzzaNIkxSvFo1qhUePT05eWGkWUSykYqKpNUJ4ZAssUt4M9G4Xx0AwB/GzYw4iUj2UVGRtNle4KxavwXY+RLeTNOhef3C5fgjKxEpm4qKpM2fX/kSgMEdmkacpGyxI6mfjp4ccRKR7KKiImnz2AcLAXjorLxogyTgrP32BGDJmk0UFHjEaUSyh4qKpMXs73eMANy4XuZcRlwSM6NnOInXfe/OjziNSPZQUZG0OOPhYJyvO0/tH3GSxD32870BuH3C3IiTiGQPFRVJuYICZ8W6oIF+RP89Ik6TuJaN6hQuL169McIkItlDRUVS7qH3FgDQr23jiJOU35VHdQfgV//6JOIkItlBRUVS7ubXZgPw4JmZ30Bf1IVDgumGP/1mdcRJRLKDioqk1A9hvxSA3RvXKWXNzGRmtGxYG4A3v1wacRqRzKeiIil1xdhgnK/zD+oYcZKKu/+MQQBcNubTiJOIZD4VFUmpibOWATvaJrLRoD2bALBhy3a2bS+IOI1IZlNRkZSZtSTom1KrejVqVM/ur9rBXYMh8R+ctCDiJCKZLbv/p0tGu3zMdABuO6VvxEkq7/aRwWe47Y05EScRyWwqKpIyc5auBeD4fm0iTlJ58X1WNmzZFmESkcymoiIp8e6coC2lXdO6mFnEaZLj9H3aA3D9y19GnEQkc6moSEr89t/BVV9/OyV7hmUpy7XH9ADg2anfRpxEJHNFWlTM7Cgzm2Nm883sqmKeH2Vmy81seng7L4qcUj7uO4ZlGdwx84e5T1S9WjUKl5ev3RxhEpHMFVlRMbPqwL3AcKAncJqZ9Sxm1WfdvX94ezitIaVCxk1fDEDvPTJvuuDKuvSwLgD84aUvIk4ikpmiPFIZDMx39wXuvgUYA4yIMI8kyR/GBb9wbz+lX8RJku+SQzsD8PrM7yNOIpKZoiwqewDxJ6fzw8eKOtnMPjezsWbWrrgNmdkFZjbVzKYuX748FVklQQUFztpNwdVR3XevekcqNeP62yxZo5GLRYqKsqgUd0lQ0Sn2/gN0cPe+wETg8eI25O6j3T3P3fNatGiR5JhSHmM/yQeyY8rgirrm6GB0AJ0CE9lVlEUlH4g/8mgLLI5fwd1XunusRfQhYFCaskkF/fk/weW2N53UJ+IkqXPugcHIxbEhaERkhyiLysdAFzPraGa1gFOBl+NXMLPWcXePB2alMZ+UU0GBs3ZzcOqrc8sGEadJnerVjGrhcbZOgYnsLLKi4u7bgIuBNwiKxXPuPtPMbjCz48PVLjWzmWb2GXApMCqatJKIl6Z/B1Sty4hLctXw4BSYOkKK7MzcizZjZLe8vDyfOnVq1DFy0sA/v8mq9VuY8OuD6dqqYdRxUmrb9gI6X/saAAtvOSbiNCKVZ2bT3L3SM+mpR70khbuzKpyQq6oXFGCnUZdXrFNHSJEYFRVJignhrIj92+0WcZL0+c0RXQG4JZwuWURUVCRJ/vJq0LZw/fG9Ik6SPhccHFwFNnZafsRJRDKHiookxbergqug+uXQkUqdmtULl3/ctDXCJCKZQ0VFKm3yVysB6Nqq6l5GXJJzDugIwF0T50WcRCQzqKhIpd38WtB96Jqje0ScJP0uOzwYYPLh97+OOIlIZlBRkUr7PH8NAEO7tYw4Sfo1rluzcHnztu0RJhHJDGUWFTOrZmYDzOwYMzvUzFqlI5hkh3nhlMGtG9cpY82q68QBwTioj3+wMNogIhmgxKJiZnuZ2WhgPnALcBrwS+BNM/vQzH5uZjrSyXE3jQ9Off3fkd0iThKd3x0VfPa73pofcRKR6NUo5bm/APcDv/Ai3e7NrCXwM+BMShg5WHLDO3OCqQZOGlDcrAW5oXXjugCs27yNggKnWrXiBuAWyQ0lHmm4+2nuPqloQQmfW+bud7i7CkoOWxn2JK9do1rO/yLdf69mALyhybskx1Xo9JWZ7Z7sIJJ97ggvo71o6F4RJ4ne1cODK99umzAn4iQi0apom8gjSU0hWenJDxcBO3qW57I+bRsDsGD5+oiTiESrQkXF3TUsa47btHXH5bP1apXWNJc7OrWoD8CM8BJrkVyUyCXF7Yu7pSOcZK6nwqOUkwe2jThJ5ogNMHnr6xpgUnJXIn9ivkowd7wBdYCOwBwgd0YOlF3c9+5XAPzmyK4RJ8kcR/duDXzK+/NXRB1FJDJlFhV332mycTMbCPwiZYkk48XPnbLHbnUjTpM5qlUz6teqzvot21mxbjPNG9SOOpJI2pW7TcXdPwH2TkEWyRLvzg36puTt2STiJJnnwiHBlXB3aoBJyVGJtKn8Ju72WzP7F7A8DdkkQ/19wlwgt3vRl+ScA4NRi2NXxonkmkTaVOLnht1G0MbyfGriSDaY8V1wddN+YYc/2aF+7R3/pbZsK6BWDY1kJLklkTaV69MRRLLDt6s2ANCqkdoLSjKifxvGTV/M85/kc9pgXSgpuaWiPeovSHYQyQ7/eDM49XXJoV0iTpK5YpcW3/2W2lUk91T02Dy3B3rKYS98+h0AP8lrF3GSzLVns6AT5OI1myJOIpJ+Fe1R/2Cyg0jm27hlRy96tRWUrlebRgBMXbgq4iQi6ZXQb4Zwgq7fmdkfY7dUB5PM88TkhQBqJ0jA5YcHp8D+Hp4uFMkViVxS/ADwU+ASgtNepwB7pjiXZKCH3lsAwGWHqT2lLIf3CKZW/uCrlREnEUmvRI5U9nf3s4AfwivB9gN0Qj3HuDsr1gW96HfP4amDE2VmNKwTXFy5Ipx3RiQXJFJUNoY/N5hZG2ArwfhfkkNi41kNUi/6hJ13YDAlwD1va5phyR2JFJVXzGw34DbgE2Ah8EwqQ0nmiU3I9evDNYBkos45sAOg3vWSWxLp/PjncPF5M3sFqOPumjAix0xb9AMAB3RWL/pENaxTE4DtBc72Aqd6jk+5LLmhxCMVMzuw6GPuvjlWUMyskZn1TmU4yQxLfwz6WzRvUAsz/WIsj+G9g5m3X/7su4iTiKRHaae/TjazD8JLiI8xs8FmdrCZnWNmTwKvABr3PAfcFfYMP+8gTRtcXpcdHlwpd7faVSRHlHj6y91/bWZNgJEElxG3Jmi0nwU86O7vpyeiRO3pj74B4Kz9dCV5eXXfPegEqbnrJVeU2qbi7j8AD4U3yUHbthcULmsu+orp1Lw+C1asZ97StXRp1bDsF4hkMY21IaWKjfV1fL82ESfJXpcc1hmAOzTApOQAFRUp1b3vBG0Bl6oXfYUd1zcoyK9+viTiJCKpF2lRMbOjzGyOmc03s6uKeb62mT0bPv+RmXVIf8rctmhlMH9K55YNIk6SvWpU3/HfbP3mbREmEUm9RMb+qmdmfzCzh8L7Xczs2Mq+sZlVB+4FhgM9gdPMrGeR1c4lGB6mM/AP4NbKvq8kbvb3PwLQRQWl0mIXOTwxWR0hpWpL5Ejln8BmgjG/APKBvyThvQcD8919gbtvAcYAI4qsMwJ4PFweCxxm6iiRNpc9Mx2AS3Tqq9IuPjRoV3k4HJRTKmfRyvWc+9jHfJ6/OuooUkQiRWUvd/8rwZhfuPtGkjNJ1x7At3H388PHil3H3bcBa4BdunSb2QVmNtXMpi5fvjwJ0QRgWO/d6b1HI47p0zrqKFmvZcNgEM6V67fg7hGnyX5jp+Xz1uxlLF6tidAyTSJFZYuZ1QUcwMz2IjhyqaziClPR/22JrIO7j3b3PHfPa9GiRRKiCQTT4r5yyUEaXiRJ8sLBODUcfuU9+v7XAOzTsWnESaSoRIrKn4DXgXZm9jTwFvC7JLx3PjsPod8WWFzSOmZWA2gMaCo9yUqx3vV3TtSlxZVRUOCsD2chbVK/VsRppKhEBpR808w+AfYlOHK4zN1XJOG9Pwa6mFlH4DvgVOBnRdZ5GTgbmEzQs/9t17kDyVIHdm4OwBRNMVwp/50XnOI+qEvziJNIcRK5+msgwUyPSwiOJNqb2V7hkUOFhW0kFwNvEAz98py7zzSzG8zs+HC1R4BmZjYf+A2wy2XHItnCzGga/mW9bK3aAirqjnCK5ss1DUNGSqQw3AcMBD4nOFLpHS43M7ML3X1CRd/c3ccD44s89se45U0E446JVAnnHNCB2yfM5e635vPnEzTId0V8lh/MvKEJ4zJTIm0qC4EBYUP4IGAA8AVwOPDXFGYTqXJ+fkAwaerTH6m/SkUsXh1MRNuiYe2Ik0hJEikq3d19ZuyOu39JUGR0wb1IOdWvHZwcKPBg8i4pn9g0DL8culfESaQkiRSVOWZ2v5kNCW/3AXPNrDZh3xURSdzRfYKJu174JD/iJNlnzMdB17af7dM+4iRSkkSKyihgPnA58GtgQfjYVuCQVAUTqap+HTYwxwbrlMRs3ra9cLl2jeoRJpHSJHJJ8Ubgb+GtqHVJTyRSxcXmVFkYDtYpiXkuPEo5aUDRgTckkyRySXEXMxtrZl+a2YLYLR3hRKqq2KjPsUE7pWz3v/sVoEuJM12iA0reD2wjON31BPBkKkOJVHWx+Wn+PmFuxEmyx+I1Qd+e9s3qRZxESpNIUanr7m8B5u6L3P064NDUxhKp2mKDdE74cmnESbLDtEXBKAS92jSKOImUJZHOj5vMrBowz8wuJhhSpWVqY4lUbdWrGdUsuLT4x01baVSnZtSRMtrfwiO6yzQNQ8ZL5EjlcqAecCkwCDgDOCuVoURywXkHdQLg4UlqoixLbGTnI3q2ijiJlCWRotLB3de5e767/9zdTwZ0kbhIJcU68D0cDuMuxVu5Lphpo2HtGmiOvsyXSFG5OsHHRKQcdqsXDC65Yct2TdxVirvfDvrzXHBwp4iTSCJKbFMxs+HA0cAeZnZX3FONCK4EE5FKOrhrCybNXc6rM5ZwbN82UcfJSI99sBCAcw7sGG0QSUhpRyqLgWnApvBn7PYyMCz10USqvt8N6wbAHZq4q1hbtxcULsfGTZPMVuK/krt/BnxmZk+Fc5+ISJL13qMxAPOXaXCK4jw/LRgf7Zi+rSNOIokq7fTXDHbMS7/L8+7eN3WxRHLHns3qsWjlBuYuXUvXcAgXCcRGJf7tkd0iTiKJKu148ti0pRDJYb85oiuXjZnOX1+fw8Nn50UdJ6PEetF3bF4/4iSSqBLbVMLe84vcfRFBu0qf8LYxfExEkiDWQD9xlnrXx5vyddCLvmdr9aLPJokMKPkTYArBtL4/AT4ys5GpDiaSK6pXM2pUC04xr96wJeI0mePW12cD8NthGkAymyTST+VaYG93P9vdzwIGA39IbSyR3PKLIUEfjDvf0lVgMdMW/QDAId00KlQ2SaSoVHP3ZXH3Vyb4OhFJ0C+Hdgbgn/9bGG2QDPFdOBd90/q11Is+yyRy4ffrZvYG8Ex4/6fA+NRFEsk98X0wtm0voEb13P677bbw1Nclh3aOOImUV5nfXHe/AngQ6Av0A0a7+5WpDiaSa44N+2I8/dE3ESeJ3kvTFwOaiz4blVhUzOweM9sfwN1fcPffuPuv3f3F9MUTyR1XHtUdULvK2k1bC5c1F332Ke1IZR7wNzNbaGa3mln/dIUSyUXtmgYzGq5avyWnB5i8951g2uBR+3eINohUSGn9VO509/2AIcAq4J9mNsvM/mhmusZPJAUGd2gKwJs5PCPkA/+NzUWvCbmyUSJtKovc/VZ3HwD8DDgRmJXyZCI56JpjegBwy2uzI04SjfgBJGNTA0h2SaTzY00zO87MngZeA+YCJ6c8mUgO6t9uNwAWrFgfcZJoPP1hMFjHMX00gGS2Kq2h/ggzexTIBy4guIx4L3f/qbu/lK6AIrkmNs7V9G9XR5wk/WJz0V81vHvESaSiSjtSuQaYDPRw9+Pc/Wl3z80/n0TS6PfhKbDrXp4ZcZL0Kihw1m4OZtmIXbQg2ae0+VQOSWcQEQkc2j0YliTXjlT+83nQN2Wfjk0jTiKVkdvddkUykJnRvEHQSD1/2dqI06TPzeODixP+dFyviJNIZaioiGSgq4YHp8Cu/8+XESdJD3fn+x/tpmtoAAARUElEQVSDuVN6ttFQ99lMRUUkA500YA8A3pu3IuIk6TFxVjBmbe89VFCynYqKSAaqVs1oEA4y+c3KDRGnSb0/vxIckV1/vE59ZTsVFZEMdWV4We0fX/4i4iSp982qoHAO2lON9NkukqJiZk3N7E0zmxf+bFLCetvNbHp4ezndOUWidPrgYITed+csjzhJar09OxiSpvvuDSNOIskQ1ZHKVcBb7t4FeCu8X5yN7t4/vB2fvngi0atWzahbMxil99tVVfcU2HUvB6e+bhjRO+IkkgxRFZURwOPh8uPACRHlEMlosbHArnlxRsRJUsPdC099DVb/lCohqqLSyt2XAIQ/S5qEuo6ZTTWzD82sxMJjZheE601dvrxqnyqQ3BI7BVZVrwKbEI7G3KO1rvqqKhKZTrhCzGwisHsxT11bjs20d/fFZtYJeNvMZrj7V0VXcvfRwGiAvLy83J2IQqqc2FVg6zZvY/6ydXRu2SDqSEn1+5eCixBuPFGnvqqKlB2puPvh7t67mNs4YKmZtQYIfy4rYRuLw58LgHeBAanKK5Kp/nRcTwCuGPtZxEmSy91ZvnYzAAPbF3utjmShqE5/vQycHS6fDYwruoKZNTGz2uFyc+AAIDe6F4vEGTmoLQCfflO1xgIbOy0f2DHcv1QNURWVW4AjzGwecER4HzPLM7OHw3V6AFPN7DPgHeAWd1dRkZxjZjSrH4wF9sk3P0ScJnmufiG4+OCvI/tGnESSKZKi4u4r3f0wd+8S/lwVPj7V3c8Llz9w9z7u3i/8+UgUWUUywe2n9APgkn99GnGS5Ni6vYBtBUHzZ9dW6p9SlahHvUgWOCQcDv+71Rtxz/5rUe5+ax6wY5h/qTpUVESyROzKr3HTF0ecpPLuens+ALeerFNfVY2KikiWuO/0gQD89t/ZfRXY6g1bCpdbNKwdYRJJBRUVkSwRa3vYVuBs3V4QcZqKu+r5oIH+goM7RZxEUkFFRSSLHN0n6E9846uzIk5Sca/P/B6A/zuya8RJJBVUVESyyM0nBW0Qj32wMNogFTT926CvTTWD2jWqR5xGUkFFRSSLNK5bs3A5G0cuvvDJaQDc87OBESeRVFFREckyN4wIZkc857GPI05SPgUFO+ahP7pP64jTSKqoqIhkmTP33ROAecvWZVWflTvCvikD22tYlqpMRUUky5gZ7ZrWBeCpj76JOE3i7gqLyv1nDIo4iaSSiopIFnrq3H0A+MNL2TF//cIV6wuXWzWqE2ESSTUVFZEstGez+oXLS9ZsjDBJYk5/+CMArguH8ZeqS0VFJEv93xFBP4/TH/oo4iSlKyhwvlsdFL6z9+8QbRhJORUVkSx18aGdAViwYj0FBZnbYH/DK8GMFf3a7YaZRZxGUk1FRSRLmRldwkEmbxqfuT3sYx01Hxu1d7RBJC1UVESy2JgL9gXg4fe/jjhJ8d6Zs2Om8CbhRGNStamoiGSxZg12jPI78culESYp3s//GXTQfPq8fSJOIumioiKS5WJHK+c9MTXiJDuLH0bmgM7NI0wi6aSiIpLl9u3UrHB5/rJ1ESbZ2WF/+y8AVx7VPeIkkk4qKiJVQKz/x+F//2/ESQI/btrKlnDOl4uG7hVxGkknFRWRKmDUAR0Ll5eGgzZG6ci/TwLgpAF7RJxE0k1FRaSK+EU4k+K+N78VaY4NW7YVjkZ8+yn9Is0i6aeiIlJFXDU8aLtwh2URHq0cHralHNKtBdWqqbNjrlFREakizIxR4TAog2+K5mhl7aatLF4TFLRHzlZnx1ykoiJShVx3fK/C5SiuBOt7/QQAhvVqpaOUHKWiIlLFXDGsG5D+K8EWrlhPbM6wBzRnSs5SURGpYn51SOfC5XHTv0vb+w69/d3w/ffSwJE5TEVFpAp67OdBe8ZlY6anZcrhZ6bsmIHyimHq7JjLVFREqqCh3VoWLp98/wcpfS935+oXZgDwzPn7pvS9JPOpqIhUUZ9fdyQAn3yzmkUr15exdsXFGucB9turWSlrSi5QURGpohrVqckpg9oCMOS2d1NyGuzt2UtZu2kbAHP/Mjzp25fso6IiUoXdFtej/dC/JfdqsC3bCjjnsWBk5OuO60mtGvp1IioqIlXe9D8eAcDXK9bzr4++KWPtxHX9/WuFy/Fjj0luU1ERqeJ2q1eL68NOkde8OIMFyyvfKXLfuB77X998dKW3J1WHiopIDjh7/w70atMICE6Drd6wpcLb+vk/pxQOGDnlmsPUJ0V2oqIikiNevfSgwuX+N7xZoUEnTxv9Ie/MWQ4EfWFaNqqTtHxSNaioiOSQhbccU7g8+Ka3ytXjvsNVrzJ5wUoA/nZKv536wojERFJUzOwUM5tpZgVmllfKekeZ2Rwzm29mV6Uzo0hVtfCWY6geDvZ42ZjpXDbmU7YXlHy58awlP9LhqlcL7z957mBODi9VFinK0jGEwy5vatYDKAAeBH7r7lOLWac6MBc4AsgHPgZOc/cvS9t2Xl6eT526y+ZEpIibxs9i9KQFhfcP6tKccw/sSIdm9dmwZTuT5i3nrrfmsWHL9sJ1vrh+GA1q14girqSYmU1z9xL/yE9UJN8Od58FlNXANxiY7+4LwnXHACOAUouKiCTmmqN78Lth3bj6hRn8e1o+781bwXvzVuyyXv1a1bnvjEEM6doigpSSbTL5T449gG/j7ucD+xS3opldAFwA0L59+9QnE6kialSvxm2n9OO2U/ox5/u1fPrND5hB3Vo1qF2jGgd0bq4jEymXlH1bzGwisHsxT13r7uMS2UQxjxV7rs7dRwOjITj9lXBIESnUbfeGdNu9YdQxJMulrKi4++GV3EQ+0C7ufltgcSW3KSIiKZTJlxR/DHQxs45mVgs4FXg54kwiIlKKqC4pPtHM8oH9gFfN7I3w8TZmNh7A3bcBFwNvALOA59x9ZhR5RUQkMVFd/fUi8GIxjy8Gjo67Px4Yn8ZoIiJSCZl8+ktERLKMioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCSNioqIiCRNJHPUp5KZrQXmRJ0jAc2BXeduzTzKmVzKmVzZkDMbMgJ0c/dKz9JWFecJnePueVGHKIuZTVXO5FHO5FLO5MmGjBDkTMZ2dPpLRESSRkVFRESSpioWldFRB0iQciaXciaXciZPNmSEJOWscg31IiISnap4pCIiIhFRURERkaTJyqJiZk3N7E0zmxf+bFLCetvNbHp4eznu8Y5m9lH4+mfNrFZUOc2sv5lNNrOZZva5mf007rnHzOzruM/QP8n5jjKzOWY238yuKub52uH+mR/urw5xz10dPj7HzIYlM1cFcv7GzL4M999bZrZn3HPFfgciyDjKzJbHZTkv7rmzw+/IPDM7O1UZE8z5j7iMc81sddxzadmX4Xs9ambLzOyLEp43M7sr/Byfm9nAuOfSsj8TyHh6mO1zM/vAzPrFPbfQzGaE+zIpl/JWIudQM1sT92/7x7jnSv2+FMvds+4G/BW4Kly+Cri1hPXWlfD4c8Cp4fIDwEVR5QS6Al3C5TbAEmC38P5jwMgUZasOfAV0AmoBnwE9i6zzS+CBcPlU4NlwuWe4fm2gY7id6hHmPASoFy5fFMtZ2ncggoyjgHuKeW1TYEH4s0m43CSqnEXWvwR4NJ37Mu69DgYGAl+U8PzRwGuAAfsCH0WwP8vKuH/svYHhsYzh/YVA8wzZl0OBVyr7fYndsvJIBRgBPB4uPw6ckOgLzcyAQ4GxFXl9OZWZ093nuvu8cHkxsAxokaI88QYD8919gbtvAcaEeePF5x8LHBbuvxHAGHff7O5fA/PD7UWS093fcfcN4d0PgbYpylLhjKUYBrzp7qvc/QfgTeCoDMl5GvBMirKUyt0nAatKWWUE8IQHPgR2M7PWpHF/lpXR3T8IM0A038tYjrL2ZUkq9L3O1qLSyt2XAIQ/W5awXh0zm2pmH5pZ7Bd6M2C1u28L7+cDe0ScEwAzG0zwF8FXcQ/fGB4+/8PMaicx2x7At3H3i9sPheuE+2sNwf5L5LXpzBnvXIK/YGOK+w4kW6IZTw7/LceaWbtyvjYZEn6v8BRiR+DtuIfTsS8TVdJnSef+LI+i30sHJpjZNDO7IKJM8fYzs8/M7DUz6xU+VqF9mbHDtJjZRGD3Yp66thybae/ui82sE/C2mc0AfixmvQpfV52knIR/ZT0JnO3uBeHDVwPfExSa0cCVwA0VzVr0LYt5rOh+KGmdRF6bLAm/l5mdAeQBQ+Ie3uU74O5fFff6FGf8D/CMu282swsJjgAPTfC1yVKe9zoVGOvu2+MeS8e+TFQmfDcTYmaHEBSVA+MePiDcly2BN81sdnhEEYVPgD3dfZ2ZHQ28BHShgvsyY49U3P1wd+9dzG0csDT8JRz7ZbyshG0sDn8uAN4FBhAM7LabmcUKaltgcZQ5zawR8Crw+/BQPrbtJeHh/WbgnyT3FFM+0C7ufnH7oXCdcH81JjiMTuS16cyJmR1OUMiPD/cXUOJ3IO0Z3X1lXK6HgEGJvjadOeOcSpFTX2nal4kq6bOkc3+Wycz6Ag8DI9x9ZezxuH25DHiR1J0+LpO7/+ju68Ll8UBNM2tORfdlqhuJUnEDbmPnBvC/FrNOE6B2uNwcmEfYyAT8m50b6n8ZYc5awFvA5cU81zr8acAdwC1JzFaDoBGzIzsa4XoVWedX7NxQ/1y43IudG+oXkLqG+kRyDiA4Zdgl0e9ABBlbxy2fCHwYLjcFvg6zNgmXm0a1L8P1uhE0JFu692WRHB0ouXH5GHZuqJ+S7v2ZQMb2BO2N+xd5vD7QMG75A+CoCPfl7rF/a4Li9k24XxP6vuyyvVR+kBTuoGYEv4jnhT+bho/nAQ+Hy/sDM8IdMQM4N+71nYAp4T/4v2P/WSLKeQawFZged+sfPvd2mP0L4CmgQZLzHQ3MJfiFfG342A0Ef+0D1An3z/xwf3WKe+214evmAMNT/O9dVs6JwNK4/fdyWd+BCDLeDMwMs7wDdI977TnhPp4P/DzKfRnev44if8Ckc1+G7/cMwZWQWwn+Yj4XuBC4MHzegHvDzzEDyEv3/kwg48PAD3Hfy6nh453C/fhZ+J24NuJ9eXHcd/ND4opgcd+Xsm4apkVERJImY9tUREQk+6ioiIhI0qioiIhI0qioiIhI0qioiIhI0qioiMQxs2Zxo7V+b2bfxd3/IEXvOcDMHq7ga8eYWZdkZxKpKF1SLFICM7uOYGTe21P8Pv8G/uLun1XgtUOAM9z9/OQnEyk/HamIJMjM1oU/h5rZf83suXDOkVvCuTOmhHNk7BWu18LMnjezj8PbAcVssyHQN1ZQzOy6cP6Ld81sgZldGj5e38xeDQf9+8J2zLvzHnB43LBDIpHSF1GkYvoBPQjGQltAMELCYDO7jGAeksuBO4F/uPv7ZtYeeCN8Tbw8ghET4nUnmCOmITDHzO4nGL59sbsfA2BmjQHcvcDM5od5piX/Y4qUj4qKSMV87OG0Bmb2FTAhfHwGQUEAOBzoGUxBA0AjM2vo7mvjttMaWF5k2696MPjkZjNbBrQKt3u7md1KMKHSe3HrLyOY4E1FRSKnoiJSMZvjlgvi7hew4/9VNWA/d99YynY2EoyxVtK2twM13H2umQ0iGIvpZjOb4O6xaRDqhNsRiZzaVERSZwLBYH0AmFn/YtaZBXQua0Nm1gbY4O5PAbcTTA8b05VgQECRyOlIRSR1LgXuNbPPCf6vTSIYHbaQu882s8bFnBYrqg9wm5kVEIw2exGAmbUCNsZOxYlETZcUi0TMzH4NrHX3cvdVCV/7o7s/kvxkIuWn018i0bufndtRymM1wdTEIhlBRyoiIpI0OlIREZGkUVEREZGkUVEREZGkUVEREZGkUVEREZGk+X9E7ZcWw3+AuwAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib inline\n", - "import math\n", - "from qupulse.pulses.plotting import plot as plot\n", - "\n", - "sine = file_pulse_storage['my_other_pulse']\n", - "\n", - "_ = plot(sine, {'omega': 2*math.pi}, sample_rate=1000, show=False)\n", - "\n", - "if sine is file_pulse_storage['my_other_pulse']:\n", - " print('Loading the same pulse multiple times gives you the same object')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Composed pulses and the role of identifiers\n", - "If we have a pulse that contains other pulses all pulses that have an identifier are stored seperatly. Each `PulseStorage` instance expects that identifiers are unique (see below). Anonymous subpulses are stored together with their parent.\n", - "\n", - "We will now only use a dictionary as a backend it is easier to see what happens.\n", - "\n", - "### Storing" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'combined': '{\\n'\n", - " ' \"#identifier\": \"combined\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.sequence_pulse_template.SequencePulseTemplate\",\\n'\n", - " ' \"subtemplates\": [\\n'\n", - " ' {\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.repetition_pulse_template.RepetitionPulseTemplate\",\\n'\n", - " ' \"body\": {\\n'\n", - " ' \"#identifier\": \"my_other_pulse\",\\n'\n", - " ' \"#type\": \"reference\"\\n'\n", - " ' },\\n'\n", - " ' \"repetition_count\": \"N_sine\"\\n'\n", - " ' },\\n'\n", - " ' {\\n'\n", - " ' \"#identifier\": \"my_pulse\",\\n'\n", - " ' \"#type\": \"reference\"\\n'\n", - " ' }\\n'\n", - " ' ]\\n'\n", - " '}',\n", - " 'my_other_pulse': '{\\n'\n", - " ' \"#identifier\": \"my_other_pulse\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.function_pulse_template.FunctionPulseTemplate\",\\n'\n", - " ' \"channel\": \"default\",\\n'\n", - " ' \"duration_expression\": \"2*pi/omega\",\\n'\n", - " ' \"expression\": \"sin(omega*t)\",\\n'\n", - " ' \"measurements\": [],\\n'\n", - " ' \"parameter_constraints\": []\\n'\n", - " '}',\n", - " 'my_pulse': '{\\n'\n", - " ' \"#identifier\": \"my_pulse\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.table_pulse_template.TablePulseTemplate\",\\n'\n", - " ' \"entries\": {\\n'\n", - " ' \"default\": [\\n'\n", - " ' [\\n'\n", - " ' \"t_begin\",\\n'\n", - " ' \"v_begin\",\\n'\n", - " ' \"hold\"\\n'\n", - " ' ],\\n'\n", - " ' [\\n'\n", - " ' \"t_end\",\\n'\n", - " ' \"v_end\",\\n'\n", - " ' \"linear\"\\n'\n", - " ' ]\\n'\n", - " ' ]\\n'\n", - " ' },\\n'\n", - " ' \"measurements\": [],\\n'\n", - " ' \"parameter_constraints\": []\\n'\n", - " '}'}\n" - ] - } - ], - "source": [ - "from qupulse.pulses import RepetitionPT, SequencePT\n", - "\n", - "# anonymous pulse template\n", - "repeated_sine = RepetitionPT(sine, 'N_sine')\n", - "\n", - "my_sequence = SequencePT(repeated_sine, table_pulse, identifier='combined')\n", - "\n", - "dict_pulse_storage['combined'] = my_sequence\n", - "\n", - "pprint.pprint(dict_backend.storage)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you see, the serialization of 'combined' explicitly contains the anonymous `RepetitionPulseTemplate` but references to 'my_pulse' and 'my_other_pulse' which are stored as separate entries.\n", - "\n", - "## Pulse registry and unique identifiers\n", - "There is the possibility to store pulse templates on construction into a pulse registry. This can be a `PulseStorage`. To set a pulse storage as the default pulse registry call `set_to_default_registry`" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'combined': '{\\n'\n", - " ' \"#identifier\": \"combined\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.sequence_pulse_template.SequencePulseTemplate\",\\n'\n", - " ' \"subtemplates\": [\\n'\n", - " ' {\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.repetition_pulse_template.RepetitionPulseTemplate\",\\n'\n", - " ' \"body\": {\\n'\n", - " ' \"#identifier\": \"my_other_pulse\",\\n'\n", - " ' \"#type\": \"reference\"\\n'\n", - " ' },\\n'\n", - " ' \"repetition_count\": \"N_sine\"\\n'\n", - " ' },\\n'\n", - " ' {\\n'\n", - " ' \"#identifier\": \"my_pulse\",\\n'\n", - " ' \"#type\": \"reference\"\\n'\n", - " ' }\\n'\n", - " ' ]\\n'\n", - " '}',\n", - " 'my_other_pulse': '{\\n'\n", - " ' \"#identifier\": \"my_other_pulse\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.function_pulse_template.FunctionPulseTemplate\",\\n'\n", - " ' \"channel\": \"default\",\\n'\n", - " ' \"duration_expression\": \"2*pi/omega\",\\n'\n", - " ' \"expression\": \"sin(omega*t)\",\\n'\n", - " ' \"measurements\": [],\\n'\n", - " ' \"parameter_constraints\": []\\n'\n", - " '}',\n", - " 'my_pulse': '{\\n'\n", - " ' \"#identifier\": \"my_pulse\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.table_pulse_template.TablePulseTemplate\",\\n'\n", - " ' \"entries\": {\\n'\n", - " ' \"default\": [\\n'\n", - " ' [\\n'\n", - " ' \"t_begin\",\\n'\n", - " ' \"v_begin\",\\n'\n", - " ' \"hold\"\\n'\n", - " ' ],\\n'\n", - " ' [\\n'\n", - " ' \"t_end\",\\n'\n", - " ' \"v_end\",\\n'\n", - " ' \"linear\"\\n'\n", - " ' ]\\n'\n", - " ' ]\\n'\n", - " ' },\\n'\n", - " ' \"measurements\": [],\\n'\n", - " ' \"parameter_constraints\": []\\n'\n", - " '}',\n", - " 'new_pulse': '{\\n'\n", - " ' \"#identifier\": \"new_pulse\",\\n'\n", - " ' \"#type\": '\n", - " '\"qupulse.pulses.function_pulse_template.FunctionPulseTemplate\",\\n'\n", - " ' \"channel\": \"default\",\\n'\n", - " ' \"duration_expression\": 1,\\n'\n", - " ' \"expression\": 0,\\n'\n", - " ' \"measurements\": [],\\n'\n", - " ' \"parameter_constraints\": []\\n'\n", - " '}'}\n" - ] - } - ], - "source": [ - "from qupulse.pulses import FunctionPT\n", - "\n", - "dict_pulse_storage.set_to_default_registry()\n", - "\n", - "new_pulse = FunctionPT(0, 1, identifier='new_pulse')\n", - "\n", - "pprint.pprint(dict_backend.storage)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you see each newly created pulse is put into the pulse storage. Creating a new pulse with the same name will fail:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Oh No!!!\n", - "('Pulse with name already exists', 'new_pulse')\n", - "\n" - ] - } - ], - "source": [ - "try:\n", - " new_pulse = FunctionPT(0, 1, identifier='new_pulse')\n", - "except RuntimeError as err:\n", - " print('Oh No!!!')\n", - " print(err)\n", - " print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We have to either explicitly overwrite the registry or delete the old pulse from it:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Overwriting the registry works!\n", - "Deleting the pulse works, too!\n" - ] - } - ], - "source": [ - "try:\n", - " new_pulse = FunctionPT(0, 1, identifier='new_pulse', registry=dict())\n", - "except:\n", - " raise\n", - "else:\n", - " print('Overwriting the registry works!')\n", - "\n", - "del dict_pulse_storage['new_pulse']\n", - "try:\n", - " new_pulse = FunctionPT(0, 1, identifier='new_pulse')\n", - "except:\n", - " raise\n", - "else:\n", - " print('Deleting the pulse works, too!')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/doc/source/examples/04ZurichInstrumentsSetup.ipynb b/doc/source/examples/04ZurichInstrumentsSetup.ipynb new file mode 100644 index 000000000..ada1e39fe --- /dev/null +++ b/doc/source/examples/04ZurichInstrumentsSetup.ipynb @@ -0,0 +1,458 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7e31fbc9f47a77ce", + "metadata": { + "collapsed": false + }, + "source": [ + "# Zurich Instruments Hardware Setup\n", + "\n", + "This notebook shows an exemplary use of qupulse with a ZI HDAWG and MFLI. The drivers for these instruments are kept in external packages to facilitate easy driver customization. Depending on your python version and hardware version you either need `qupulse-hdawg-legacy` or `qupulse-hdawg` for the HDAWG and `qupulse-mfli` for the MFLI.\n", + "\n", + "## Connections and wiring\n", + "\n", + "The example here assumes a very nonsensical wiring that does not require anything else besides an HDAWG, and MFLI and three cables/adapters to connect SMB to BNC ports. We assume the following connections:\n", + "\n", + "```\n", + "HDAWG_1_WAVE -> MFLI_AUX_IN_1\n", + "HDAWG_2_WAVE -> MFLI_AUX_IN_2\n", + "HDAWG_1_MARK_FRONT -> MFLI_TRIG_IN_1\n", + "```\n", + "`MFLI_TRIG_IN_1` is located on the back of the device.\n", + "\n", + "## Hardware Setup\n", + "\n", + "The hardware setup class provides a layer to map output channels to an arbitrary number of physical channels.\n", + "It also provides a mapping of measurement windows to specific dac instruments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6432f1ccf75c7d58", + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.hardware.setup import HardwareSetup\n", + "\n", + "hw_setup = HardwareSetup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "initial_id", + "metadata": {}, + "outputs": [], + "source": [ + "# This abstracts over possibly installed hdawg drivers\n", + "from qupulse.hardware.awgs.zihdawg import HDAWGRepresentation\n", + "\n", + "awg_serial = 'DEVXXXX'\n", + "assert awg_serial != 'DEVXXXX', \"Please enter the serial of a connected HDAWG\"\n", + "\n", + "hdawg = HDAWGRepresentation(awg_serial, 'USB' )" + ] + }, + { + "cell_type": "markdown", + "id": "4f15ba19d0961dbb", + "metadata": { + "collapsed": false + }, + "source": [ + "### Channel groupings\n", + "\n", + "The `AWG` class abstracts over a set of dependently programmable channels. The HDAWG supports multiple channel groupings which decouples individual channel groups. The most robust setting for qupulse is to use the `1x8` channel grouping which executes the same sequencing program on all channels and only differs in the waveform data that is sequenced. This results in a single channel tuple/`AWG` object which represents all eight channels.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb9a838c161c244d", + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.hardware.awgs.zihdawg import HDAWGChannelGrouping\n", + "from qupulse.hardware.setup import PlaybackChannel, MarkerChannel\n", + "\n", + "hdawg.channel_grouping = HDAWGChannelGrouping.CHAN_GROUP_1x8\n", + "awg, = hdawg.channel_tuples\n", + "\n", + "# here we assume plunger one and two are connected to the two first channels of the AWG\n", + "# It is considered best practice to use such names that relate to the connected sample gates\n", + "hw_setup.set_channel('P1', PlaybackChannel(awg, 0))\n", + "hw_setup.set_channel('P2', PlaybackChannel(awg, 1))\n", + "\n", + "# We connect the trigger to the marker output of the first channel\n", + "hw_setup.set_channel('Trig', MarkerChannel(awg, 0))\n", + "\n", + "# We can assign the same channel to multiple identifiers. Here we just assign all channels to a hardware name\n", + "for channel_idx, channel_letter in enumerate('ABCDEFGH'):\n", + " channel_name = f\"{hdawg.serial}_{channel_letter}\"\n", + " hw_setup.set_channel(channel_name, PlaybackChannel(awg, channel_idx), allow_multiple_registration=True)\n", + "\n", + "# We can also assign multiple channels to the same identifier\n", + "hw_setup.set_channel(f\"{hdawg.serial}_ALL\", [PlaybackChannel(awg, idx) for idx in range(8)], allow_multiple_registration=True)" + ] + }, + { + "cell_type": "markdown", + "id": "10ada657dd098fc7", + "metadata": { + "collapsed": false + }, + "source": [ + "### MFLI\n", + "\n", + "Next we will connect the MFLI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99e3edfcdf4ff697", + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse_mfli.mfli import MFLIDAQ, postprocessing_average_within_windows\n", + "\n", + "mfli_serial = 'DEVXXXX'\n", + "assert mfli_serial != 'DEVXXXX', \"Please enter the serial of a connected MFLI\"\n", + "\n", + "mfli = MFLIDAQ.connect_to(mfli_serial)" + ] + }, + { + "cell_type": "markdown", + "id": "bf2a9ed85290c479", + "metadata": { + "collapsed": false + }, + "source": [ + "### Measurement masks\n", + "\n", + "qupulse has multiple layers where measurements are mapped. The hardware setup can map measurement windows to potentially multiple measurement masks, which are a combination of an instrument and an instrument specific identifier." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6afb0d40c704a02", + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.hardware.setup import MeasurementMask\n", + "\n", + "hw_setup.set_measurement('SET1', MeasurementMask(mfli, 'AverageAux1'))\n", + "hw_setup.set_measurement('SET2', MeasurementMask(mfli, 'AverageAux2'))\n", + "hw_setup.set_measurement('SET_ALL', [MeasurementMask(mfli, 'AverageAux1'), MeasurementMask(mfli, 'AverageAux2')], allow_multiple_registration=True)\n" + ] + }, + { + "cell_type": "markdown", + "id": "e7353faf52ebd31d", + "metadata": {}, + "source": [ + "Each instrument can do arbitrary things with the identifier from the mask which heavily depends on what the instrument can do and what you use it for.\n", + "\n", + "The MLFI maps the names to internal paths following your configuration. You can make the configuration global or program specific." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c943fb4d", + "metadata": {}, + "outputs": [], + "source": [ + "# linking the measurement mask names to physical input channels\n", + "mfli.register_measurement_channel(program_name=None, channel_path=\"demods/0/sample.AuxIn0\", window_name=\"AverageAux2\")\n", + "mfli.register_measurement_channel(program_name=None, channel_path=\"auxins/0/sample.AuxIn1\", window_name=\"AverageAux1\")" + ] + }, + { + "cell_type": "markdown", + "id": "9bb6bf76c80276e9", + "metadata": {}, + "source": [ + "The other inputs can be addressed via strings as the following:\n", + "```\n", + "{\n", + " \"R\": [\"demods/0/sample.R\"],\n", + " \"X\": [\"demods/0/sample.X\"],\n", + " \"Y\": [\"demods/0/sample.Y\"],\n", + " \"A\": [\"auxins/0/sample.AuxIn0.avg\"],\n", + " \"many\": [\"demods/0/sample.R\", \"auxins/0/sample.AuxIn0.avg\", \"demods/0/sample.X\", \"demods/0/sample.Y\"]\n", + "}\n", + "```\n", + "where the keys of the dict are the values for the window_name, and the values of the dict are the channel_path inputs. Note that these can also be lists to record multiple channels under one name. I.e. for IQ demodulation.\n", + "\n", + "### Operations\n", + "\n", + "Each driver can automatically perform certain operations on the recorded data. The MFLI expects a callable that processes the raw data returned by the instrument. This is suboptimal but the current solution. If you want to implement your own operation look at the shipped postprocessing functions for the signature.\n", + "\n", + "There are other functions you can use defined in the mfli package like `postprocessing_crop_windows`. Please file an issue if this documentation here is out of date." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51401e51", + "metadata": {}, + "outputs": [], + "source": [ + "# configuring the driver to average all datapoint for each window.\n", + "mfli.register_operations(\n", + " program_name=None,\n", + " operations=postprocessing_average_within_windows\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ee6314ed25574b8f", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "417c4976", + "metadata": {}, + "outputs": [], + "source": [ + "# registering trigger settings for a standard configuration\n", + "# The measurement is perfomed once after one trigger on TrigIn1 is observed.\n", + "mfli.register_trigger_settings(program_name=None,\n", + " trigger_input=f\"demods/0/sample.TrigIn1\", # here TrigInN referrers to the printer label N\n", + " edge=\"rising\",\n", + " trigger_count=1,\n", + " level=.5,\n", + " measurement_count=1,\n", + " other_settings={\"holdoff/time\": 1e-3}\n", + " ) " + ] + }, + { + "cell_type": "markdown", + "id": "a7c5b77d781b5ab2", + "metadata": { + "collapsed": false + }, + "source": [ + "## Pulse definition\n", + "\n", + "Next we define a pulse that we want to use. We settle for a two-dimensional scan of a voltage space but we define the scan in terms of virtual gates, i.e. the potentials that the quantum dots `Q1` and `Q2` see.\n", + "Then we provide a linear transformation that maps them to the output voltages `P1` and `P2`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27610ca4eb6cda25", + "metadata": {}, + "outputs": [], + "source": [ + "from qupulse.pulses import *\n", + "import numpy as np\n", + "from qupulse.program.transformation import LinearTransformation\n", + "from qupulse.program.loop import Loop, LoopBuilder, roll_constant_waveforms\n", + "\n", + "awg_sample_rate = 10**9\n", + "hdawg.set_sample_clock(awg_sample_rate)\n", + "\n", + "pt = (ConstantPT(2**20, {\n", + " 'Q1': '-0.1 + x_i * 0.02',\n", + " 'Q2': '-0.2 + y_i * 0.01'}, measurements=[('meas', 0, 2**20)])\n", + " .with_iteration('x_i', 'N_x')\n", + " .with_iteration('y_i', 'N_y')\n", + " .with_parallel_channels({'Marker': 1}))\n", + "\n", + "trafo = LinearTransformation(np.array([[1., -.1], [-.09, 1.]])*0.5,\n", + " ('Q1', 'Q2'),\n", + " ('P1', 'P2'))\n", + "\n", + "measurement_mapping = {'meas': 'SET_ALL'}\n", + "\n", + "# we chose the default LoopBuilder program builder here as it is the only supported as the time of writing this example \n", + "program: Loop = pt.create_program(parameters={'N_x': 20, 'N_y': 30},\n", + " global_transformation=trafo,\n", + " program_builder=LoopBuilder(),\n", + " measurement_mapping=measurement_mapping,\n", + " channel_mapping={'Marker': 'Trig'})" + ] + }, + { + "cell_type": "markdown", + "id": "cb014734179113dd", + "metadata": {}, + "source": [ + "## HDAWG: Waveform compression and sample rate reduction\n", + "\n", + "The HDAWG has the capability to dynamically reduce the sample rate by a power of two during playback. The driver does this automatically if it detects a compatible waveform that is (piecewise) constant.\n", + "\n", + "However, the current implementation samples all waveforms in the computer memory. We have a lot (N_x * N_y) of very long waveforms which each take 4 MB in computer memory when sampled with 1GHz. For a sufficiently high resolution this will eat up our RAM with constant waveforms. qupulse provides `roll_constant_waveforms` to detect long constant waveforms and roll them into loops **inplace** if possible with the given parameters. This will remove the measurements from the `Loop` program because they cannot be preserved by the logic. Therefore, we extract them beforehand." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "435420307d15bfd2", + "metadata": {}, + "outputs": [], + "source": [ + "# extract measurement positions\n", + "measurements = program.get_measurement_windows(drop=True)\n", + "\n", + "print(f'Single point before rolling: {program[0]!r}')\n", + "\n", + "# Compress program\n", + "roll_constant_waveforms(program, sample_rate=awg_sample_rate / 10**9, waveform_quantum=256, minimal_waveform_quanta=16)\n", + "\n", + "print(f'Single point after rolling: {program[0]!r}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "346dabd84ea976fd", + "metadata": {}, + "outputs": [], + "source": [ + "hw_setup.clear_programs()\n", + "hw_setup.register_program('csd', program, awg.run_current_program, measurements=measurements)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d7d63d18bd6fc25", + "metadata": {}, + "outputs": [], + "source": [ + "hdawg.output(1, True)\n", + "hdawg.output(2, True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "832c501c9082dc5d", + "metadata": {}, + "outputs": [], + "source": [ + "hw_setup.arm_program('csd')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "954f4e09664d073f", + "metadata": {}, + "outputs": [], + "source": [ + "hw_setup.run_program('csd')\n", + "import time; time.sleep(float(program.duration) / 1e9)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4537c8c741597b0", + "metadata": {}, + "outputs": [], + "source": [ + "hdawg.output(1, False)\n", + "hdawg.output(2, False)" + ] + }, + { + "cell_type": "markdown", + "id": "e517992b6a35fc07", + "metadata": { + "collapsed": false + }, + "source": [ + "The data extration is not standardized at the time of writing this example because it heavily depends on your data processing pipeline how the data is handled and where it shall go. qupulse has no functionality to associate a measured value with the value of some parameter that might have been varied during the measurement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "636ea90347e59fe5", + "metadata": {}, + "outputs": [], + "source": [ + "# receaving the recorded data from the MFLI\n", + "\n", + "data = mfli.measure_program(wait=True) # wait=True would wait until the aquisition is finished.\n" + ] + }, + { + "cell_type": "markdown", + "id": "90137bb3a5dd2f22", + "metadata": { + "collapsed": false + }, + "source": [ + "The recorded data is sliced to the measurement windows in the default configuration. Thus ```my_lockin.measure_program``` returns a list (number of measurements) of dicts (the qupulse channels), of dicts (the lockin channels), of lists (the observed trigger), of lists of xarray DataArrays (each DataArray containing the data sliced for one window) or numpy arrays (containing the data resulting from averaging over the windows). I.e. ```returned_data[][][][]``` leads to ether the list of DataArrays or to a numpy array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3aa849c80214139", + "metadata": {}, + "outputs": [], + "source": [ + "data_0 = data[0]\n", + "(average_1,), = data_0['AverageAux1'].values()\n", + "(average_2,), = data_0['AverageAux2'].values()" + ] + }, + { + "cell_type": "markdown", + "id": "fee1a294623c50e8", + "metadata": {}, + "source": [ + "Warning: As the time of writing this example there are problems when no demodulator is used at all. One channel looks like it has a sliding window average. Contribution in fixing that is highly appreciated." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc7de11e789884f2", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plt.plot(average_1, '*')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14c5cd608d2238a3", + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(average_2)" + ] + } + ], + "metadata": { + "nbsphinx": { + "execute": "never" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/source/examples/05MappingTemplate.ipynb b/doc/source/examples/05MappingTemplate.ipynb deleted file mode 100644 index f0de8ed4c..000000000 --- a/doc/source/examples/05MappingTemplate.ipynb +++ /dev/null @@ -1,1074 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Mapping with the MappingPulseTemplate\n", - "\n", - "We will now have a look on how to remap parameters, channel ids and measurements. The definition of measurements is illustrated in [Definition of Measurements](08Measurements.ipynb). The `MappingPulseTemplate` class allows us to take any already existing `PulseTemplate` and specify a mapping for its parameters, channel ids and measurements. \n", - "\n", - "This can be useful for simply renaming things, e.g., to avoid name collisions of parameters or change the name of a channel a pulse should be executed on, but can also be employed to derive the value of certain parameters from other parameters.\n", - "\n", - "## Mapping Parameters" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2*pi/omega\n", - "{'omega', 'a'}\n" - ] - } - ], - "source": [ - "from qupulse.pulses import MappingPT, FunctionPT, SequencePT, AtomicMultiChannelPT\n", - "\n", - "sine = FunctionPT('a*sin(omega*t)', 't_duration')\n", - "\n", - "my_parameter_mapping = dict(t_duration='2*pi/omega', omega='omega', a='a')\n", - "\n", - "single_period_sine = MappingPT(sine, parameter_mapping=my_parameter_mapping)\n", - "\n", - "print(single_period_sine.duration)\n", - "print(single_period_sine.parameter_names)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that we had to give mappings for all parameters, not only for the ones which changed. If we omit some of the encapsulated pulse tempaltes parameters an `MissingMappingException` is raised. This is done to enforce active thinking.\n", - "\n", - "You can, however, allow partial parameter mappings by passing `allow_partial_paramter_mappings=True` to the constructor." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "we expect an exception here:\n", - "MissingMappingException : The template needs a mapping function for parameter(s) {'omega', 'a'}\n", - "\n", - "no exception with allow_partial_parameter_mapping=True\n", - "2*pi/omega\n", - "{'omega', 'a'}\n" - ] - } - ], - "source": [ - "partial_parameter_mapping = dict(t_duration='2*pi/omega')\n", - "print('we expect an exception here:')\n", - "try:\n", - " single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping)\n", - "except Exception as exception:\n", - " print(type(exception).__name__, ':', exception)\n", - "print('')\n", - "\n", - "print('no exception with allow_partial_parameter_mapping=True')\n", - "single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping, allow_partial_parameter_mapping=True)\n", - "print(single_period_sine.duration)\n", - "print(single_period_sine.parameter_names)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Mapping of Channel Ids and Measurement Names\n", - "\n", - "Sometimes it is necessary to rename channels or measurements. Here we see a case where we want to play a sine and a cosine in parallel by using the `AtomicMultiChannelPulseTemplate` (for a more in depth explanation of multi-channel pulse template, see [Multi-Channel Pulses](07MultiChannelTemplates.ipynb)). Of course, this doesn't work as both pulses are by default defined on the 'default' channel." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ChannelMappingException : Channel is defined in subtemplate 1 and subtemplate 2\n" - ] - } - ], - "source": [ - "sine_measurements = [('M', 't_duration/2', 't_duration')]\n", - "sine = FunctionPT('a*sin(omega*t)', 't_duration', measurements=sine_measurements)\n", - "\n", - "cos_measurements = [('M', 0, 't_duration/2')]\n", - "cos = FunctionPT('a*cos(omega*t)', 't_duration', measurements=cos_measurements)\n", - "\n", - "try:\n", - " both = AtomicMultiChannelPT(sine, cos)\n", - "except Exception as exception:\n", - " print(type(exception).__name__, ':', exception)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The solution is to use the `MappingPT` and rename the channels as we see in the next cell. Additionally, we want to distinguish between the measurements, so we rename them, too. " - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "remapped_cos channels: {'cos_channel'}\n", - "remapped_cos measurements: {'M_cos'}\n", - "\n", - "remapped_sine channels: {'sin_channel'}\n", - "remapped_sine measurements: {'M_sin'}\n", - "\n", - "{'sin_channel', 'cos_channel'}\n", - "{'M_cos', 'M_sin'}\n" - ] - } - ], - "source": [ - "cos_channel_mapping = dict(default='cos_channel')\n", - "cos_measurement_mapping = dict(M='M_cos')\n", - "remapped_cos = MappingPT(cos, channel_mapping=cos_channel_mapping, measurement_mapping=cos_measurement_mapping)\n", - "print('remapped_cos channels:', remapped_cos.defined_channels)\n", - "print('remapped_cos measurements:', remapped_cos.measurement_names)\n", - "print()\n", - "\n", - "sine_channel_mapping = dict(default='sin_channel')\n", - "sine_measurement_mapping = dict(M='M_sin')\n", - "remapped_sine = MappingPT(sine, measurement_mapping=sine_measurement_mapping, channel_mapping=sine_channel_mapping)\n", - "print('remapped_sine channels:', remapped_sine.defined_channels)\n", - "print('remapped_sine measurements:', remapped_sine.measurement_names)\n", - "print()\n", - "\n", - "both = AtomicMultiChannelPT(remapped_sine, remapped_cos)\n", - "print(both.defined_channels)\n", - "print(both.measurement_names)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's also plot it to see if it looks like expected with some dummy values for our parameters:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The number of channels in table_template is 2.\n" - ] - } - ], - "source": [ - "from qupulse.pulses import TablePT\n", - "\n", - "table_template = TablePT(identifier='2-channel-table-template',\n", - " entries={'first_channel' : [(0, 0),\n", - " (1, 4),\n", - " ('foo', 'bar'),\n", - " (10, 0)],\n", - " 'second_channel': [(0, 0),\n", - " ('foo', 2.7, 'linear'),\n", - " (9, 'bar', 'linear')]}\n", - " )\n", - "\n", - "# plot it\n", - "%matplotlib notebook\n", - "from qupulse.pulses.plotting import plot\n", - "parameters = dict(\n", - " foo=7,\n", - " bar=-1.3\n", - ")\n", - "_ = plot(table_template, parameters, sample_rate=100)\n", - "print(\"The number of channels in table_template is {}.\".format(table_template.num_channels))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Combining Templates: `AtomicMultiChannelPulseTemplate`\n", - "\n", - "`AtomicMultiChannelPulseTemplate`(`AtomicMultiChannelPT`) allows to compose a multi-channel template out of atomic (i.e., no control flow) templates of equal duration. It allows to reassign channel indices of the channels of its subtemplates. The constructor is similar to the one of `SequencePulseTemplate` and expects subtemplates (including parameter and channel mappings if required).\n", - "\n", - "The following example will combine the two-channel table pulse template `table_template` from above and a function pulse template `function_template` to a three-channel template `template`. We reassign indices such that channel 'rectangle' of the new `template` is channel 'first_channel' and 'triangle' is channel 'second_channel' of `table_template`. Furthermore the parameters get remapped. `function_template` doesn't get changed at all." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The number of channels in sequence_template is 2.\n" - ] - } - ], - "source": [ - "from qupulse.pulses import SequencePT\n", - "\n", - "sequence_template = SequencePT(\n", - " (table_template, dict(foo='1.2 * hugo', bar='hugo ** 2')),\n", - " (table_template, dict(foo='1.2 * hugo', bar='hugo ** 2'), {'first_channel': 'second_channel', \n", - " 'second_channel': 'first_channel'}),\n", - " identifier='2-channel-sequence-template'\n", - ")\n", - "\n", - "plot(sequence_template, dict(hugo=2), sample_rate=100)\n", - "print(\"The number of channels in sequence_template is {}.\".format(sequence_template.num_channels))" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/doc/source/examples/09ParameterConstraints.ipynb b/doc/source/examples/09ParameterConstraints.ipynb deleted file mode 100644 index 95173d4fb..000000000 --- a/doc/source/examples/09ParameterConstraints.ipynb +++ /dev/null @@ -1,928 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Constraining Parameters\n", - "\n", - "Often, it is useful to constrain parameters. Either to be in a specific range or even that some relation between parameters is fulfilled. Many pulse templates allow that and accept `parameter_constraints` as a keyword argument. In this example we look at a simple table pulse that ramps a voltage from `v_a` to `v_b` with the ramp time `t_ramp`." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib notebook\n", - "\n", - "example_values = dict(meas=[0, 0],\n", - " op=[5, -5],\n", - " eps_J=[1, -1],\n", - " ST_plus=[2.5, -2.5],\n", - " S_init=[-1, -1],\n", - " ST_jump=[1, -1],\n", - " max_ramp_speed=0.3,\n", - " \n", - " t_init=5,\n", - " \n", - " t_meas_wait = 1,\n", - " \n", - " t_ST_prep = 10,\n", - " t_op = 20,\n", - " \n", - " t_ST_read = 10,\n", - " t_meas_start = 20,\n", - " t_meas_duration=5,\n", - " \n", - " t_start=0,\n", - " t_step=5,\n", - " N_fid_steps=5, N_repetitions=2)\n", - "\n", - "from qupulse.pulses.plotting import plot\n", - "\n", - "_ = plot(experiment, example_values)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can clearly make out the many repetitions of our basic functionality pulse and also the varying duration between the voltage peaks due to our parameter sweep (as well as the two-fold repetition of the sweep itself).\n", - "\n", - "Let's also quickly plot only a single repetition by setting according parameters for our `experiment` pulse template." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import random\n", - "\n", - "random.seed('Some seed such that numbers generated are predictable')\n", - "parameters = {parameter_name: random.random() * 10 - 5 for parameter_name in all_epsilons}\n", - "\n", - "%matplotlib notebook\n", - "from qupulse.pulses.plotting import plot\n", - "_ = plot(gates[0], parameters)\n", - "_ = plot(gates[1], parameters)\n", - "_ = plot(sequences[1], parameters)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must construct the $S_k'$. For simplicity, we assume that there is only one initialization and one measurement pulse which are defined somehow and define only stubs here. We also define a waiting pulse with a variable length:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# stub for an initialization pulse of length 4\n", - "init = TablePT({0: [(0, 5), (4, 0, 'linear')]})\n", - "\n", - "# stub for a measurement pulse of length 12\n", - "measure = TablePT({0: [(0, 0), (12, 5, 'linear')]})\n", - "\n", - "# a wating pulse\n", - "wait = TablePT({0: [(0, 0), ('wait_duration', 0)]})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For our example, let us assume that we want all $S_k'$ to take 200 ns (since we've chosen the $S_k$ to be rather short). We know that the duration of our gate pulses in nanoseconds is equal to the number of entries in the `TablePulseTemplate` objects (each voltage level is held for one unit of time in the tables which corresponds to $\\Delta t = 1$ ns by convention). Accordingly, the init pulse lasts for 4 ns and the measure pulse for 12 ns. The required length of the wait pulse can then be computed as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[175, 178, 176]\n" - ] - } - ], - "source": [ - "wait_times = []\n", - "desired_time = 200\n", - "\n", - "for m_k in m:\n", - " duration_k = 4 + 12 # init + measurement duration\n", - " for g_ki in m_k:\n", - " duration_k += len(gates[g_ki].entries) # add the number of entries of all gates in the sequence\n", - " wait_time_k = desired_time - duration_k\n", - " wait_times.append(wait_time_k)\n", - " \n", - "print(wait_times)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally we can construct the $S_k'$:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# an identity mapping for all epsilons\n", - "all_epsilons_map = {param_name: param_name for param_name in all_epsilons}\n", - "\n", - "gates_with_init_and_readout = [SequencePT((wait, {'wait_duration': wait_duration}),\n", - " init,\n", - " gate,\n", - " measure)\n", - " for gate, wait_duration in zip(sequences, wait_times)]\n", - "final_sequence = SequencePT(*gates_with_init_and_readout)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us plot $S_1'$ to see whether we've accomplished our goal:" - ] - }, - { - "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", - " fig.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", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "_ = plot(final_sequence, parameters)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we construct a single scanline which just repeats all three sequences over and over again. Since our $S_k'$ are short, we just build a scanline with a duration of 0.6 microseconds. With a duration for each $S_k'$ of 200 ns, we can fit 1'000 repetitions of $S_1' | S_2' | S_3'$ in our scanline. We will, however, not plot our scanline because it will be quite large despite it's short duration." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "from qupulse.pulses import RepetitionPT\n", - "scanline = RepetitionPT(final_sequence, 1000)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [default]", - "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.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/doc/source/examples/13RetrospectiveConstantChannelAddition.ipynb b/doc/source/examples/13RetrospectiveConstantChannelAddition.ipynb deleted file mode 100644 index ad941c8c0..000000000 --- a/doc/source/examples/13RetrospectiveConstantChannelAddition.ipynb +++ /dev/null @@ -1,926 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ParallelConstantChannelPulseTemplate\n", - "One reoccuring problem is to add a constant channel to an already existing possibly complex pulse. The setting in this example requires us to put a trigger pulse before the example pulse written in [10FreeInductionDecayExample](10FreeInductionDecayExample.ipynb). Unfortunately, the trigger pulse has to be played on a seperate marker channel that is not included in the example pulse. Therefore we will add this channel to the pulse with the constant value 0.\n", - "\n", - "Let us start with loading the experiment and defining the trigger pulse" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Defined channels of loaded pulse: {'RFY', 'RFX'}\n", - "Defined channels of trigger pulse: {'RFY', 'Marker', 'RFX'}\n" - ] - } - ], - "source": [ - "from qupulse.pulses import TablePT\n", - "from qupulse.serialization import FilesystemBackend, PulseStorage\n", - "\n", - "pulse_storage = PulseStorage(FilesystemBackend('./serialized_pulses'))\n", - "free_induction_decay = pulse_storage['free_induction_decay']\n", - "print('Defined channels of loaded pulse:', free_induction_decay.defined_channels)\n", - "\n", - "trig_pulse = TablePT({'RFX': [(0, 0), ('t_trig', 0)],\n", - " 'RFY': [(0, 0), ('t_trig', 0)],\n", - " 'Marker': [(0, 1), ('t_trig', 1)]})\n", - "print('Defined channels of trigger pulse:', trig_pulse.defined_channels)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we now try to concatenate the pulses we get an error as they differ in their defined channels." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ValueError('The subtemplates are defined for different channels')\n" - ] - } - ], - "source": [ - "try:\n", - " experiment = trig_pulse @ free_induction_decay\n", - "except ValueError as err:\n", - " print(repr(err))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now add an extra channel with a constant value to the `free_induction_decay` pulse. This allows us to concatenate the pulses." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from qupulse.pulses.multi_channel_pulse_template import ParallelConstantChannelPulseTemplate\n", - "extended_free_induction_decay = ParallelConstantChannelPulseTemplate(free_induction_decay, {'Marker': 0})\n", - "\n", - "experiment = trig_pulse @ extended_free_induction_decay" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Read example parameters from file and plot complete pulse" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "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", - " fig.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 = $('