├── .gitignore
├── LICENSE
├── README.md
├── examples
├── .ipynb_checkpoints
│ ├── advanced baseline processing-checkpoint.ipynb
│ ├── fitting over and undecoupled resonators in refelction-checkpoint.ipynb
│ └── pandas_and_circlefit-checkpoint.ipynb
├── S11.txt
├── S21testdata.s2p
├── advanced baseline processing.ipynb
├── fitting over and undecoupled resonators in reflection.ipynb
├── notch_port_example.py
├── notch_port_example_withGUI.py
├── pandas_and_circlefit.ipynb
├── reflection_port_example.py
├── reflection_port_example_withGUI.py
└── remove_wiggly_baseline_with GUI.py
├── old_discontinued_circlefit
└── Circlefit_V3.1.zip
├── resonator_tools
├── __init__.py
├── calibration.py
├── circlefit.py
├── circuit.py
├── noise.py
└── utilities.py
├── setup.py
└── tests
├── __init__.py
└── resonator_tests.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 |
26 | # PyInstaller
27 | # Usually these files are written by a python script from a template
28 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
29 | *.manifest
30 | *.spec
31 |
32 | # Installer logs
33 | pip-log.txt
34 | pip-delete-this-directory.txt
35 |
36 | # Unit test / coverage reports
37 | htmlcov/
38 | .tox/
39 | .coverage
40 | .coverage.*
41 | .cache
42 | nosetests.xml
43 | coverage.xml
44 | *,cover
45 |
46 | # Translations
47 | *.mo
48 | *.pot
49 |
50 | # Django stuff:
51 | *.log
52 |
53 | # Sphinx documentation
54 | docs/_build/
55 |
56 | # PyBuilder
57 | target/
58 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # resonator_tools
2 |
3 | A small python library to fit complex resonator scattering data.
4 | It supports transmission, reflection and notch-type measurements.
5 |
6 | For installation of the module execute:
7 | python setup.py install
8 |
9 | Description of the algorithm:
10 | http://scitation.aip.org/content/aip/journal/rsi/86/2/10.1063/1.4907935
11 |
12 | Where is it used?
13 | The "resonator_tools" have contributed to the following publications:
14 | https://scholar.google.de/scholar?oi=bibs&hl=de&cites=690000812747125148&as_sdt=5
15 |
16 | Questions? Contact the author:
17 | https://www.phi.kit.edu/ustinov_downloads.php
18 |
--------------------------------------------------------------------------------
/examples/.ipynb_checkpoints/pandas_and_circlefit-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": {
3 | "name": "",
4 | "signature": "sha256:25d58d0ad878b5b3eb3c04f9ab73c1310b0ec623d81be671993f72be36d8a557"
5 | },
6 | "nbformat": 3,
7 | "nbformat_minor": 0,
8 | "worksheets": [
9 | {
10 | "cells": [
11 | {
12 | "cell_type": "heading",
13 | "level": 1,
14 | "metadata": {},
15 | "source": [
16 | "Fitting a resonator measured in reflection"
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "collapsed": false,
22 | "input": [
23 | "from resonator_tools import circuit\n",
24 | "import numpy as np\n",
25 | "import pandas as pd\n",
26 | "from IPython.display import display\n",
27 | "%matplotlib inline"
28 | ],
29 | "language": "python",
30 | "metadata": {},
31 | "outputs": [],
32 | "prompt_number": 1
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "metadata": {},
37 | "source": [
38 | "Although we could use the resonator tools to load data, here we want to use the Pandas library, which is used for statistical data analysis. It can handle many different file types including hdf5."
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "collapsed": false,
44 | "input": [
45 | "df = pd.read_csv('S11.txt',sep='\\t')"
46 | ],
47 | "language": "python",
48 | "metadata": {},
49 | "outputs": [],
50 | "prompt_number": 2
51 | },
52 | {
53 | "cell_type": "markdown",
54 | "metadata": {},
55 | "source": [
56 | "Pandas has a very nice way of displaying the data. Let's look at the first few entries:"
57 | ]
58 | },
59 | {
60 | "cell_type": "code",
61 | "collapsed": false,
62 | "input": [
63 | "display(df.head())"
64 | ],
65 | "language": "python",
66 | "metadata": {},
67 | "outputs": [
68 | {
69 | "html": [
70 | "
\n",
71 | "
\n",
72 | " \n",
73 | " \n",
74 | " | \n",
75 | " freq | \n",
76 | " mag | \n",
77 | " phase | \n",
78 | "
\n",
79 | " \n",
80 | " \n",
81 | " \n",
82 | " 0 | \n",
83 | " 7.112886e+09 | \n",
84 | " -29.041420 | \n",
85 | " 40.656170 | \n",
86 | "
\n",
87 | " \n",
88 | " 1 | \n",
89 | " 7.112886e+09 | \n",
90 | " -29.042747 | \n",
91 | " 40.569664 | \n",
92 | "
\n",
93 | " \n",
94 | " 2 | \n",
95 | " 7.112887e+09 | \n",
96 | " -29.045673 | \n",
97 | " 40.464161 | \n",
98 | "
\n",
99 | " \n",
100 | " 3 | \n",
101 | " 7.112887e+09 | \n",
102 | " -29.049311 | \n",
103 | " 40.361294 | \n",
104 | "
\n",
105 | " \n",
106 | " 4 | \n",
107 | " 7.112887e+09 | \n",
108 | " -29.051012 | \n",
109 | " 40.265739 | \n",
110 | "
\n",
111 | " \n",
112 | "
\n",
113 | "
"
114 | ],
115 | "metadata": {},
116 | "output_type": "display_data",
117 | "text": [
118 | " freq mag phase\n",
119 | "0 7.112886e+09 -29.041420 40.656170\n",
120 | "1 7.112886e+09 -29.042747 40.569664\n",
121 | "2 7.112887e+09 -29.045673 40.464161\n",
122 | "3 7.112887e+09 -29.049311 40.361294\n",
123 | "4 7.112887e+09 -29.051012 40.265739"
124 | ]
125 | }
126 | ],
127 | "prompt_number": 3
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "Next, we define a reflection port measurement and add the data."
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "collapsed": false,
139 | "input": [
140 | "port1 = circuit.reflection_port(f_data=df[\"freq\"].values,\n",
141 | " z_data_raw=10**(df[\"mag\"].values/20.)*np.exp(1j*df[\"phase\"].values/180.*np.pi))"
142 | ],
143 | "language": "python",
144 | "metadata": {},
145 | "outputs": [],
146 | "prompt_number": 4
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | "Perform an automated fit."
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "collapsed": false,
158 | "input": [
159 | "port1.autofit()"
160 | ],
161 | "language": "python",
162 | "metadata": {},
163 | "outputs": [],
164 | "prompt_number": 5
165 | },
166 | {
167 | "cell_type": "markdown",
168 | "metadata": {},
169 | "source": [
170 | "Let's plot the data and the fit!"
171 | ]
172 | },
173 | {
174 | "cell_type": "code",
175 | "collapsed": false,
176 | "input": [
177 | "port1.plotall()"
178 | ],
179 | "language": "python",
180 | "metadata": {},
181 | "outputs": [
182 | {
183 | "metadata": {},
184 | "output_type": "display_data",
185 | "png": "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\n",
186 | "text": [
187 | ""
188 | ]
189 | }
190 | ],
191 | "prompt_number": 6
192 | },
193 | {
194 | "cell_type": "markdown",
195 | "metadata": {},
196 | "source": [
197 | "Next, let us have a look at the fit results. Here, we convert the dictionary of results into a dataframe to display it in a nicer way."
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "collapsed": false,
203 | "input": [
204 | "display(pd.DataFrame([port1.fitresults]).applymap(lambda x: \"{0:.2e}\".format(x)))"
205 | ],
206 | "language": "python",
207 | "metadata": {},
208 | "outputs": [
209 | {
210 | "html": [
211 | "\n",
212 | "
\n",
213 | " \n",
214 | " \n",
215 | " | \n",
216 | " Qc | \n",
217 | " Qc_err | \n",
218 | " Qi | \n",
219 | " Qi_err | \n",
220 | " Ql | \n",
221 | " Ql_err | \n",
222 | " chi_square | \n",
223 | " fr | \n",
224 | " fr_err | \n",
225 | " theta0 | \n",
226 | "
\n",
227 | " \n",
228 | " \n",
229 | " \n",
230 | " 0 | \n",
231 | " 3.48e+05 | \n",
232 | " 2.46e+02 | \n",
233 | " 9.30e+05 | \n",
234 | " 1.74e+03 | \n",
235 | " 2.53e+05 | \n",
236 | " 1.96e+02 | \n",
237 | " 2.87e-05 | \n",
238 | " 7.11e+09 | \n",
239 | " 7.19e+00 | \n",
240 | " -4.18e-03 | \n",
241 | "
\n",
242 | " \n",
243 | "
\n",
244 | "
"
245 | ],
246 | "metadata": {},
247 | "output_type": "display_data",
248 | "text": [
249 | " Qc Qc_err Qi Qi_err Ql Ql_err chi_square \\\n",
250 | "0 3.48e+05 2.46e+02 9.30e+05 1.74e+03 2.53e+05 1.96e+02 2.87e-05 \n",
251 | "\n",
252 | " fr fr_err theta0 \n",
253 | "0 7.11e+09 7.19e+00 -4.18e-03 "
254 | ]
255 | }
256 | ],
257 | "prompt_number": 7
258 | },
259 | {
260 | "cell_type": "markdown",
261 | "metadata": {},
262 | "source": [
263 | "Finally, we can calculate the single photon limit, i.e., the input power necessary to maintain one photon on average in the resonator:"
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "collapsed": false,
269 | "input": [
270 | "print 'Single photon limit: %.2f dBm' % port1.get_single_photon_limit()"
271 | ],
272 | "language": "python",
273 | "metadata": {},
274 | "outputs": [
275 | {
276 | "output_type": "stream",
277 | "stream": "stdout",
278 | "text": [
279 | "Single photon limit: -163.42 dBm\n"
280 | ]
281 | }
282 | ],
283 | "prompt_number": 8
284 | },
285 | {
286 | "cell_type": "markdown",
287 | "metadata": {},
288 | "source": [
289 | "Or, we can compute the photons in the resonator for a given power:"
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "collapsed": false,
295 | "input": [
296 | "print 'At -100dBm, we have %.2e photons in the resonator' % port1.get_photons_in_resonator(-100)"
297 | ],
298 | "language": "python",
299 | "metadata": {},
300 | "outputs": [
301 | {
302 | "output_type": "stream",
303 | "stream": "stdout",
304 | "text": [
305 | "At -100dBm, we have 2.20e+06 photons in the resonator\n"
306 | ]
307 | }
308 | ],
309 | "prompt_number": 9
310 | }
311 | ],
312 | "metadata": {}
313 | }
314 | ]
315 | }
--------------------------------------------------------------------------------
/examples/S11.txt:
--------------------------------------------------------------------------------
1 | freq mag phase
2 | 7112886151.79 -29.0414199829 40.6561698914
3 | 7112886351.79 -29.0427474976 40.5696640015
4 | 7112886551.79 -29.0456733704 40.4641609192
5 | 7112886751.79 -29.0493106842 40.3612937927
6 | 7112886951.79 -29.0510120392 40.2657394409
7 | 7112887151.79 -29.0533924103 40.1798477173
8 | 7112887351.79 -29.0567092896 40.0749206543
9 | 7112887551.79 -29.0580387115 39.9818305969
10 | 7112887751.79 -29.0593109131 39.8811187744
11 | 7112887951.79 -29.0630283356 39.7868423462
12 | 7112888151.79 -29.0647144318 39.6951637268
13 | 7112888351.79 -29.0678272247 39.5831642151
14 | 7112888551.79 -29.0699329376 39.4860153198
15 | 7112888751.79 -29.0715961456 39.391872406
16 | 7112888951.79 -29.0759296417 39.2727966309
17 | 7112889151.79 -29.0784244537 39.1619377136
18 | 7112889351.79 -29.0816917419 39.0605621338
19 | 7112889551.79 -29.0843925476 38.9425621033
20 | 7112889751.79 -29.0861759186 38.8364524841
21 | 7112889951.79 -29.0888748169 38.7343864441
22 | 7112890151.79 -29.0907878876 38.639629364
23 | 7112890351.79 -29.0935974121 38.5414237976
24 | 7112890551.79 -29.0982971191 38.4248390198
25 | 7112890751.79 -29.1013412476 38.303730011
26 | 7112890951.79 -29.1045303345 38.1727790833
27 | 7112891151.79 -29.1083679199 38.0731201172
28 | 7112891351.79 -29.1106014252 37.9570999146
29 | 7112891551.79 -29.1139678955 37.8442077637
30 | 7112891751.79 -29.1176128387 37.7267723083
31 | 7112891951.79 -29.1202831268 37.6098442078
32 | 7112892151.79 -29.12317276 37.4988555908
33 | 7112892351.79 -29.1271800995 37.3827476501
34 | 7112892551.79 -29.1292800903 37.2751083374
35 | 7112892751.79 -29.1342372894 37.1326980591
36 | 7112892951.79 -29.1358661652 37.0348052979
37 | 7112893151.79 -29.1389389038 36.9019088745
38 | 7112893351.79 -29.1438274384 36.764705658
39 | 7112893551.79 -29.1457023621 36.6560096741
40 | 7112893751.79 -29.1498298645 36.5187606812
41 | 7112893951.79 -29.1539573669 36.3929328918
42 | 7112894151.79 -29.158700943 36.2456436157
43 | 7112894351.79 -29.1623821259 36.1094322205
44 | 7112894551.79 -29.1661434174 35.9690322876
45 | 7112894751.79 -29.1693553925 35.8453178406
46 | 7112894951.79 -29.173658371 35.7035751343
47 | 7112895151.79 -29.1772575378 35.5668106079
48 | 7112895351.79 -29.1809139252 35.4237327576
49 | 7112895551.79 -29.1855316162 35.3064651489
50 | 7112895751.79 -29.1897659302 35.1513328552
51 | 7112895951.79 -29.193862915 35.0018997192
52 | 7112896151.79 -29.197807312 34.8756599426
53 | 7112896351.79 -29.2012386322 34.7470245361
54 | 7112896551.79 -29.2064361572 34.5761680603
55 | 7112896751.79 -29.2108345032 34.4437828064
56 | 7112896951.79 -29.2154197693 34.2875938416
57 | 7112897151.79 -29.2198905945 34.1348381042
58 | 7112897351.79 -29.2246608734 33.9788627625
59 | 7112897551.79 -29.2296981812 33.8254547119
60 | 7112897751.79 -29.23412323 33.678817749
61 | 7112897951.79 -29.2384815216 33.5318450928
62 | 7112898151.79 -29.2431163788 33.3696174622
63 | 7112898351.79 -29.247713089 33.2201156616
64 | 7112898551.79 -29.2534046173 33.0596809387
65 | 7112898751.79 -29.2590484619 32.8931732178
66 | 7112898951.79 -29.263174057 32.7329368591
67 | 7112899151.79 -29.2676391602 32.5650787354
68 | 7112899351.79 -29.2732505798 32.3928413391
69 | 7112899551.79 -29.2797985077 32.2118835449
70 | 7112899751.79 -29.2849655151 32.0393829346
71 | 7112899951.79 -29.2901611328 31.8732681274
72 | 7112900151.79 -29.2954788208 31.692609787
73 | 7112900351.79 -29.3021087646 31.5010166168
74 | 7112900551.79 -29.308221817 31.3414974213
75 | 7112900751.79 -29.3129444122 31.1600170135
76 | 7112900951.79 -29.3180503845 30.9811191559
77 | 7112901151.79 -29.3241786957 30.8062534332
78 | 7112901351.79 -29.3310012817 30.6291217804
79 | 7112901551.79 -29.3376045227 30.4313850403
80 | 7112901751.79 -29.343624115 30.261631012
81 | 7112901951.79 -29.3514900208 30.046251297
82 | 7112902151.79 -29.3568229675 29.8720684052
83 | 7112902351.79 -29.3621273041 29.6753311157
84 | 7112902551.79 -29.3707256317 29.470293045
85 | 7112902751.79 -29.3775997162 29.2704486847
86 | 7112902951.79 -29.3850440979 29.0597782135
87 | 7112903151.79 -29.3923797607 28.8383846283
88 | 7112903351.79 -29.4014110565 28.6495018005
89 | 7112903551.79 -29.4076557159 28.4371509552
90 | 7112903751.79 -29.4147796631 28.2311878204
91 | 7112903951.79 -29.4230575562 28.0089435577
92 | 7112904151.79 -29.4311981201 27.7708396912
93 | 7112904351.79 -29.4387378693 27.5503063202
94 | 7112904551.79 -29.4471683502 27.3329238892
95 | 7112904751.79 -29.4538383484 27.1263504028
96 | 7112904951.79 -29.4621543884 26.897726059
97 | 7112905151.79 -29.4718761444 26.6621742249
98 | 7112905351.79 -29.478723526 26.4633388519
99 | 7112905551.79 -29.4891242981 26.2256698608
100 | 7112905751.79 -29.4975471497 25.9607372284
101 | 7112905951.79 -29.506986618 25.7253665924
102 | 7112906151.79 -29.5159072876 25.4717540741
103 | 7112906351.79 -29.5269393921 25.2051677704
104 | 7112906551.79 -29.5357112885 24.9685630798
105 | 7112906751.79 -29.5446071625 24.7307376862
106 | 7112906951.79 -29.556219101 24.4516067505
107 | 7112907151.79 -29.5650367737 24.1830482483
108 | 7112907351.79 -29.5750083923 23.9382514954
109 | 7112907551.79 -29.5856361389 23.6791477203
110 | 7112907751.79 -29.5960712433 23.4198246002
111 | 7112907951.79 -29.6069087982 23.1382446289
112 | 7112908151.79 -29.6169109344 22.8575630188
113 | 7112908351.79 -29.6278076172 22.58411026
114 | 7112908551.79 -29.6418056488 22.2553825378
115 | 7112908751.79 -29.6521530151 22.0025959015
116 | 7112908951.79 -29.6649265289 21.7176818848
117 | 7112909151.79 -29.6777992249 21.3886528015
118 | 7112909351.79 -29.6896877289 21.0978393555
119 | 7112909551.79 -29.7010478973 20.8152046204
120 | 7112909751.79 -29.713596344 20.5196762085
121 | 7112909951.79 -29.7254142761 20.1888332367
122 | 7112910151.79 -29.740694046 19.8599643707
123 | 7112910351.79 -29.7530784607 19.5694332123
124 | 7112910551.79 -29.7673988342 19.2151088715
125 | 7112910751.79 -29.781671524 18.8664455414
126 | 7112910951.79 -29.7962684631 18.5416488647
127 | 7112911151.79 -29.8091106415 18.2299690247
128 | 7112911351.79 -29.8248672485 17.8784599304
129 | 7112911551.79 -29.8409881592 17.5183734894
130 | 7112911751.79 -29.8560905457 17.1820011139
131 | 7112911951.79 -29.8706893921 16.8432331085
132 | 7112912151.79 -29.8866004944 16.4722194672
133 | 7112912351.79 -29.9025096893 16.1211509705
134 | 7112912551.79 -29.9201469421 15.7231464386
135 | 7112912751.79 -29.9373950958 15.3374013901
136 | 7112912951.79 -29.9542217255 14.9592084885
137 | 7112913151.79 -29.9754161835 14.5362529755
138 | 7112913351.79 -29.9948310852 14.1298074722
139 | 7112913551.79 -30.0123271942 13.7574520111
140 | 7112913751.79 -30.02876091 13.3768577576
141 | 7112913951.79 -30.050365448 12.9352073669
142 | 7112914151.79 -30.0715389252 12.4788103104
143 | 7112914351.79 -30.0896682739 12.0710163116
144 | 7112914551.79 -30.1083698273 11.7014408112
145 | 7112914751.79 -30.134021759 11.1996707916
146 | 7112914951.79 -30.1552562714 10.7055835724
147 | 7112915151.79 -30.1743125916 10.3083209991
148 | 7112915351.79 -30.1995048523 9.8061170578
149 | 7112915551.79 -30.219789505 9.3702955246
150 | 7112915751.79 -30.2444820404 8.89730548859
151 | 7112915951.79 -30.2691516876 8.39351654053
152 | 7112916151.79 -30.2937870026 7.90898084641
153 | 7112916351.79 -30.3196315765 7.41554737091
154 | 7112916551.79 -30.3464679718 6.85498189926
155 | 7112916751.79 -30.3712825775 6.37863826752
156 | 7112916951.79 -30.3977909088 5.86556816101
157 | 7112917151.79 -30.4246349335 5.33062934875
158 | 7112917351.79 -30.4554672241 4.7455496788
159 | 7112917551.79 -30.4852657318 4.17402982712
160 | 7112917751.79 -30.5133953094 3.63583946228
161 | 7112917951.79 -30.545009613 3.07135176659
162 | 7112918151.79 -30.5737876892 2.52529907227
163 | 7112918351.79 -30.607831955 1.88873744011
164 | 7112918551.79 -30.640871048 1.25803089142
165 | 7112918751.79 -30.6717910767 0.67052179575
166 | 7112918951.79 -30.7087745667 0.0257931556553
167 | 7112919151.79 -30.7478637695 -0.664188325405
168 | 7112919351.79 -30.7801132202 -1.23034977913
169 | 7112919551.79 -30.8115139008 -1.8547513485
170 | 7112919751.79 -30.8507270813 -2.54084444046
171 | 7112919951.79 -30.887845993 -3.20032525063
172 | 7112920151.79 -30.9318161011 -3.95836472511
173 | 7112920351.79 -30.9733943939 -4.70586299896
174 | 7112920551.79 -31.0163440704 -5.44456672668
175 | 7112920751.79 -31.0589828491 -6.18624830246
176 | 7112920951.79 -31.1006069183 -6.9016046524
177 | 7112921151.79 -31.1454391479 -7.69521045685
178 | 7112921351.79 -31.1958217621 -8.55935382843
179 | 7112921551.79 -31.236497879 -9.22374153137
180 | 7112921751.79 -31.2865467072 -10.1176490784
181 | 7112921951.79 -31.3375377655 -10.9914064407
182 | 7112922151.79 -31.3891906738 -11.8570833206
183 | 7112922351.79 -31.4326152802 -12.6113204956
184 | 7112922551.79 -31.490196228 -13.5534944534
185 | 7112922751.79 -31.5448493958 -14.4647626877
186 | 7112922951.79 -31.6002445221 -15.372885704
187 | 7112923151.79 -31.6581115723 -16.3201522827
188 | 7112923351.79 -31.7132797241 -17.2387619019
189 | 7112923551.79 -31.776058197 -18.2660293579
190 | 7112923751.79 -31.8362770081 -19.2835788727
191 | 7112923951.79 -31.8941993713 -20.2449588776
192 | 7112924151.79 -31.9586372375 -21.3429145813
193 | 7112924351.79 -32.0264320374 -22.3861370087
194 | 7112924551.79 -32.093296051 -23.4916381836
195 | 7112924751.79 -32.1588668823 -24.5453548431
196 | 7112924951.79 -32.2366714478 -25.8191928864
197 | 7112925151.79 -32.305557251 -26.9577274323
198 | 7112925351.79 -32.3772392273 -28.1541690826
199 | 7112925551.79 -32.4515304565 -29.3701267242
200 | 7112925751.79 -32.5195617676 -30.5391597748
201 | 7112925951.79 -32.6015472412 -31.8435344696
202 | 7112926151.79 -32.6865158081 -33.1942749023
203 | 7112926351.79 -32.7633743286 -34.5236968994
204 | 7112926551.79 -32.839679718 -35.8208808899
205 | 7112926751.79 -32.9245681763 -37.2521743774
206 | 7112926951.79 -33.0130119324 -38.7764625549
207 | 7112927151.79 -33.0939445496 -40.1389846802
208 | 7112927351.79 -33.1859512329 -41.6905059814
209 | 7112927551.79 -33.2627830505 -43.0973205566
210 | 7112927751.79 -33.3534927368 -44.6995887756
211 | 7112927951.79 -33.4381713867 -46.2194366455
212 | 7112928151.79 -33.531124115 -47.9219055176
213 | 7112928351.79 -33.631526947 -49.6385688782
214 | 7112928551.79 -33.7270507813 -51.3959732056
215 | 7112928751.79 -33.8128738403 -53.0928916931
216 | 7112928951.79 -33.9056282043 -54.9134407043
217 | 7112929151.79 -34.0023612976 -56.7591667175
218 | 7112929351.79 -34.0971069336 -58.6793022156
219 | 7112929551.79 -34.1995506287 -60.6295661926
220 | 7112929751.79 -34.2840881348 -62.6748542786
221 | 7112929951.79 -34.3806266785 -64.7666244507
222 | 7112930151.79 -34.4722518921 -66.9149475098
223 | 7112930351.79 -34.55519104 -68.9359893799
224 | 7112930551.79 -34.6272697449 -70.6857833862
225 | 7112930751.79 -34.7184791565 -72.9267730713
226 | 7112930951.79 -34.8082771301 -75.3440170288
227 | 7112931151.79 -34.8979263306 -77.6356811523
228 | 7112931351.79 -34.9735679626 -79.917755127
229 | 7112931551.79 -35.0453948975 -82.1688079834
230 | 7112931751.79 -35.1205863953 -84.5878677368
231 | 7112931951.79 -35.1787223816 -86.8336868286
232 | 7112932151.79 -35.2483863831 -89.5069274902
233 | 7112932351.79 -35.3001251221 -91.767578125
234 | 7112932551.79 -35.354473114 -94.3734512329
235 | 7112932751.79 -35.3971214294 -96.8362045288
236 | 7112932951.79 -35.4430618286 -99.4056396484
237 | 7112933151.79 -35.476776123 -101.983596802
238 | 7112933351.79 -35.5099220276 -104.712265015
239 | 7112933551.79 -35.530166626 -107.081314087
240 | 7112933751.79 -35.5481872559 -109.7394104
241 | 7112933951.79 -35.5557594299 -112.536514282
242 | 7112934151.79 -35.5540008545 -115.205032349
243 | 7112934351.79 -35.5517158508 -118.057945251
244 | 7112934551.79 -35.5384597778 -120.509887695
245 | 7112934751.79 -35.5222091675 -123.022529602
246 | 7112934951.79 -35.4969024658 -125.591384888
247 | 7112935151.79 -35.4675750732 -128.331680298
248 | 7112935351.79 -35.4320793152 -130.703582764
249 | 7112935551.79 -35.3930549622 -133.249710083
250 | 7112935751.79 -35.338924408 -135.628738403
251 | 7112935951.79 -35.2889137268 -138.098434448
252 | 7112936151.79 -35.2266120911 -140.532104492
253 | 7112936351.79 -35.1740951538 -142.719711304
254 | 7112936551.79 -35.1016960144 -145.238311768
255 | 7112936751.79 -35.0282936096 -147.639633179
256 | 7112936951.79 -34.9553565979 -149.752853394
257 | 7112937151.79 -34.8829994202 -152.167602539
258 | 7112937351.79 -34.8024520874 -154.365356445
259 | 7112937551.79 -34.7155532837 -156.601791382
260 | 7112937751.79 -34.6332168579 -158.659408569
261 | 7112937951.79 -34.5460090637 -160.783325195
262 | 7112938151.79 -34.4520263672 -162.958175659
263 | 7112938351.79 -34.3624534607 -164.960891724
264 | 7112938551.79 -34.2794685364 -166.985214233
265 | 7112938751.79 -34.1870193481 -168.800354004
266 | 7112938951.79 -34.0872077942 -170.755645752
267 | 7112939151.79 -34.0014419556 -172.477767944
268 | 7112939351.79 -33.9034843445 -174.525054932
269 | 7112939551.79 -33.8182525635 -176.175720215
270 | 7112939751.79 -33.7129402161 -178.052658081
271 | 7112939951.79 -33.6330032349 -179.584976196
272 | 7112940151.79 -33.5493659973 178.867004395
273 | 7112940351.79 -33.4641304016 177.321472168
274 | 7112940551.79 -33.3733634949 175.664611816
275 | 7112940751.79 -33.2829742432 174.079620361
276 | 7112940951.79 -33.2026252747 172.715698242
277 | 7112941151.79 -33.1108818054 171.152160645
278 | 7112941351.79 -33.0248184204 169.702438354
279 | 7112941551.79 -32.9448661804 168.314956665
280 | 7112941751.79 -32.8555717468 166.826248169
281 | 7112941951.79 -32.7840194702 165.6222229
282 | 7112942151.79 -32.6991271973 164.20362854
283 | 7112942351.79 -32.6267280579 162.983413696
284 | 7112942551.79 -32.5468482971 161.676559448
285 | 7112942751.79 -32.4721450806 160.401489258
286 | 7112942951.79 -32.3967971802 159.129776001
287 | 7112943151.79 -32.3263931274 158.013076782
288 | 7112943351.79 -32.2536430359 156.816375732
289 | 7112943551.79 -32.1832809448 155.651916504
290 | 7112943751.79 -32.1221656799 154.591781616
291 | 7112943951.79 -32.0533752441 153.483551025
292 | 7112944151.79 -31.9818096161 152.325286865
293 | 7112944351.79 -31.9196796417 151.336471558
294 | 7112944551.79 -31.8532066345 150.249511719
295 | 7112944751.79 -31.7993202209 149.328384399
296 | 7112944951.79 -31.7368488312 148.310516357
297 | 7112945151.79 -31.6748104095 147.258712769
298 | 7112945351.79 -31.6172161102 146.302246094
299 | 7112945551.79 -31.5684185028 145.506484985
300 | 7112945751.79 -31.5048503876 144.471557617
301 | 7112945951.79 -31.4497699738 143.544723511
302 | 7112946151.79 -31.3979454041 142.652526855
303 | 7112946351.79 -31.3529453278 141.872787476
304 | 7112946551.79 -31.2977485657 140.95111084
305 | 7112946751.79 -31.2492275238 140.17137146
306 | 7112946951.79 -31.2056732178 139.383224487
307 | 7112947151.79 -31.1584758759 138.552856445
308 | 7112947351.79 -31.1131496429 137.804168701
309 | 7112947551.79 -31.0691814423 137.027282715
310 | 7112947751.79 -31.0244541168 136.255279541
311 | 7112947951.79 -30.9798908234 135.480041504
312 | 7112948151.79 -30.9421787262 134.793243408
313 | 7112948351.79 -30.8987483978 134.041702271
314 | 7112948551.79 -30.8584671021 133.338607788
315 | 7112948751.79 -30.8216533661 132.661376953
316 | 7112948951.79 -30.7861328125 131.989776611
317 | 7112949151.79 -30.7465438843 131.274887085
318 | 7112949351.79 -30.7089862823 130.622650146
319 | 7112949551.79 -30.6722068787 129.933578491
320 | 7112949751.79 -30.640499115 129.336761475
321 | 7112949951.79 -30.6060428619 128.718688965
322 | 7112950151.79 -30.5748462677 128.107513428
323 | 7112950351.79 -30.5430850983 127.524238586
324 | 7112950551.79 -30.5122318268 126.948028564
325 | 7112950751.79 -30.4828643799 126.354553223
326 | 7112950951.79 -30.4553337097 125.842216492
327 | 7112951151.79 -30.4205951691 125.204673767
328 | 7112951351.79 -30.3943500519 124.677429199
329 | 7112951551.79 -30.3673591614 124.127189636
330 | 7112951751.79 -30.3358020782 123.539993286
331 | 7112951951.79 -30.3113803864 123.033332825
332 | 7112952151.79 -30.2865943909 122.554969788
333 | 7112952351.79 -30.2561340332 121.979286194
334 | 7112952551.79 -30.2325611115 121.474884033
335 | 7112952751.79 -30.2070503235 120.951858521
336 | 7112952951.79 -30.1823558807 120.461898804
337 | 7112953151.79 -30.1591205597 119.988265991
338 | 7112953351.79 -30.1364135742 119.527740479
339 | 7112953551.79 -30.1154403687 119.103790283
340 | 7112953751.79 -30.092918396 118.645195007
341 | 7112953951.79 -30.0740394592 118.202514648
342 | 7112954151.79 -30.0506305695 117.736694336
343 | 7112954351.79 -30.0288848877 117.308036804
344 | 7112954551.79 -30.0097751617 116.870368958
345 | 7112954751.79 -29.9900131226 116.465042114
346 | 7112954951.79 -29.9710769653 116.023330688
347 | 7112955151.79 -29.9527664185 115.641098022
348 | 7112955351.79 -29.9347457886 115.230293274
349 | 7112955551.79 -29.9151096344 114.783607483
350 | 7112955751.79 -29.8980789185 114.365966797
351 | 7112955951.79 -29.8792762756 113.969696045
352 | 7112956151.79 -29.8629131317 113.609535217
353 | 7112956351.79 -29.845741272 113.224334717
354 | 7112956551.79 -29.8300285339 112.832984924
355 | 7112956751.79 -29.8144760132 112.469009399
356 | 7112956951.79 -29.7985687256 112.11681366
357 | 7112957151.79 -29.7815341949 111.726341248
358 | 7112957351.79 -29.7651786804 111.347503662
359 | 7112957551.79 -29.7504177094 111.037971497
360 | 7112957751.79 -29.737405777 110.697219849
361 | 7112957951.79 -29.7211151123 110.35735321
362 | 7112958151.79 -29.7078323364 110.023330688
363 | 7112958351.79 -29.6969413757 109.721611023
364 | 7112958551.79 -29.683921814 109.410339355
365 | 7112958751.79 -29.6686267853 109.068977356
366 | 7112958951.79 -29.6563796997 108.746902466
367 | 7112959151.79 -29.6432304382 108.403335571
368 | 7112959351.79 -29.631652832 108.138656616
369 | 7112959551.79 -29.6204032898 107.823356628
370 | 7112959751.79 -29.6069107056 107.5184021
371 | 7112959951.79 -29.5953388214 107.201972961
372 | 7112960151.79 -29.5831317902 106.917694092
373 | 7112960351.79 -29.5739021301 106.638137817
374 | 7112960551.79 -29.5603084564 106.328033447
375 | 7112960751.79 -29.5516147614 106.050346375
376 | 7112960951.79 -29.5401935577 105.768669128
377 | 7112961151.79 -29.5289783478 105.47467041
378 | 7112961351.79 -29.5183124542 105.217750549
379 | 7112961551.79 -29.5076732635 104.963874817
380 | 7112961751.79 -29.4981689453 104.685142517
381 | 7112961951.79 -29.4886188507 104.417533875
382 | 7112962151.79 -29.4794845581 104.168746948
383 | 7112962351.79 -29.4704017639 103.924591064
384 | 7112962551.79 -29.4610939026 103.660041809
385 | 7112962751.79 -29.4517192841 103.416282654
386 | 7112962951.79 -29.4432506561 103.172599792
387 | 7112963151.79 -29.4336585999 102.915756226
388 | 7112963351.79 -29.4238929749 102.665168762
389 | 7112963551.79 -29.4152946472 102.410377502
390 | 7112963751.79 -29.407497406 102.177383423
391 | 7112963951.79 -29.3989219666 101.935676575
392 | 7112964151.79 -29.3931102753 101.713623047
393 | 7112964351.79 -29.3840446472 101.508033752
394 | 7112964551.79 -29.3753509521 101.274932861
395 | 7112964751.79 -29.3675117493 101.065917969
396 | 7112964951.79 -29.3609313965 100.841255188
397 | 7112965151.79 -29.3530654907 100.618225098
398 | 7112965351.79 -29.3464336395 100.397903442
399 | 7112965551.79 -29.3387184143 100.192245483
400 | 7112965751.79 -29.3313159943 99.9787826538
401 | 7112965951.79 -29.3240680695 99.7603530884
402 | 7112966151.79 -29.3187103271 99.5674057007
403 | 7112966351.79 -29.3104038239 99.3256835938
404 | 7112966551.79 -29.3049411774 99.1575241089
405 | 7112966751.79 -29.2975254059 98.9616088867
406 | 7112966951.79 -29.29180336 98.7493591309
407 | 7112967151.79 -29.284986496 98.5568237305
408 | 7112967351.79 -29.2794017792 98.3647232056
409 | 7112967551.79 -29.2726421356 98.1539993286
410 | 7112967751.79 -29.2661838531 97.9649734497
411 | 7112967951.79 -29.2600288391 97.7969894409
412 | 7112968151.79 -29.2558269501 97.6447143555
413 | 7112968351.79 -29.2499752045 97.4524459839
414 | 7112968551.79 -29.2453022003 97.2811050415
415 | 7112968751.79 -29.2385616302 97.0701599121
416 | 7112968951.79 -29.2327194214 96.8921356201
417 | 7112969151.79 -29.2274570465 96.7140884399
418 | 7112969351.79 -29.2226772308 96.5478897095
419 | 7112969551.79 -29.2166023254 96.3553161621
420 | 7112969751.79 -29.2117080688 96.1945800781
421 | 7112969951.79 -29.2060184479 96.0274429321
422 | 7112970151.79 -29.2024688721 95.872505188
423 | 7112970351.79 -29.1971282959 95.7041854858
424 | 7112970551.79 -29.191116333 95.5210342407
425 | 7112970751.79 -29.1867809296 95.3535003662
426 | 7112970951.79 -29.181016922 95.2219772339
427 | 7112971151.79 -29.1773490906 95.0492172241
428 | 7112971351.79 -29.172296524 94.8775863647
429 | 7112971551.79 -29.1677970886 94.7388916016
430 | 7112971751.79 -29.1637401581 94.5770111084
431 | 7112971951.79 -29.1579742432 94.4201202393
432 | 7112972151.79 -29.1546440125 94.2627716064
433 | 7112972351.79 -29.150636673 94.1110305786
434 | 7112972551.79 -29.1462879181 93.9831466675
435 | 7112972751.79 -29.1428947449 93.8402252197
436 | 7112972951.79 -29.1397857666 93.685874939
437 | 7112973151.79 -29.1339092255 93.5384674072
438 | 7112973351.79 -29.1303596497 93.3998794556
439 | 7112973551.79 -29.1263179779 93.2400360107
440 | 7112973751.79 -29.1232681274 93.1196136475
441 | 7112973951.79 -29.1195087433 92.9893112183
442 | 7112974151.79 -29.1146831512 92.841293335
443 | 7112974351.79 -29.1118297577 92.7020797729
444 | 7112974551.79 -29.1077423096 92.5562667847
445 | 7112974751.79 -29.1055641174 92.4065170288
446 | 7112974951.79 -29.1019954681 92.3015365601
447 | 7112975151.79 -29.0970172882 92.1622695923
448 | 7112975351.79 -29.0922546387 92.0345611572
449 | 7112975551.79 -29.0895709991 91.9001235962
450 | 7112975751.79 -29.0866203308 91.7699661255
451 | 7112975951.79 -29.0832939148 91.6366043091
452 | 7112976151.79 -29.0810985565 91.5446090698
453 | 7112976351.79 -29.077703476 91.4200439453
454 | 7112976551.79 -29.0735569 91.2852020264
455 | 7112976751.79 -29.0710048676 91.1828765869
456 | 7112976951.79 -29.0680656433 91.0568313599
457 | 7112977151.79 -29.0649929047 90.9418869019
458 | 7112977351.79 -29.0614242554 90.8108520508
459 | 7112977551.79 -29.0575656891 90.6791610718
460 | 7112977751.79 -29.0541229248 90.548248291
461 | 7112977951.79 -29.05210495 90.4298095703
462 | 7112978151.79 -29.0500869751 90.3356704712
463 | 7112978351.79 -29.0456295013 90.2152786255
464 | 7112978551.79 -29.0414524078 90.0981826782
465 | 7112978751.79 -29.0398960114 89.9874420166
466 | 7112978951.79 -29.0376052856 89.8669586182
467 | 7112979151.79 -29.0351257324 89.7706069946
468 | 7112979351.79 -29.0314216614 89.6592178345
469 | 7112979551.79 -29.0295543671 89.5618286133
470 | 7112979751.79 -29.0273132324 89.4590301514
471 | 7112979951.79 -29.0245571136 89.3369827271
472 | 7112980151.79 -29.022108078 89.2261352539
473 | 7112980351.79 -29.0186595917 89.1377563477
474 | 7112980551.79 -29.0174312592 89.0398101807
475 | 7112980751.79 -29.0136165619 88.9458084106
476 | 7112980951.79 -29.0119419098 88.8277282715
477 | 7112981151.79 -29.010591507 88.7223358154
478 | 7112981351.79 -29.0085849762 88.625793457
479 | 7112981551.79 -29.0049781799 88.524810791
480 | 7112981751.79 -29.0038719177 88.4309539795
481 | 7112981951.79 -28.9999523163 88.3362426758
482 | 7112982151.79 -28.9971370697 88.2193069458
483 | 7112982351.79 -28.9951400757 88.1351470947
484 | 7112982551.79 -28.9943256378 88.0488128662
485 | 7112982751.79 -28.9916267395 87.9335403442
486 | 7112982951.79 -28.990032196 87.8511962891
487 | 7112983151.79 -28.9867687225 87.747833252
488 | 7112983351.79 -28.9849834442 87.6607208252
489 | 7112983551.79 -28.9839553833 87.5676727295
490 | 7112983751.79 -28.9811935425 87.4755630493
491 | 7112983951.79 -28.9777202606 87.3772888184
492 | 7112984151.79 -28.9758930206 87.2980117798
493 | 7112984351.79 -28.9738864899 87.2104949951
494 | 7112984551.79 -28.9727306366 87.1030654907
495 | 7112984751.79 -28.9708786011 87.0149078369
496 | 7112984951.79 -28.9685821533 86.9465332031
497 | 7112985151.79 -28.9666900635 86.845489502
498 | 7112985351.79 -28.9654083252 86.7677001953
499 | 7112985551.79 -28.9634037018 86.6886062622
500 | 7112985751.79 -28.9617195129 86.5867996216
501 | 7112985951.79 -28.9602642059 86.5100860596
502 | 7112986151.79 -28.9576091766 86.4353103638
503 |
--------------------------------------------------------------------------------
/examples/notch_port_example.py:
--------------------------------------------------------------------------------
1 |
2 | from resonator_tools import circuit
3 |
4 |
5 | port1 = circuit.notch_port()
6 | port1.add_froms2p('S21testdata.s2p',3,4,'realimag',fdata_unit=1e9,delimiter=None)
7 | port1.autofit()
8 | print("Fit results:", port1.fitresults)
9 | port1.plotall()
10 | print("single photon limit:", port1.get_single_photon_limit(diacorr=True), "dBm")
11 | print("photons in reso for input -140dBm:", port1.get_photons_in_resonator(-140,unit='dBm',diacorr=True), "photons")
12 | print("done")
13 |
--------------------------------------------------------------------------------
/examples/notch_port_example_withGUI.py:
--------------------------------------------------------------------------------
1 |
2 | from resonator_tools import circuit
3 |
4 |
5 | port1 = circuit.notch_port()
6 | port1.add_froms2p('S21testdata.s2p',3,4,'realimag',fdata_unit=1e9,delimiter=None)
7 | port1.GUIfit()
8 | print("Fit results:", port1.fitresults)
9 | port1.plotall()
10 | print("single photon limit:", port1.get_single_photon_limit(diacorr=True), "dBm")
11 | print("photons in reso for input -140dBm:", port1.get_photons_in_resonator(-140,unit='dBm',diacorr=True), "photons")
12 | print("done")
13 |
--------------------------------------------------------------------------------
/examples/pandas_and_circlefit.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": {
3 | "name": "",
4 | "signature": "sha256:25d58d0ad878b5b3eb3c04f9ab73c1310b0ec623d81be671993f72be36d8a557"
5 | },
6 | "nbformat": 3,
7 | "nbformat_minor": 0,
8 | "worksheets": [
9 | {
10 | "cells": [
11 | {
12 | "cell_type": "heading",
13 | "level": 1,
14 | "metadata": {},
15 | "source": [
16 | "Fitting a resonator measured in reflection"
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "collapsed": false,
22 | "input": [
23 | "from resonator_tools import circuit\n",
24 | "import numpy as np\n",
25 | "import pandas as pd\n",
26 | "from IPython.display import display\n",
27 | "%matplotlib inline"
28 | ],
29 | "language": "python",
30 | "metadata": {},
31 | "outputs": [],
32 | "prompt_number": 1
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "metadata": {},
37 | "source": [
38 | "Although we could use the resonator tools to load data, here we want to use the Pandas library, which is used for statistical data analysis. It can handle many different file types including hdf5."
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "collapsed": false,
44 | "input": [
45 | "df = pd.read_csv('S11.txt',sep='\\t')"
46 | ],
47 | "language": "python",
48 | "metadata": {},
49 | "outputs": [],
50 | "prompt_number": 2
51 | },
52 | {
53 | "cell_type": "markdown",
54 | "metadata": {},
55 | "source": [
56 | "Pandas has a very nice way of displaying the data. Let's look at the first few entries:"
57 | ]
58 | },
59 | {
60 | "cell_type": "code",
61 | "collapsed": false,
62 | "input": [
63 | "display(df.head())"
64 | ],
65 | "language": "python",
66 | "metadata": {},
67 | "outputs": [
68 | {
69 | "html": [
70 | "\n",
71 | "
\n",
72 | " \n",
73 | " \n",
74 | " | \n",
75 | " freq | \n",
76 | " mag | \n",
77 | " phase | \n",
78 | "
\n",
79 | " \n",
80 | " \n",
81 | " \n",
82 | " 0 | \n",
83 | " 7.112886e+09 | \n",
84 | " -29.041420 | \n",
85 | " 40.656170 | \n",
86 | "
\n",
87 | " \n",
88 | " 1 | \n",
89 | " 7.112886e+09 | \n",
90 | " -29.042747 | \n",
91 | " 40.569664 | \n",
92 | "
\n",
93 | " \n",
94 | " 2 | \n",
95 | " 7.112887e+09 | \n",
96 | " -29.045673 | \n",
97 | " 40.464161 | \n",
98 | "
\n",
99 | " \n",
100 | " 3 | \n",
101 | " 7.112887e+09 | \n",
102 | " -29.049311 | \n",
103 | " 40.361294 | \n",
104 | "
\n",
105 | " \n",
106 | " 4 | \n",
107 | " 7.112887e+09 | \n",
108 | " -29.051012 | \n",
109 | " 40.265739 | \n",
110 | "
\n",
111 | " \n",
112 | "
\n",
113 | "
"
114 | ],
115 | "metadata": {},
116 | "output_type": "display_data",
117 | "text": [
118 | " freq mag phase\n",
119 | "0 7.112886e+09 -29.041420 40.656170\n",
120 | "1 7.112886e+09 -29.042747 40.569664\n",
121 | "2 7.112887e+09 -29.045673 40.464161\n",
122 | "3 7.112887e+09 -29.049311 40.361294\n",
123 | "4 7.112887e+09 -29.051012 40.265739"
124 | ]
125 | }
126 | ],
127 | "prompt_number": 3
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "Next, we define a reflection port measurement and add the data."
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "collapsed": false,
139 | "input": [
140 | "port1 = circuit.reflection_port(f_data=df[\"freq\"].values,\n",
141 | " z_data_raw=10**(df[\"mag\"].values/20.)*np.exp(1j*df[\"phase\"].values/180.*np.pi))"
142 | ],
143 | "language": "python",
144 | "metadata": {},
145 | "outputs": [],
146 | "prompt_number": 4
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | "Perform an automated fit."
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "collapsed": false,
158 | "input": [
159 | "port1.autofit()"
160 | ],
161 | "language": "python",
162 | "metadata": {},
163 | "outputs": [],
164 | "prompt_number": 5
165 | },
166 | {
167 | "cell_type": "markdown",
168 | "metadata": {},
169 | "source": [
170 | "Let's plot the data and the fit!"
171 | ]
172 | },
173 | {
174 | "cell_type": "code",
175 | "collapsed": false,
176 | "input": [
177 | "port1.plotall()"
178 | ],
179 | "language": "python",
180 | "metadata": {},
181 | "outputs": [
182 | {
183 | "metadata": {},
184 | "output_type": "display_data",
185 | "png": "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\n",
186 | "text": [
187 | ""
188 | ]
189 | }
190 | ],
191 | "prompt_number": 6
192 | },
193 | {
194 | "cell_type": "markdown",
195 | "metadata": {},
196 | "source": [
197 | "Next, let us have a look at the fit results. Here, we convert the dictionary of results into a dataframe to display it in a nicer way."
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "collapsed": false,
203 | "input": [
204 | "display(pd.DataFrame([port1.fitresults]).applymap(lambda x: \"{0:.2e}\".format(x)))"
205 | ],
206 | "language": "python",
207 | "metadata": {},
208 | "outputs": [
209 | {
210 | "html": [
211 | "\n",
212 | "
\n",
213 | " \n",
214 | " \n",
215 | " | \n",
216 | " Qc | \n",
217 | " Qc_err | \n",
218 | " Qi | \n",
219 | " Qi_err | \n",
220 | " Ql | \n",
221 | " Ql_err | \n",
222 | " chi_square | \n",
223 | " fr | \n",
224 | " fr_err | \n",
225 | " theta0 | \n",
226 | "
\n",
227 | " \n",
228 | " \n",
229 | " \n",
230 | " 0 | \n",
231 | " 3.48e+05 | \n",
232 | " 2.46e+02 | \n",
233 | " 9.30e+05 | \n",
234 | " 1.74e+03 | \n",
235 | " 2.53e+05 | \n",
236 | " 1.96e+02 | \n",
237 | " 2.87e-05 | \n",
238 | " 7.11e+09 | \n",
239 | " 7.19e+00 | \n",
240 | " -4.18e-03 | \n",
241 | "
\n",
242 | " \n",
243 | "
\n",
244 | "
"
245 | ],
246 | "metadata": {},
247 | "output_type": "display_data",
248 | "text": [
249 | " Qc Qc_err Qi Qi_err Ql Ql_err chi_square \\\n",
250 | "0 3.48e+05 2.46e+02 9.30e+05 1.74e+03 2.53e+05 1.96e+02 2.87e-05 \n",
251 | "\n",
252 | " fr fr_err theta0 \n",
253 | "0 7.11e+09 7.19e+00 -4.18e-03 "
254 | ]
255 | }
256 | ],
257 | "prompt_number": 7
258 | },
259 | {
260 | "cell_type": "markdown",
261 | "metadata": {},
262 | "source": [
263 | "Finally, we can calculate the single photon limit, i.e., the input power necessary to maintain one photon on average in the resonator:"
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "collapsed": false,
269 | "input": [
270 | "print 'Single photon limit: %.2f dBm' % port1.get_single_photon_limit()"
271 | ],
272 | "language": "python",
273 | "metadata": {},
274 | "outputs": [
275 | {
276 | "output_type": "stream",
277 | "stream": "stdout",
278 | "text": [
279 | "Single photon limit: -163.42 dBm\n"
280 | ]
281 | }
282 | ],
283 | "prompt_number": 8
284 | },
285 | {
286 | "cell_type": "markdown",
287 | "metadata": {},
288 | "source": [
289 | "Or, we can compute the photons in the resonator for a given power:"
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "collapsed": false,
295 | "input": [
296 | "print 'At -100dBm, we have %.2e photons in the resonator' % port1.get_photons_in_resonator(-100)"
297 | ],
298 | "language": "python",
299 | "metadata": {},
300 | "outputs": [
301 | {
302 | "output_type": "stream",
303 | "stream": "stdout",
304 | "text": [
305 | "At -100dBm, we have 2.20e+06 photons in the resonator\n"
306 | ]
307 | }
308 | ],
309 | "prompt_number": 9
310 | }
311 | ],
312 | "metadata": {}
313 | }
314 | ]
315 | }
--------------------------------------------------------------------------------
/examples/reflection_port_example.py:
--------------------------------------------------------------------------------
1 |
2 | from resonator_tools import circuit
3 |
4 |
5 | port1 = circuit.reflection_port()
6 | port1.add_fromtxt('S11.txt','dBmagphasedeg',1)
7 | port1.autofit()
8 | print("Fit results:", port1.fitresults)
9 | port1.plotall()
10 | print("single photon limit:", port1.get_single_photon_limit(), "dBm")
11 | print("done")
12 |
--------------------------------------------------------------------------------
/examples/reflection_port_example_withGUI.py:
--------------------------------------------------------------------------------
1 |
2 | from resonator_tools import circuit
3 |
4 |
5 | port1 = circuit.reflection_port()
6 | port1.add_fromtxt('S11.txt','dBmagphasedeg',1)
7 | port1.GUIfit()
8 | print("Fit results:", port1.fitresults)
9 | port1.plotall()
10 | print("single photon limit:", port1.get_single_photon_limit(), "dBm")
11 | print("done")
12 |
--------------------------------------------------------------------------------
/examples/remove_wiggly_baseline_with GUI.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | from resonator_tools import circuit
4 |
5 | #---------------------------------------
6 | #generate test data
7 | fr = 7e9 #resonance frequency in Hz
8 | Qi = 200e3
9 | Qc = 300e3
10 | freq = np.linspace(fr-5e6, fr+5e6, 5000)
11 | port1 = circuit.reflection_port() #define a reflection port
12 | #add noise
13 | noise = np.random.normal(loc=1.0,scale=0.01,size=(len(freq),))
14 | S11 = noise * port1._S11_directrefl(freq,fr=fr,Ql=Qi*Qc/(Qc+Qi),Qc=Qc,a=1.,alpha=0.,delay=.0)
15 | # add wiggly baseline
16 | baseline = 1.+0.1*np.cos(2.*np.pi*0.001e-4*freq)+0.05*np.sin(2.*np.pi*0.0069e-4*freq)+0.001*np.sin(2.*np.pi*0.0001e-4*freq)
17 | S11b = S11*baseline
18 | #-----------------------------------------
19 |
20 | # create fitting object
21 | port1 = circuit.reflection_port()
22 | port1.add_data(freq,S11b)
23 |
24 | # fit and remove base line
25 | port1.GUIbaselinefit()
26 |
27 | # fit the corrected data
28 | port1.GUIfit()
29 | print("Fit results:", port1.fitresults)
30 | port1.plotall()
31 | print("single photon limit:", port1.get_single_photon_limit(), "dBm")
32 | print("done")
33 |
34 |
--------------------------------------------------------------------------------
/old_discontinued_circlefit/Circlefit_V3.1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianprobst/resonator_tools/bbd6bca255eb7ebdf550fde9f6c526a7d0791eac/old_discontinued_circlefit/Circlefit_V3.1.zip
--------------------------------------------------------------------------------
/resonator_tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastianprobst/resonator_tools/bbd6bca255eb7ebdf550fde9f6c526a7d0791eac/resonator_tools/__init__.py
--------------------------------------------------------------------------------
/resonator_tools/calibration.py:
--------------------------------------------------------------------------------
1 |
2 | import numpy as np
3 | from scipy import sparse
4 | from scipy.interpolate import interp1d
5 |
6 | class calibration(object):
7 | '''
8 | some useful tools for manual calibration
9 | '''
10 | def normalize_zdata(self,z_data,cal_z_data):
11 | return z_data/cal_z_data
12 |
13 | def normalize_amplitude(self,z_data,cal_ampdata):
14 | return z_data/cal_ampdata
15 |
16 | def normalize_phase(self,z_data,cal_phase):
17 | return z_data*np.exp(-1j*cal_phase)
18 |
19 | def normalize_by_func(self,f_data,z_data,func):
20 | return z_data/func(f_data)
21 |
22 | def _baseline_als(self,y, lam, p, niter=10):
23 | '''
24 | see http://zanran_storage.s3.amazonaws.com/www.science.uva.nl/ContentPages/443199618.pdf
25 | "Asymmetric Least Squares Smoothing" by P. Eilers and H. Boelens in 2005.
26 | http://stackoverflow.com/questions/29156532/python-baseline-correction-library
27 | "There are two parameters: p for asymmetry and lambda for smoothness. Both have to be
28 | tuned to the data at hand. We found that generally 0.001<=p<=0.1 is a good choice
29 | (for a signal with positive peaks) and 10e2<=lambda<=10e9, but exceptions may occur."
30 | '''
31 | L = len(y)
32 | D = sparse.csc_matrix(np.diff(np.eye(L), 2))
33 | w = np.ones(L)
34 | for i in range(niter):
35 | W = sparse.spdiags(w, 0, L, L)
36 | Z = W + lam * D.dot(D.transpose())
37 | z = sparse.linalg.spsolve(Z, w*y)
38 | w = p * (y > z) + (1-p) * (y < z)
39 | return z
40 |
41 | def fit_baseline_amp(self,z_data,lam,p,niter=10):
42 | '''
43 | for this to work, you need to analyze a large part of the baseline
44 | tune lam and p until you get the desired result
45 | '''
46 | return self._baseline_als(np.absolute(z_data),lam,p,niter=niter)
47 |
48 | def baseline_func_amp(self,z_data,f_data,lam,p,niter=10):
49 | '''
50 | for this to work, you need to analyze a large part of the baseline
51 | tune lam and p until you get the desired result
52 | returns the baseline as a function
53 | the points in between the datapoints are computed by cubic interpolation
54 | '''
55 | return interp1d(f_data, self._baseline_als(np.absolute(z_data),lam,p,niter=niter), kind='cubic')
56 |
57 | def baseline_func_phase(self,z_data,f_data,lam,p,niter=10):
58 | '''
59 | for this to work, you need to analyze a large part of the baseline
60 | tune lam and p until you get the desired result
61 | returns the baseline as a function
62 | the points in between the datapoints are computed by cubic interpolation
63 | '''
64 | return interp1d(f_data, self._baseline_als(np.angle(z_data),lam,p,niter=niter), kind='cubic')
65 |
66 | def fit_baseline_phase(self,z_data,lam,p,niter=10):
67 | '''
68 | for this to work, you need to analyze a large part of the baseline
69 | tune lam and p until you get the desired result
70 | '''
71 | return self._baseline_als(np.angle(z_data),lam,p,niter=niter)
72 |
73 | def GUIbaselinefit(self):
74 | '''
75 | A GUI to help you fit the baseline
76 | '''
77 | self.__lam = 1e6
78 | self.__p = 0.9
79 | niter = 10
80 | self.__baseline = self._baseline_als(np.absolute(self.z_data_raw),self.__lam,self.__p,niter=niter)
81 | import matplotlib.pyplot as plt
82 | from matplotlib.widgets import Slider
83 | fig, (ax0,ax1) = plt.subplots(nrows=2)
84 | plt.suptitle('Use the sliders to make the green curve match the baseline.')
85 | plt.subplots_adjust(left=0.25, bottom=0.25)
86 | l0, = ax0.plot(np.absolute(self.z_data_raw))
87 | l0b, = ax0.plot(np.absolute(self.__baseline))
88 | l1, = ax1.plot(np.absolute(self.z_data_raw/self.__baseline))
89 | ax0.set_ylabel('amp, rawdata vs. baseline')
90 | ax1.set_ylabel('amp, corrected')
91 | axcolor = 'lightgoldenrodyellow'
92 | axSmooth = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
93 | axAsym = plt.axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
94 | axbcorr = plt.axes([0.25, 0.05, 0.65, 0.03], axisbg=axcolor)
95 | sSmooth = Slider(axSmooth, 'Smoothness', 0.1, 10., valinit=np.log10(self.__lam),valfmt='1E%f')
96 | sAsym = Slider(axAsym, 'Asymmetry', 1e-4,0.99999, valinit=self.__p,valfmt='%f')
97 | sbcorr = Slider(axbcorr, 'vertical shift',0.7,1.1,valinit=1.)
98 | def update(val):
99 | self.__lam = 10**sSmooth.val
100 | self.__p = sAsym.val
101 | self.__baseline = sbcorr.val*self._baseline_als(np.absolute(self.z_data_raw),self.__lam,self.__p,niter=niter)
102 | l0.set_ydata(np.absolute(self.z_data_raw))
103 | l0b.set_ydata(np.absolute(self.__baseline))
104 | l1.set_ydata(np.absolute(self.z_data_raw/self.__baseline))
105 | fig.canvas.draw_idle()
106 | sSmooth.on_changed(update)
107 | sAsym.on_changed(update)
108 | sbcorr.on_changed(update)
109 | plt.show()
110 | self.z_data_raw /= self.__baseline
111 | plt.close()
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/resonator_tools/circlefit.py:
--------------------------------------------------------------------------------
1 |
2 | import numpy as np
3 | import scipy.optimize as spopt
4 | from scipy import stats
5 |
6 |
7 | class circlefit(object):
8 | '''
9 | contains all the circlefit procedures
10 | see http://scitation.aip.org/content/aip/journal/rsi/86/2/10.1063/1.4907935
11 | arxiv version: http://arxiv.org/abs/1410.3365
12 | '''
13 | def _remove_cable_delay(self,f_data,z_data, delay):
14 | return z_data/np.exp(2j*np.pi*f_data*delay)
15 |
16 | def _center(self,z_data,zc):
17 | return z_data-zc
18 |
19 | def _dist(self,x):
20 | np.absolute(x,x)
21 | c = (x > np.pi).astype(int)
22 | return x+c*(-2.*x+2.*np.pi)
23 |
24 | def _periodic_boundary(self,x,bound):
25 | return np.fmod(x,bound)-np.trunc(x/bound)*bound
26 |
27 | def _phase_fit_wslope(self,f_data,z_data,theta0, Ql, fr, slope):
28 | phase = np.angle(z_data)
29 | def residuals(p,x,y):
30 | theta0, Ql, fr, slope = p
31 | err = self._dist(y - (theta0+2.*np.arctan(2.*Ql*(1.-x/fr))-slope*x))
32 | return err
33 | p0 = [theta0, Ql, fr, slope]
34 | p_final = spopt.leastsq(residuals,p0,args=(np.array(f_data),np.array(phase)))
35 | return p_final[0]
36 |
37 | def _phase_fit(self,f_data,z_data,theta0, Ql, fr):
38 | phase = np.angle(z_data)
39 | def residuals_1(p,x,y,Ql):
40 | theta0, fr = p
41 | err = self._dist(y - (theta0+2.*np.arctan(2.*Ql*(1.-x/fr))))
42 | return err
43 | def residuals_2(p,x,y,theta0):
44 | Ql, fr = p
45 | err = self._dist(y - (theta0+2.*np.arctan(2.*Ql*(1.-x/fr))))
46 | return err
47 | def residuals_3(p,x,y,theta0,Ql):
48 | fr = p
49 | err = self._dist(y - (theta0+2.*np.arctan(2.*Ql*(1.-x/fr))))
50 | return err
51 | def residuals_4(p,x,y,theta0,fr):
52 | Ql = p
53 | err = self._dist(y - (theta0+2.*np.arctan(2.*Ql*(1.-x/fr))))
54 | return err
55 | def residuals_5(p,x,y):
56 | theta0, Ql, fr = p
57 | err = self._dist(y - (theta0+2.*np.arctan(2.*Ql*(1.-x/fr))))
58 | return err
59 | p0 = [theta0, fr]
60 | p_final = spopt.leastsq(lambda a,b,c: residuals_1(a,b,c,Ql),p0,args=(f_data,phase))#,ftol=1e-12,xtol=1e-12)
61 | theta0, fr = p_final[0]
62 | p0 = [Ql, fr]
63 | p_final = spopt.leastsq(lambda a,b,c: residuals_2(a,b,c,theta0),p0,args=(f_data,phase))#,ftol=1e-12,xtol=1e-12)
64 | Ql, fr = p_final[0]
65 | p0 = fr
66 | p_final = spopt.leastsq(lambda a,b,c: residuals_3(a,b,c,theta0,Ql),p0,args=(f_data,phase))#,ftol=1e-12,xtol=1e-12)
67 | fr = p_final[0][0]
68 | p0 = Ql
69 | p_final = spopt.leastsq(lambda a,b,c: residuals_4(a,b,c,theta0,fr),p0,args=(f_data,phase))#,ftol=1e-12,xtol=1e-12)
70 | Ql = p_final[0][0]
71 | p0 = np.array([theta0, Ql, fr], dtype='float64')
72 | p_final = spopt.leastsq(residuals_5,p0,args=(f_data,phase))
73 | return p_final[0]
74 |
75 | def _fit_skewed_lorentzian(self,f_data,z_data):
76 | amplitude = np.absolute(z_data)
77 | amplitude_sqr = amplitude**2
78 | A1a = np.minimum(amplitude_sqr[0],amplitude_sqr[-1])
79 | A3a = -np.max(amplitude_sqr)
80 | fra = f_data[np.argmin(amplitude_sqr)]
81 | def residuals(p,x,y):
82 | A2, A4, Ql = p
83 | err = y -(A1a+A2*(x-fra)+(A3a+A4*(x-fra))/(1.+4.*Ql**2*((x-fra)/fra)**2))
84 | return err
85 | p0 = [0., 0., 1e3]
86 | p_final = spopt.leastsq(residuals,p0,args=(np.array(f_data),np.array(amplitude_sqr)))
87 | A2a, A4a, Qla = p_final[0]
88 |
89 | def residuals2(p,x,y):
90 | A1, A2, A3, A4, fr, Ql = p
91 | err = y -(A1+A2*(x-fr)+(A3+A4*(x-fr))/(1.+4.*Ql**2*((x-fr)/fr)**2))
92 | return err
93 | def fitfunc(x,A1, A2, A3, A4, fr, Ql):
94 | return A1+A2*(x-fr)+(A3+A4*(x-fr))/(1.+4.*Ql**2*((x-fr)/fr)**2)
95 |
96 | p0 = [A1a, A2a , A3a, A4a, fra, Qla]
97 | #p_final = spopt.leastsq(residuals2,p0,args=(np.array(f_data),np.array(amplitude_sqr)))
98 | try:
99 | popt, pcov = spopt.curve_fit(fitfunc, np.array(f_data), np.array(amplitude_sqr),p0=p0)
100 | #A1, A2, A3, A4, fr, Ql = p_final[0]
101 | #print(p_final[0][5])
102 | if pcov is not None:
103 | self.df_error = np.sqrt(pcov[4][4])
104 | self.dQl_error = np.sqrt(pcov[5][5])
105 | else:
106 | self.df_error = np.inf
107 | self.dQl_error = np.inf
108 | except:
109 | popt = p0
110 | self.df_error = np.inf
111 | self.dQl_error = np.inf
112 | #return p_final[0]
113 | return popt
114 |
115 | def _fit_circle(self,z_data, refine_results=False):
116 | def calc_moments(z_data):
117 | xi = z_data.real
118 | xi_sqr = xi*xi
119 | yi = z_data.imag
120 | yi_sqr = yi*yi
121 | zi = xi_sqr+yi_sqr
122 | Nd = float(len(xi))
123 | xi_sum = xi.sum()
124 | yi_sum = yi.sum()
125 | zi_sum = zi.sum()
126 | xiyi_sum = (xi*yi).sum()
127 | xizi_sum = (xi*zi).sum()
128 | yizi_sum = (yi*zi).sum()
129 | return np.array([ [(zi*zi).sum(), xizi_sum, yizi_sum, zi_sum], \
130 | [xizi_sum, xi_sqr.sum(), xiyi_sum, xi_sum], \
131 | [yizi_sum, xiyi_sum, yi_sqr.sum(), yi_sum], \
132 | [zi_sum, xi_sum, yi_sum, Nd] ])
133 |
134 | M = calc_moments(z_data)
135 |
136 | a0 = ((M[2][0]*M[3][2]-M[2][2]*M[3][0])*M[1][1]-M[1][2]*M[2][0]*M[3][1]-M[1][0]*M[2][1]*M[3][2]+M[1][0]*M[2][2]*M[3][1]+M[1][2]*M[2][1]*M[3][0])*M[0][3]+(M[0][2]*M[2][3]*M[3][0]-M[0][2]*M[2][0]*M[3][3]+M[0][0]*M[2][2]*M[3][3]-M[0][0]*M[2][3]*M[3][2])*M[1][1]+(M[0][1]*M[1][3]*M[3][0]-M[0][1]*M[1][0]*M[3][3]-M[0][0]*M[1][3]*M[3][1])*M[2][2]+(-M[0][1]*M[1][2]*M[2][3]-M[0][2]*M[1][3]*M[2][1])*M[3][0]+((M[2][3]*M[3][1]-M[2][1]*M[3][3])*M[1][2]+M[2][1]*M[3][2]*M[1][3])*M[0][0]+(M[1][0]*M[2][3]*M[3][2]+M[2][0]*(M[1][2]*M[3][3]-M[1][3]*M[3][2]))*M[0][1]+((M[2][1]*M[3][3]-M[2][3]*M[3][1])*M[1][0]+M[1][3]*M[2][0]*M[3][1])*M[0][2]
137 | a1 = (((M[3][0]-2.*M[2][2])*M[1][1]-M[1][0]*M[3][1]+M[2][2]*M[3][0]+2.*M[1][2]*M[2][1]-M[2][0]*M[3][2])*M[0][3]+(2.*M[2][0]*M[3][2]-M[0][0]*M[3][3]-2.*M[2][2]*M[3][0]+2.*M[0][2]*M[2][3])*M[1][1]+(-M[0][0]*M[3][3]+2.*M[0][1]*M[1][3]+2.*M[1][0]*M[3][1])*M[2][2]+(-M[0][1]*M[1][3]+2.*M[1][2]*M[2][1]-M[0][2]*M[2][3])*M[3][0]+(M[1][3]*M[3][1]+M[2][3]*M[3][2])*M[0][0]+(M[1][0]*M[3][3]-2.*M[1][2]*M[2][3])*M[0][1]+(M[2][0]*M[3][3]-2.*M[1][3]*M[2][1])*M[0][2]-2.*M[1][2]*M[2][0]*M[3][1]-2.*M[1][0]*M[2][1]*M[3][2])
138 | a2 = ((2.*M[1][1]-M[3][0]+2.*M[2][2])*M[0][3]+(2.*M[3][0]-4.*M[2][2])*M[1][1]-2.*M[2][0]*M[3][2]+2.*M[2][2]*M[3][0]+M[0][0]*M[3][3]+4.*M[1][2]*M[2][1]-2.*M[0][1]*M[1][3]-2.*M[1][0]*M[3][1]-2.*M[0][2]*M[2][3])
139 | a3 = (-2.*M[3][0]+4.*M[1][1]+4.*M[2][2]-2.*M[0][3])
140 | a4 = -4.
141 |
142 | def func(x):
143 | return a0+a1*x+a2*x*x+a3*x*x*x+a4*x*x*x*x
144 |
145 | def d_func(x):
146 | return a1+2*a2*x+3*a3*x*x+4*a4*x*x*x
147 |
148 | x0 = spopt.fsolve(func, 0., fprime=d_func)
149 |
150 | def solve_eq_sys(val,M):
151 | #prepare
152 | M[3][0] = M[3][0]+2*val
153 | M[0][3] = M[0][3]+2*val
154 | M[1][1] = M[1][1]-val
155 | M[2][2] = M[2][2]-val
156 | return np.linalg.svd(M)
157 |
158 | U,s,Vt = solve_eq_sys(x0[0],M)
159 |
160 | A_vec = Vt[np.argmin(s),:]
161 |
162 | xc = -A_vec[1]/(2.*A_vec[0])
163 | yc = -A_vec[2]/(2.*A_vec[0])
164 | # the term *sqrt term corrects for the constraint, because it may be altered due to numerical inaccuracies during calculation
165 | r0 = 1./(2.*np.absolute(A_vec[0]))*np.sqrt(A_vec[1]*A_vec[1]+A_vec[2]*A_vec[2]-4.*A_vec[0]*A_vec[3])
166 | if refine_results:
167 | print("agebraic r0: " + str(r0))
168 | xc,yc,r0 = self._fit_circle_iter(z_data, xc, yc, r0)
169 | r0 = self._fit_circle_iter_radialweight(z_data, xc, yc, r0)
170 | print("iterative r0: " + str(r0))
171 | return xc, yc, r0
172 |
173 | def _guess_delay(self,f_data,z_data):
174 | phase2 = np.unwrap(np.angle(z_data))
175 | gradient, intercept, r_value, p_value, std_err = stats.linregress(f_data,phase2)
176 | return gradient*(-1.)/(np.pi*2.)
177 |
178 |
179 | def _fit_delay(self,f_data,z_data,delay=0.,maxiter=0):
180 | def residuals(p,x,y):
181 | phasedelay = p
182 | z_data_temp = y*np.exp(1j*(2.*np.pi*phasedelay*x))
183 | xc,yc,r0 = self._fit_circle(z_data_temp)
184 | err = np.sqrt((z_data_temp.real-xc)**2+(z_data_temp.imag-yc)**2)-r0
185 | return err
186 | p_final = spopt.leastsq(residuals,delay,args=(f_data,z_data),maxfev=maxiter,ftol=1e-12,xtol=1e-12)
187 | return p_final[0][0]
188 |
189 | def _fit_delay_alt_bigdata(self,f_data,z_data,delay=0.,maxiter=0):
190 | def residuals(p,x,y):
191 | phasedelay = p
192 | z_data_temp = 1j*2.*np.pi*phasedelay*x
193 | np.exp(z_data_temp,out=z_data_temp)
194 | np.multiply(y,z_data_temp,out=z_data_temp)
195 | #z_data_temp = y*np.exp(1j*(2.*np.pi*phasedelay*x))
196 | xc,yc,r0 = self._fit_circle(z_data_temp)
197 | err = np.sqrt((z_data_temp.real-xc)**2+(z_data_temp.imag-yc)**2)-r0
198 | return err
199 | p_final = spopt.leastsq(residuals,delay,args=(f_data,z_data),maxfev=maxiter,ftol=1e-12,xtol=1e-12)
200 | return p_final[0][0]
201 |
202 | def _fit_entire_model(self,f_data,z_data,fr,absQc,Ql,phi0,delay,a=1.,alpha=0.,maxiter=0):
203 | '''
204 | fits the whole model: a*exp(i*alpha)*exp(-2*pi*i*f*delay) * [ 1 - {Ql/Qc*exp(i*phi0)} / {1+2*i*Ql*(f-fr)/fr} ]
205 | '''
206 | def funcsqr(p,x):
207 | fr,absQc,Ql,phi0,delay,a,alpha = p
208 | return np.array([np.absolute( ( a*np.exp(complex(0,alpha))*np.exp(complex(0,-2.*np.pi*delay*x[i])) * ( 1 - (Ql/absQc*np.exp(complex(0,phi0)))/(complex(1,2*Ql*(x[i]-fr)/fr)) ) ) )**2 for i in range(len(x))])
209 | def residuals(p,x,y):
210 | fr,absQc,Ql,phi0,delay,a,alpha = p
211 | err = [np.absolute( y[i] - ( a*np.exp(complex(0,alpha))*np.exp(complex(0,-2.*np.pi*delay*x[i])) * ( 1 - (Ql/absQc*np.exp(complex(0,phi0)))/(complex(1,2*Ql*(x[i]-fr)/fr)) ) ) ) for i in range(len(x))]
212 | return err
213 | p0 = [fr,absQc,Ql,phi0,delay,a,alpha]
214 | (popt, params_cov, infodict, errmsg, ier) = spopt.leastsq(residuals,p0,args=(np.array(f_data),np.array(z_data)),full_output=True,maxfev=maxiter)
215 | len_ydata = len(np.array(f_data))
216 | if (len_ydata > len(p0)) and params_cov is not None: #p_final[1] is cov_x data #this caculation is from scipy curve_fit routine - no idea if this works correctly...
217 | s_sq = (funcsqr(popt, np.array(f_data))).sum()/(len_ydata-len(p0))
218 | params_cov = params_cov * s_sq
219 | else:
220 | params_cov = np.inf
221 | return popt, params_cov, infodict, errmsg, ier
222 |
223 | #
224 |
225 | def _optimizedelay(self,f_data,z_data,Ql,fr,maxiter=4):
226 | xc,yc,r0 = self._fit_circle(z_data)
227 | z_data = self._center(z_data,complex(xc,yc))
228 | theta, Ql, fr, slope = self._phase_fit_wslope(f_data,z_data,0.,Ql,fr,0.)
229 | delay = 0.
230 | for i in range(maxiter-1): #interate to get besser phase delay term
231 | delay = delay - slope/(2.*2.*np.pi)
232 | z_data_corr = self._remove_cable_delay(f_data,z_data,delay)
233 | xc, yc, r0 = self._fit_circle(z_data_corr)
234 | z_data_corr2 = self._center(z_data_corr,complex(xc,yc))
235 | theta0, Ql, fr, slope = self._phase_fit_wslope(f_data,z_data_corr2,0.,Ql,fr,0.)
236 | delay = delay - slope/(2.*2.*np.pi) #start final interation
237 | return delay
238 |
239 | def _fit_circle_iter(self,z_data, xc, yc, rc):
240 | '''
241 | this is the radial weighting procedure
242 | it improves your fitting value for the radius = Ql/Qc
243 | use this to improve your fit in presence of heavy noise
244 | after having used the standard algebraic fir_circle() function
245 | the weight here is: W=1/sqrt((xc-xi)^2+(yc-yi)^2)
246 | this works, because the center of the circle is usually much less
247 | corrupted by noise than the radius
248 | '''
249 | xdat = z_data.real
250 | ydat = z_data.imag
251 | def fitfunc(x,y,xc,yc):
252 | return np.sqrt((x-xc)**2+(y-yc)**2)
253 | def residuals(p,x,y):
254 | xc,yc,r = p
255 | temp = (r-fitfunc(x,y,xc,yc))
256 | return temp
257 | p0 = [xc,yc,rc]
258 | p_final = spopt.leastsq(residuals,p0,args=(xdat,ydat))
259 | xc,yc,rc = p_final[0]
260 | return xc,yc,rc
261 |
262 | def _fit_circle_iter_radialweight(self,z_data, xc, yc, rc):
263 | '''
264 | this is the radial weighting procedure
265 | it improves your fitting value for the radius = Ql/Qc
266 | use this to improve your fit in presence of heavy noise
267 | after having used the standard algebraic fir_circle() function
268 | the weight here is: W=1/sqrt((xc-xi)^2+(yc-yi)^2)
269 | this works, because the center of the circle is usually much less
270 | corrupted by noise than the radius
271 | '''
272 | xdat = z_data.real
273 | ydat = z_data.imag
274 | def fitfunc(x,y):
275 | return np.sqrt((x-xc)**2+(y-yc)**2)
276 | def weight(x,y):
277 | try:
278 | res = 1./np.sqrt((xc-x)**2+(yc-y)**2)
279 | except:
280 | res = 1.
281 | return res
282 | def residuals(p,x,y):
283 | r = p[0]
284 | temp = (r-fitfunc(x,y))*weight(x,y)
285 | return temp
286 | p0 = [rc]
287 | p_final = spopt.leastsq(residuals,p0,args=(xdat,ydat))
288 | return p_final[0][0]
289 |
290 | def _get_errors(self,residual,xdata,ydata,fitparams):
291 | '''
292 | wrapper for get_cov, only gives the errors and chisquare
293 | '''
294 | chisqr, cov = self._get_cov(residual,xdata,ydata,fitparams)
295 | if cov is not None:
296 | errors = np.sqrt(np.diagonal(cov))
297 | else:
298 | errors = None
299 | return chisqr, errors
300 |
301 | def _residuals_notch_full(self,p,x,y):
302 | fr,absQc,Ql,phi0,delay,a,alpha = p
303 | err = np.absolute( y - ( a*np.exp(complex(0,alpha))*np.exp(complex(0,-2.*np.pi*delay*x)) * ( 1 - (Ql/absQc*np.exp(complex(0,phi0)))/(complex(1,2*Ql*(x-fr)/float(fr))) ) ) )
304 | return err
305 |
306 | def _residuals_notch_ideal(self,p,x,y):
307 | fr,absQc,Ql,phi0 = p
308 | #if fr == 0: print(p)
309 | err = np.absolute( y - ( ( 1. - (Ql/float(absQc)*np.exp(1j*phi0))/(1+2j*Ql*(x-fr)/float(fr)) ) ) )
310 | #if np.isinf((complex(1,2*Ql*(x-fr)/float(fr))).imag):
311 | # print(complex(1,2*Ql*(x-fr)/float(fr)))
312 | # print("x: " + str(x))
313 | # print("Ql: " +str(Ql))
314 | #print("fr: " +str(fr))
315 | return err
316 |
317 | def _residuals_notch_ideal_complex(self,p,x,y):
318 | fr,absQc,Ql,phi0 = p
319 | #if fr == 0: print(p)
320 | err = y - ( ( 1. - (Ql/float(absQc)*np.exp(1j*phi0))/(1+2j*Ql*(x-fr)/float(fr)) ) )
321 | #if np.isinf((complex(1,2*Ql*(x-fr)/float(fr))).imag):
322 | # print(complex(1,2*Ql*(x-fr)/float(fr)))
323 | # print("x: " + str(x))
324 | # print("Ql: " +str(Ql))
325 | #print("fr: " +str(fr))
326 | return err
327 |
328 | def _residuals_directrefl(self,p,x,y):
329 | fr,Qc,Ql = p
330 | #if fr == 0: print(p)
331 | err = y - ( 2.*Ql/Qc - 1. + 2j*Ql*(fr-x)/fr ) / ( 1. - 2j*Ql*(fr-x)/fr )
332 | #if np.isinf((complex(1,2*Ql*(x-fr)/float(fr))).imag):
333 | # print(complex(1,2*Ql*(x-fr)/float(fr)))
334 | # print("x: " + str(x))
335 | # print("Ql: " +str(Ql))
336 | #print("fr: " +str(fr))
337 | return err
338 |
339 | def _residuals_transm_ideal(self,p,x,y):
340 | fr,Ql = p
341 | err = np.absolute( y - ( 1./(complex(1,2*Ql*(x-fr)/float(fr))) ) )
342 | return err
343 |
344 |
345 | def _get_cov_fast_notch(self,xdata,ydata,fitparams): #enhanced by analytical derivatives
346 | #derivatives of notch_ideal model with respect to parameters
347 | def dS21_dQl(p,f):
348 | fr,absQc,Ql,phi0 = p
349 | return - (np.exp(1j*phi0) * fr**2) / (absQc * (fr+2j*Ql*f-2j*Ql*fr)**2 )
350 |
351 | def dS21_dQc(p,f):
352 | fr,absQc,Ql,phi0 = p
353 | return (np.exp(1j*phi0) * Ql*fr) / (2j*(f-fr)*absQc**2*Ql+absQc**2*fr )
354 |
355 | def dS21_dphi0(p,f):
356 | fr,absQc,Ql,phi0 = p
357 | return - (1j*Ql*fr*np.exp(1j*phi0) ) / (2j*(f-fr)*absQc*Ql+absQc*fr )
358 |
359 | def dS21_dfr(p,f):
360 | fr,absQc,Ql,phi0 = p
361 | return - (2j*Ql**2*f*np.exp(1j*phi0) ) / (absQc * (fr+2j*Ql*f-2j*Ql*fr)**2 )
362 |
363 | u = self._residuals_notch_ideal_complex(fitparams,xdata,ydata)
364 | chi = np.absolute(u)
365 | u = u/chi # unit vector pointing in the correct direction for the derivative
366 |
367 | aa = dS21_dfr(fitparams,xdata)
368 | bb = dS21_dQc(fitparams,xdata)
369 | cc = dS21_dQl(fitparams,xdata)
370 | dd = dS21_dphi0(fitparams,xdata)
371 |
372 | Jt = np.array([aa.real*u.real+aa.imag*u.imag, bb.real*u.real+bb.imag*u.imag\
373 | , cc.real*u.real+cc.imag*u.imag, dd.real*u.real+dd.imag*u.imag ])
374 | A = np.dot(Jt,np.transpose(Jt))
375 | chisqr = 1./float(len(xdata)-len(fitparams)) * (chi**2).sum()
376 | try:
377 | cov = np.linalg.inv(A)*chisqr
378 | except:
379 | cov = None
380 | return chisqr, cov
381 |
382 | def _get_cov_fast_directrefl(self,xdata,ydata,fitparams): #enhanced by analytical derivatives
383 | #derivatives of notch_ideal model with respect to parameters
384 | def dS21_dQl(p,f):
385 | fr,Qc,Ql = p
386 | return 2.*fr**2/( Qc*(2j*Ql*fr-2j*Ql*f+fr)**2 )
387 |
388 | def dS21_dQc(p,f):
389 | fr,Qc,Ql = p
390 | return 2.*Ql*fr/(2j*Qc**2*(f-fr)*Ql-Qc**2*fr)
391 |
392 | def dS21_dfr(p,f):
393 | fr,Qc,Ql = p
394 | return - 4j*Ql**2*f/(Qc*(2j*Ql*fr-2j*Ql*f+fr)**2)
395 |
396 | u = self._residuals_directrefl(fitparams,xdata,ydata)
397 | chi = np.absolute(u)
398 | u = u/chi # unit vector pointing in the correct direction for the derivative
399 |
400 | aa = dS21_dfr(fitparams,xdata)
401 | bb = dS21_dQc(fitparams,xdata)
402 | cc = dS21_dQl(fitparams,xdata)
403 |
404 | Jt = np.array([aa.real*u.real+aa.imag*u.imag, bb.real*u.real+bb.imag*u.imag\
405 | , cc.real*u.real+cc.imag*u.imag ])
406 | A = np.dot(Jt,np.transpose(Jt))
407 | chisqr = 1./float(len(xdata)-len(fitparams)) * (chi**2).sum()
408 | try:
409 | cov = np.linalg.inv(A)*chisqr
410 | except:
411 | cov = None
412 | return chisqr, cov
--------------------------------------------------------------------------------
/resonator_tools/circuit.py:
--------------------------------------------------------------------------------
1 | import warnings
2 | import numpy as np
3 | import scipy.optimize as spopt
4 | from scipy.constants import hbar
5 | from scipy.interpolate import splrep, splev
6 |
7 | from resonator_tools.utilities import plotting, save_load, Watt2dBm, dBm2Watt
8 | from resonator_tools.circlefit import circlefit
9 | from resonator_tools.calibration import calibration
10 |
11 | ##
12 | ## z_data_raw denotes the raw data
13 | ## z_data denotes the normalized data
14 | ##
15 |
16 | class reflection_port(circlefit, save_load, plotting, calibration):
17 | '''
18 | normal direct port probed in reflection
19 | '''
20 | def __init__(self, f_data=None, z_data_raw=None):
21 | self.porttype = 'direct'
22 | self.fitresults = {}
23 | self.z_data = None
24 | if f_data is not None:
25 | self.f_data = np.array(f_data)
26 | else:
27 | self.f_data=None
28 | if z_data_raw is not None:
29 | self.z_data_raw = np.array(z_data_raw)
30 | else:
31 | self.z_data=None
32 | self.phasefitsmooth = 3
33 |
34 | def _S11(self,f,fr,k_c,k_i):
35 | '''
36 | use either frequency or angular frequency units
37 | for all quantities
38 | k_l=k_c+k_i: total (loaded) coupling rate
39 | k_c: coupling rate
40 | k_i: internal loss rate
41 | '''
42 | return ((k_c-k_i)+2j*(f-fr))/((k_c+k_i)-2j*(f-fr))
43 |
44 | def get_delay(self,f_data,z_data,delay=None,ignoreslope=True,guess=True):
45 | '''
46 | ignoreslope option not used here
47 | retrieves the cable delay assuming the ideal resonance has a circular shape
48 | modifies the cable delay until the shape Im(S21) vs Re(S21) is circular
49 | see "do_calibration"
50 | '''
51 | maxval = np.max(np.absolute(z_data))
52 | z_data = z_data/maxval
53 | A1, A2, A3, A4, fr, Ql = self._fit_skewed_lorentzian(f_data,z_data)
54 | if self.df_error/fr > 0.0001 or self.dQl_error/Ql>0.1:
55 | #print("WARNING: Calibration using Lorentz fit failed, trying phase fit...")
56 | A1 = np.mean(np.absolute(z_data))
57 | A2 = 0.
58 | A3 = 0.
59 | A4 = 0.
60 | #fr = np.mean(f_data)
61 | f = splrep(f_data,np.unwrap(np.angle(z_data)),k=5,s=self.phasefitsmooth)
62 | fr = f_data[np.argmax(np.absolute(splev(f_data,f,der=1)))]
63 | Ql = 1e4
64 | if ignoreslope==True:
65 | A2 = 0.
66 | else:
67 | A2 = 0.
68 | print("WARNING: The ignoreslope option is ignored! Corrections to the baseline should be done manually prior to fitting.")
69 | print("see also: resonator_tools.calibration.fit_baseline_amp() etc. for help on fitting the baseline.")
70 | print("There is also an example ipython notebook for using this function.")
71 | print("However, make sure to understand the impact of the baseline (parasitic coupled resonances etc.) on your system.")
72 | #z_data = (np.absolute(z_data)-A2*(f_data-fr)) * np.exp(np.angle(z_data)*1j) #usually not necessary
73 | if delay is None:
74 | if guess==True:
75 | delay = self._guess_delay(f_data,z_data)
76 | else:
77 | delay=0.
78 | delay = self._fit_delay(f_data,z_data,delay,maxiter=200)
79 | params = [A1, A2, A3, A4, fr, Ql]
80 | return delay, params
81 |
82 | def do_calibration(self,f_data,z_data,ignoreslope=True,guessdelay=True,fixed_delay=None):
83 | '''
84 | calculating parameters for normalization
85 | '''
86 | delay, params = self.get_delay(f_data,z_data,ignoreslope=ignoreslope,guess=guessdelay,delay=fixed_delay)
87 | z_data = (z_data-params[1]*(f_data-params[4]))*np.exp(2.*1j*np.pi*delay*f_data)
88 | xc, yc, r0 = self._fit_circle(z_data)
89 | zc = complex(xc,yc)
90 | fitparams = self._phase_fit(f_data,self._center(z_data,zc),0.,np.absolute(params[5]),params[4])
91 | theta, Ql, fr = fitparams
92 | beta = self._periodic_boundary(theta+np.pi,np.pi) ###
93 | offrespoint = complex((xc+r0*np.cos(beta)),(yc+r0*np.sin(beta)))
94 | alpha = self._periodic_boundary(np.angle(offrespoint)+np.pi,np.pi)
95 | #a = np.absolute(offrespoint)
96 | #alpha = np.angle(zc)
97 | a = r0 + np.absolute(zc)
98 | return delay, a, alpha, fr, Ql, params[1], params[4]
99 |
100 | def do_normalization(self,f_data,z_data,delay,amp_norm,alpha,A2,frcal):
101 | '''
102 | transforming resonator into canonical position
103 | '''
104 | return (z_data-A2*(f_data-frcal))/amp_norm*np.exp(1j*(-alpha+2.*np.pi*delay*f_data))
105 |
106 | def circlefit(self,f_data,z_data,fr=None,Ql=None,refine_results=False,calc_errors=True):
107 | '''
108 | S11 version of the circlefit
109 | '''
110 |
111 | if fr is None: fr=f_data[np.argmin(np.absolute(z_data))]
112 | if Ql is None: Ql=1e6
113 | xc, yc, r0 = self._fit_circle(z_data,refine_results=refine_results)
114 | phi0 = -np.arcsin(yc/r0)
115 | theta0 = self._periodic_boundary(phi0+np.pi,np.pi)
116 | z_data_corr = self._center(z_data,complex(xc,yc))
117 | theta0, Ql, fr = self._phase_fit(f_data,z_data_corr,theta0,Ql,fr)
118 | #print("Ql from phasefit is: " + str(Ql))
119 | Qi = Ql/(1.-r0)
120 | Qc = 1./(1./Ql-1./Qi)
121 |
122 | results = {"Qi":Qi,"Qc":Qc,"Ql":Ql,"fr":fr,"theta0":theta0}
123 |
124 | #calculation of the error
125 | p = [fr,Qc,Ql]
126 | #chi_square, errors = rt.get_errors(rt.residuals_notch_ideal,f_data,z_data,p)
127 | if calc_errors==True:
128 | chi_square, cov = self._get_cov_fast_directrefl(f_data,z_data,p)
129 | #chi_square, cov = rt.get_cov(rt.residuals_notch_ideal,f_data,z_data,p)
130 |
131 | if cov is not None:
132 | errors = np.sqrt(np.diagonal(cov))
133 | fr_err,Qc_err,Ql_err = errors
134 | #calc Qi with error prop (sum the squares of the variances and covariaces)
135 | dQl = 1./((1./Ql-1./Qc)**2*Ql**2)
136 | dQc = - 1./((1./Ql-1./Qc)**2*Qc**2)
137 | Qi_err = np.sqrt((dQl**2*cov[2][2]) + (dQc**2*cov[1][1])+(2*dQl*dQc*cov[2][1])) #with correlations
138 | errors = {"Ql_err":Ql_err, "Qc_err":Qc_err, "fr_err":fr_err,"chi_square":chi_square,"Qi_err":Qi_err}
139 | results.update( errors )
140 | else:
141 | print("WARNING: Error calculation failed!")
142 | else:
143 | #just calc chisquared:
144 | fun2 = lambda x: self._residuals_notch_ideal(x,f_data,z_data)**2
145 | chi_square = 1./float(len(f_data)-len(p)) * (fun2(p)).sum()
146 | errors = {"chi_square":chi_square}
147 | results.update(errors)
148 |
149 | return results
150 |
151 |
152 | def autofit(self,electric_delay=None,fcrop=None):
153 | '''
154 | automatic calibration and fitting
155 | electric_delay: set the electric delay manually
156 | fcrop = (f1,f2) : crop the frequency range used for fitting
157 | '''
158 | if fcrop is None:
159 | self._fid = np.ones(self.f_data.size,dtype=bool)
160 | else:
161 | f1, f2 = fcrop
162 | self._fid = np.logical_and(self.f_data>=f1,self.f_data<=f2)
163 | delay, amp_norm, alpha, fr, Ql, A2, frcal =\
164 | self.do_calibration(self.f_data[self._fid],self.z_data_raw[self._fid],ignoreslope=True,guessdelay=False,fixed_delay=electric_delay)
165 | self.z_data = self.do_normalization(self.f_data,self.z_data_raw,delay,amp_norm,alpha,A2,frcal)
166 | self.fitresults = self.circlefit(self.f_data[self._fid],self.z_data[self._fid],fr,Ql,refine_results=False,calc_errors=True)
167 | self.z_data_sim = A2*(self.f_data-frcal)+self._S11_directrefl(self.f_data,fr=self.fitresults["fr"],Ql=self.fitresults["Ql"],Qc=self.fitresults["Qc"],a=amp_norm,alpha=alpha,delay=delay)
168 | self.z_data_sim_norm = self._S11_directrefl(self.f_data,fr=self.fitresults["fr"],Ql=self.fitresults["Ql"],Qc=self.fitresults["Qc"],a=1.,alpha=0.,delay=0.)
169 | self._delay = delay
170 |
171 | def GUIfit(self):
172 | '''
173 | automatic fit with possible user interaction to crop the data and modify the electric delay
174 | f1,f2,delay are determined in the GUI. Then, data is cropped and autofit with delay is performed
175 | '''
176 | #copy data
177 | fmin, fmax = self.f_data.min(), self.f_data.max()
178 | self.autofit()
179 | self.__delay = self._delay
180 | #prepare plot and slider
181 | import matplotlib.pyplot as plt
182 | from matplotlib.widgets import Slider, Button
183 | fig, ((ax2,ax0),(ax1,ax3)) = plt.subplots(nrows=2,ncols=2)
184 | plt.suptitle('Normalized data. Use the silders to improve the fitting if necessary.')
185 | plt.subplots_adjust(left=0.25, bottom=0.25)
186 | l0, = ax0.plot(self.f_data*1e-9,np.absolute(self.z_data))
187 | l1, = ax1.plot(self.f_data*1e-9,np.angle(self.z_data))
188 | l2, = ax2.plot(np.real(self.z_data),np.imag(self.z_data))
189 | l0s, = ax0.plot(self.f_data*1e-9,np.absolute(self.z_data_sim_norm))
190 | l1s, = ax1.plot(self.f_data*1e-9,np.angle(self.z_data_sim_norm))
191 | l2s, = ax2.plot(np.real(self.z_data_sim_norm),np.imag(self.z_data_sim_norm))
192 | ax0.set_xlabel('f (GHz)')
193 | ax1.set_xlabel('f (GHz)')
194 | ax2.set_xlabel('real')
195 | ax0.set_ylabel('amp')
196 | ax1.set_ylabel('phase (rad)')
197 | ax2.set_ylabel('imagl')
198 | fr_ann = ax3.annotate('fr = %e Hz +- %e Hz' % (self.fitresults['fr'],self.fitresults['fr_err']),xy=(0.1, 0.8), xycoords='axes fraction')
199 | Ql_ann = ax3.annotate('Ql = %e +- %e' % (self.fitresults['Ql'],self.fitresults['Ql_err']),xy=(0.1, 0.6), xycoords='axes fraction')
200 | Qc_ann = ax3.annotate('Qc = %e +- %e' % (self.fitresults['Qc'],self.fitresults['Qc_err']),xy=(0.1, 0.4), xycoords='axes fraction')
201 | Qi_ann = ax3.annotate('Qi = %e +- %e' % (self.fitresults['Qi'],self.fitresults['Qi_err']),xy=(0.1, 0.2), xycoords='axes fraction')
202 | axcolor = 'lightgoldenrodyellow'
203 | axdelay = plt.axes([0.25, 0.05, 0.65, 0.03], axisbg=axcolor)
204 | axf2 = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
205 | axf1 = plt.axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
206 | sscale = 10.
207 | sdelay = Slider(axdelay, 'delay', -1., 1., valinit=self.__delay/(sscale*self.__delay),valfmt='%f')
208 | df = (fmax-fmin)*0.05
209 | sf2 = Slider(axf2, 'f2', (fmin-df)*1e-9, (fmax+df)*1e-9, valinit=fmax*1e-9,valfmt='%.10f GHz')
210 | sf1 = Slider(axf1, 'f1', (fmin-df)*1e-9, (fmax+df)*1e-9, valinit=fmin*1e-9,valfmt='%.10f GHz')
211 | def update(val):
212 | self.autofit(electric_delay=sdelay.val*sscale*self.__delay,fcrop=(sf1.val*1e9,sf2.val*1e9))
213 | l0.set_data(self.f_data*1e-9,np.absolute(self.z_data))
214 | l1.set_data(self.f_data*1e-9,np.angle(self.z_data))
215 | l2.set_data(np.real(self.z_data),np.imag(self.z_data))
216 | l0s.set_data(self.f_data[self._fid]*1e-9,np.absolute(self.z_data_sim_norm[self._fid]))
217 | l1s.set_data(self.f_data[self._fid]*1e-9,np.angle(self.z_data_sim_norm[self._fid]))
218 | l2s.set_data(np.real(self.z_data_sim_norm[self._fid]),np.imag(self.z_data_sim_norm[self._fid]))
219 | fr_ann.set_text('fr = %e Hz +- %e Hz' % (self.fitresults['fr'],self.fitresults['fr_err']))
220 | Ql_ann.set_text('Ql = %e +- %e' % (self.fitresults['Ql'],self.fitresults['Ql_err']))
221 | Qc_ann.set_text('Qc = %e +- %e' % (self.fitresults['Qc'],self.fitresults['Qc_err']))
222 | Qi_ann.set_text('Qi = %e +- %e' % (self.fitresults['Qi'],self.fitresults['Qi_err']))
223 | fig.canvas.draw_idle()
224 | def btnclicked(event):
225 | self.autofit(electric_delay=None,fcrop=(sf1.val*1e9,sf2.val*1e9))
226 | self.__delay = self._delay
227 | sdelay.reset()
228 | update(event)
229 | sf1.on_changed(update)
230 | sf2.on_changed(update)
231 | sdelay.on_changed(update)
232 | btnax = plt.axes([0.05, 0.1, 0.1, 0.04])
233 | button = Button(btnax, 'auto-delay', color=axcolor, hovercolor='0.975')
234 | button.on_clicked(btnclicked)
235 | plt.show()
236 | plt.close()
237 |
238 | def _S11_directrefl(self,f,fr=10e9,Ql=900,Qc=1000.,a=1.,alpha=0.,delay=.0):
239 | '''
240 | full model for notch type resonances
241 | '''
242 | return a*np.exp(complex(0,alpha))*np.exp(-2j*np.pi*f*delay) * ( 2.*Ql/Qc - 1. + 2j*Ql*(fr-f)/fr ) / ( 1. - 2j*Ql*(fr-f)/fr )
243 |
244 | def get_single_photon_limit(self,unit='dBm'):
245 | '''
246 | returns the amout of power in units of W necessary
247 | to maintain one photon on average in the cavity
248 | unit can be 'dbm' or 'watt'
249 | '''
250 | if self.fitresults!={}:
251 | fr = self.fitresults['fr']
252 | k_c = 2*np.pi*fr/self.fitresults['Qc']
253 | k_i = 2*np.pi*fr/self.fitresults['Qi']
254 | if unit=='dBm':
255 | return Watt2dBm(1./(4.*k_c/(2.*np.pi*hbar*fr*(k_c+k_i)**2)))
256 | elif unit=='watt':
257 | return 1./(4.*k_c/(2.*np.pi*hbar*fr*(k_c+k_i)**2))
258 |
259 | else:
260 | warnings.warn('Please perform the fit first',UserWarning)
261 | return None
262 |
263 | def get_photons_in_resonator(self,power,unit='dBm'):
264 | '''
265 | returns the average number of photons
266 | for a given power (defaul unit is 'dbm')
267 | unit can be 'dBm' or 'watt'
268 | '''
269 | if self.fitresults!={}:
270 | if unit=='dBm':
271 | power = dBm2Watt(power)
272 | fr = self.fitresults['fr']
273 | k_c = 2*np.pi*fr/self.fitresults['Qc']
274 | k_i = 2*np.pi*fr/self.fitresults['Qi']
275 | return 4.*k_c/(2.*np.pi*hbar*fr*(k_c+k_i)**2) * power
276 | else:
277 | warnings.warn('Please perform the fit first',UserWarning)
278 | return None
279 |
280 | class notch_port(circlefit, save_load, plotting, calibration):
281 | '''
282 | notch type port probed in transmission
283 | '''
284 | def __init__(self, f_data=None, z_data_raw=None):
285 | self.porttype = 'notch'
286 | self.fitresults = {}
287 | self.z_data = None
288 | if f_data is not None:
289 | self.f_data = np.array(f_data)
290 | else:
291 | self.f_data=None
292 | if z_data_raw is not None:
293 | self.z_data_raw = np.array(z_data_raw)
294 | else:
295 | self.z_data_raw=None
296 |
297 | def get_delay(self,f_data,z_data,delay=None,ignoreslope=True,guess=True):
298 | '''
299 | retrieves the cable delay assuming the ideal resonance has a circular shape
300 | modifies the cable delay until the shape Im(S21) vs Re(S21) is circular
301 | see "do_calibration"
302 | '''
303 | maxval = np.max(np.absolute(z_data))
304 | z_data = z_data/maxval
305 | A1, A2, A3, A4, fr, Ql = self._fit_skewed_lorentzian(f_data,z_data)
306 | if ignoreslope==True:
307 | A2 = 0.
308 | else:
309 | A2 = 0.
310 | print("WARNING: The ignoreslope option is ignored! Corrections to the baseline should be done manually prior to fitting.")
311 | print("see also: resonator_tools.calibration.fit_baseline_amp() etc. for help on fitting the baseline.")
312 | print("There is also an example ipython notebook for using this function.")
313 | print("However, make sure to understand the impact of the baseline (parasitic coupled resonances etc.) on your system.")
314 | #z_data = (np.absolute(z_data)-A2*(f_data-fr)) * np.exp(np.angle(z_data)*1j) #usually not necessary
315 | if delay is None:
316 | if guess==True:
317 | delay = self._guess_delay(f_data,z_data)
318 | else:
319 | delay=0.
320 | delay = self._fit_delay(f_data,z_data,delay,maxiter=200)
321 | params = [A1, A2, A3, A4, fr, Ql]
322 | return delay, params
323 |
324 | def do_calibration(self,f_data,z_data,ignoreslope=True,guessdelay=True,fixed_delay=None, Ql_guess=None, fr_guess=None):
325 | '''
326 | performs an automated calibration and tries to determine the prefactors a, alpha, delay
327 | fr, Ql, and a possible slope are extra information, which can be used as start parameters for subsequent fits
328 | see also "do_normalization"
329 | the calibration procedure works for transmission line resonators as well
330 | '''
331 | delay, params = self.get_delay(f_data,z_data,ignoreslope=ignoreslope,guess=guessdelay,delay=fixed_delay)
332 | z_data = (z_data-params[1]*(f_data-params[4]))*np.exp(2.*1j*np.pi*delay*f_data)
333 | xc, yc, r0 = self._fit_circle(z_data)
334 | zc = complex(xc,yc)
335 | if Ql_guess is None: Ql_guess=np.absolute(params[5])
336 | if fr_guess is None: fr_guess=params[4]
337 | fitparams = self._phase_fit(f_data,self._center(z_data,zc),0.,Ql_guess,fr_guess)
338 | theta, Ql, fr = fitparams
339 | beta = self._periodic_boundary(theta+np.pi,np.pi)
340 | offrespoint = complex((xc+r0*np.cos(beta)),(yc+r0*np.sin(beta)))
341 | alpha = np.angle(offrespoint)
342 | a = np.absolute(offrespoint)
343 | return delay, a, alpha, fr, Ql, params[1], params[4]
344 |
345 | def do_normalization(self,f_data,z_data,delay,amp_norm,alpha,A2,frcal):
346 | '''
347 | removes the prefactors a, alpha, delay and returns the calibrated data, see also "do_calibration"
348 | works also for transmission line resonators
349 | '''
350 | return (z_data-A2*(f_data-frcal))/amp_norm*np.exp(1j*(-alpha+2.*np.pi*delay*f_data))
351 |
352 | def circlefit(self,f_data,z_data,fr=None,Ql=None,refine_results=False,calc_errors=True):
353 | '''
354 | performs a circle fit on a frequency vs. complex resonator scattering data set
355 | Data has to be normalized!!
356 | INPUT:
357 | f_data,z_data: input data (frequency, complex S21 data)
358 | OUTPUT:
359 | outpus a dictionary {key:value} consisting of the fit values, errors and status information about the fit
360 | values: {"phi0":phi0, "Ql":Ql, "absolute(Qc)":absQc, "Qi": Qi, "electronic_delay":delay, "complexQc":complQc, "resonance_freq":fr, "prefactor_a":a, "prefactor_alpha":alpha}
361 | errors: {"phi0_err":phi0_err, "Ql_err":Ql_err, "absolute(Qc)_err":absQc_err, "Qi_err": Qi_err, "electronic_delay_err":delay_err, "resonance_freq_err":fr_err, "prefactor_a_err":a_err, "prefactor_alpha_err":alpha_err}
362 | for details, see:
363 | [1] (not diameter corrected) Jiansong Gao, "The Physics of Superconducting Microwave Resonators" (PhD Thesis), Appendix E, California Institute of Technology, (2008)
364 | [2] (diameter corrected) M. S. Khalil, et. al., J. Appl. Phys. 111, 054510 (2012)
365 | [3] (fitting techniques) N. CHERNOV AND C. LESORT, "Least Squares Fitting of Circles", Journal of Mathematical Imaging and Vision 23, 239, (2005)
366 | [4] (further fitting techniques) P. J. Petersan, S. M. Anlage, J. Appl. Phys, 84, 3392 (1998)
367 | the program fits the circle with the algebraic technique described in [3], the rest of the fitting is done with the scipy.optimize least square fitting toolbox
368 | also, check out [5] S. Probst et al. "Efficient and reliable analysis of noisy complex scatterung resonator data for superconducting quantum circuits" (in preparation)
369 | '''
370 |
371 | if fr is None: fr=f_data[np.argmin(np.absolute(z_data))]
372 | if Ql is None: Ql=1e6
373 | xc, yc, r0 = self._fit_circle(z_data,refine_results=refine_results)
374 | phi0 = -np.arcsin(yc/r0)
375 | theta0 = self._periodic_boundary(phi0+np.pi,np.pi)
376 | z_data_corr = self._center(z_data,complex(xc,yc))
377 | theta0, Ql, fr = self._phase_fit(f_data,z_data_corr,theta0,Ql,fr)
378 | #print("Ql from phasefit is: " + str(Ql))
379 | absQc = Ql/(2.*r0)
380 | complQc = absQc*np.exp(1j*((-1.)*phi0))
381 | Qc = 1./(1./complQc).real # here, taking the real part of (1/complQc) from diameter correction method
382 | Qi_dia_corr = 1./(1./Ql-1./Qc)
383 | Qi_no_corr = 1./(1./Ql-1./absQc)
384 |
385 | results = {"Qi_dia_corr":Qi_dia_corr,"Qi_no_corr":Qi_no_corr,"absQc":absQc,"Qc_dia_corr":Qc,"Ql":Ql,"fr":fr,"theta0":theta0,"phi0":phi0}
386 |
387 | #calculation of the error
388 | p = [fr,absQc,Ql,phi0]
389 | #chi_square, errors = rt.get_errors(rt.residuals_notch_ideal,f_data,z_data,p)
390 | if calc_errors==True:
391 | chi_square, cov = self._get_cov_fast_notch(f_data,z_data,p)
392 | #chi_square, cov = rt.get_cov(rt.residuals_notch_ideal,f_data,z_data,p)
393 |
394 | if cov is not None:
395 | errors = np.sqrt(np.diagonal(cov))
396 | fr_err,absQc_err,Ql_err,phi0_err = errors
397 | #calc Qi with error prop (sum the squares of the variances and covariaces)
398 | dQl = 1./((1./Ql-1./absQc)**2*Ql**2)
399 | dabsQc = - 1./((1./Ql-1./absQc)**2*absQc**2)
400 | Qi_no_corr_err = np.sqrt((dQl**2*cov[2][2]) + (dabsQc**2*cov[1][1])+(2*dQl*dabsQc*cov[2][1])) #with correlations
401 | #calc Qi dia corr with error prop
402 | dQl = 1/((1/Ql-np.cos(phi0)/absQc)**2 *Ql**2)
403 | dabsQc = -np.cos(phi0)/((1/Ql-np.cos(phi0)/absQc)**2 *absQc**2)
404 | dphi0 = -np.sin(phi0)/((1/Ql-np.cos(phi0)/absQc)**2 *absQc)
405 | ##err1 = ( (dQl*cov[2][2])**2 + (dabsQc*cov[1][1])**2 + (dphi0*cov[3][3])**2 )
406 | err1 = ( (dQl**2*cov[2][2]) + (dabsQc**2*cov[1][1]) + (dphi0**2*cov[3][3]) )
407 | err2 = ( dQl*dabsQc*cov[2][1] + dQl*dphi0*cov[2][3] + dabsQc*dphi0*cov[1][3] )
408 | Qi_dia_corr_err = np.sqrt(err1+2*err2) # including correlations
409 | errors = {"phi0_err":phi0_err, "Ql_err":Ql_err, "absQc_err":absQc_err, "fr_err":fr_err,"chi_square":chi_square,"Qi_no_corr_err":Qi_no_corr_err,"Qi_dia_corr_err": Qi_dia_corr_err}
410 | results.update( errors )
411 | else:
412 | print("WARNING: Error calculation failed!")
413 | else:
414 | #just calc chisquared:
415 | fun2 = lambda x: self._residuals_notch_ideal(x,f_data,z_data)**2
416 | chi_square = 1./float(len(f_data)-len(p)) * (fun2(p)).sum()
417 | errors = {"chi_square":chi_square}
418 | results.update(errors)
419 |
420 | return results
421 |
422 | def autofit(self,electric_delay=None,fcrop=None,Ql_guess=None, fr_guess=None):
423 | '''
424 | automatic calibration and fitting
425 | electric_delay: set the electric delay manually
426 | fcrop = (f1,f2) : crop the frequency range used for fitting
427 | '''
428 | if fcrop is None:
429 | self._fid = np.ones(self.f_data.size,dtype=bool)
430 | else:
431 | f1, f2 = fcrop
432 | self._fid = np.logical_and(self.f_data>=f1,self.f_data<=f2)
433 | delay, amp_norm, alpha, fr, Ql, A2, frcal =\
434 | self.do_calibration(self.f_data[self._fid],self.z_data_raw[self._fid],ignoreslope=True,guessdelay=True,fixed_delay=electric_delay,Ql_guess=Ql_guess, fr_guess=fr_guess)
435 | self.z_data = self.do_normalization(self.f_data,self.z_data_raw,delay,amp_norm,alpha,A2,frcal)
436 | self.fitresults = self.circlefit(self.f_data[self._fid],self.z_data[self._fid],fr,Ql,refine_results=False,calc_errors=True)
437 | self.z_data_sim = A2*(self.f_data-frcal)+self._S21_notch(self.f_data,fr=self.fitresults["fr"],Ql=self.fitresults["Ql"],Qc=self.fitresults["absQc"],phi=self.fitresults["phi0"],a=amp_norm,alpha=alpha,delay=delay)
438 | self.z_data_sim_norm = self._S21_notch(self.f_data,fr=self.fitresults["fr"],Ql=self.fitresults["Ql"],Qc=self.fitresults["absQc"],phi=self.fitresults["phi0"],a=1.0,alpha=0.,delay=0.)
439 | self._delay = delay
440 |
441 | def GUIfit(self):
442 | '''
443 | automatic fit with possible user interaction to crop the data and modify the electric delay
444 | f1,f2,delay are determined in the GUI. Then, data is cropped and autofit with delay is performed
445 | '''
446 | #copy data
447 | fmin, fmax = self.f_data.min(), self.f_data.max()
448 | self.autofit()
449 | self.__delay = self._delay
450 | #prepare plot and slider
451 | import matplotlib.pyplot as plt
452 | from matplotlib.widgets import Slider, Button
453 | fig, ((ax2,ax0),(ax1,ax3)) = plt.subplots(nrows=2,ncols=2)
454 | plt.suptitle('Normalized data. Use the silders to improve the fitting if necessary.')
455 | plt.subplots_adjust(left=0.25, bottom=0.25)
456 | l0, = ax0.plot(self.f_data*1e-9,np.absolute(self.z_data))
457 | l1, = ax1.plot(self.f_data*1e-9,np.angle(self.z_data))
458 | l2, = ax2.plot(np.real(self.z_data),np.imag(self.z_data))
459 | l0s, = ax0.plot(self.f_data*1e-9,np.absolute(self.z_data_sim_norm))
460 | l1s, = ax1.plot(self.f_data*1e-9,np.angle(self.z_data_sim_norm))
461 | l2s, = ax2.plot(np.real(self.z_data_sim_norm),np.imag(self.z_data_sim_norm))
462 | ax0.set_xlabel('f (GHz)')
463 | ax1.set_xlabel('f (GHz)')
464 | ax2.set_xlabel('real')
465 | ax0.set_ylabel('amp')
466 | ax1.set_ylabel('phase (rad)')
467 | ax2.set_ylabel('imagl')
468 | fr_ann = ax3.annotate('fr = %e Hz +- %e Hz' % (self.fitresults['fr'],self.fitresults['fr_err']),xy=(0.1, 0.8), xycoords='axes fraction')
469 | Ql_ann = ax3.annotate('Ql = %e +- %e' % (self.fitresults['Ql'],self.fitresults['Ql_err']),xy=(0.1, 0.6), xycoords='axes fraction')
470 | Qc_ann = ax3.annotate('Qc = %e +- %e' % (self.fitresults['absQc'],self.fitresults['absQc_err']),xy=(0.1, 0.4), xycoords='axes fraction')
471 | Qi_ann = ax3.annotate('Qi = %e +- %e' % (self.fitresults['Qi_dia_corr'],self.fitresults['Qi_dia_corr_err']),xy=(0.1, 0.2), xycoords='axes fraction')
472 | axcolor = 'lightgoldenrodyellow'
473 | axdelay = plt.axes([0.25, 0.05, 0.65, 0.03], facecolor=axcolor)
474 | axf2 = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
475 | axf1 = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
476 | sscale = 10.
477 | sdelay = Slider(axdelay, 'delay', -1., 1., valinit=self.__delay/(sscale*self.__delay),valfmt='%f')
478 | df = (fmax-fmin)*0.05
479 | sf2 = Slider(axf2, 'f2', (fmin-df)*1e-9, (fmax+df)*1e-9, valinit=fmax*1e-9,valfmt='%.10f GHz')
480 | sf1 = Slider(axf1, 'f1', (fmin-df)*1e-9, (fmax+df)*1e-9, valinit=fmin*1e-9,valfmt='%.10f GHz')
481 | def update(val):
482 | self.autofit(electric_delay=sdelay.val*sscale*self.__delay,fcrop=(sf1.val*1e9,sf2.val*1e9))
483 | l0.set_data(self.f_data*1e-9,np.absolute(self.z_data))
484 | l1.set_data(self.f_data*1e-9,np.angle(self.z_data))
485 | l2.set_data(np.real(self.z_data),np.imag(self.z_data))
486 | l0s.set_data(self.f_data[self._fid]*1e-9,np.absolute(self.z_data_sim_norm[self._fid]))
487 | l1s.set_data(self.f_data[self._fid]*1e-9,np.angle(self.z_data_sim_norm[self._fid]))
488 | l2s.set_data(np.real(self.z_data_sim_norm[self._fid]),np.imag(self.z_data_sim_norm[self._fid]))
489 | fr_ann.set_text('fr = %e Hz +- %e Hz' % (self.fitresults['fr'],self.fitresults['fr_err']))
490 | Ql_ann.set_text('Ql = %e +- %e' % (self.fitresults['Ql'],self.fitresults['Ql_err']))
491 | Qc_ann.set_text('|Qc| = %e +- %e' % (self.fitresults['absQc'],self.fitresults['absQc_err']))
492 | Qi_ann.set_text('Qi_dia_corr = %e +- %e' % (self.fitresults['Qi_dia_corr'],self.fitresults['Qi_dia_corr_err']))
493 | fig.canvas.draw_idle()
494 | def btnclicked(event):
495 | self.autofit(electric_delay=None,fcrop=(sf1.val*1e9,sf2.val*1e9))
496 | self.__delay = self._delay
497 | sdelay.reset()
498 | update(event)
499 | sf1.on_changed(update)
500 | sf2.on_changed(update)
501 | sdelay.on_changed(update)
502 | btnax = plt.axes([0.05, 0.1, 0.1, 0.04])
503 | button = Button(btnax, 'auto-delay', color=axcolor, hovercolor='0.975')
504 | button.on_clicked(btnclicked)
505 | plt.show()
506 | plt.close()
507 |
508 | def _S21_notch(self,f,fr=10e9,Ql=900,Qc=1000.,phi=0.,a=1.,alpha=0.,delay=.0):
509 | '''
510 | full model for notch type resonances
511 | '''
512 | return a*np.exp(complex(0,alpha))*np.exp(-2j*np.pi*f*delay)*(1.-Ql/Qc*np.exp(1j*phi)/(1.+2j*Ql*(f-fr)/fr))
513 |
514 | def get_single_photon_limit(self,unit='dBm',diacorr=True):
515 | '''
516 | returns the amout of power in units of W necessary
517 | to maintain one photon on average in the cavity
518 | unit can be 'dBm' or 'watt'
519 | '''
520 | if self.fitresults!={}:
521 | fr = self.fitresults['fr']
522 | if diacorr:
523 | k_c = 2*np.pi*fr/self.fitresults['Qc_dia_corr']
524 | k_i = 2*np.pi*fr/self.fitresults['Qi_dia_corr']
525 | else:
526 | k_c = 2*np.pi*fr/self.fitresults['absQc']
527 | k_i = 2*np.pi*fr/self.fitresults['Qi_no_corr']
528 | if unit=='dBm':
529 | return Watt2dBm(1./(4.*k_c/(2.*np.pi*hbar*fr*(k_c+k_i)**2)))
530 | elif unit=='watt':
531 | return 1./(4.*k_c/(2.*np.pi*hbar*fr*(k_c+k_i)**2))
532 | else:
533 | warnings.warn('Please perform the fit first',UserWarning)
534 | return None
535 |
536 | def get_photons_in_resonator(self,power,unit='dBm',diacorr=True):
537 | '''
538 | returns the average number of photons
539 | for a given power in units of W
540 | unit can be 'dBm' or 'watt'
541 | '''
542 | if self.fitresults!={}:
543 | if unit=='dBm':
544 | power = dBm2Watt(power)
545 | fr = self.fitresults['fr']
546 | if diacorr:
547 | k_c = 2*np.pi*fr/self.fitresults['Qc_dia_corr']
548 | k_i = 2*np.pi*fr/self.fitresults['Qi_dia_corr']
549 | else:
550 | k_c = 2*np.pi*fr/self.fitresults['absQc']
551 | k_i = 2*np.pi*fr/self.fitresults['Qi_no_corr']
552 | return 4.*k_c/(2.*np.pi*hbar*fr*(k_c+k_i)**2) * power
553 | else:
554 | warnings.warn('Please perform the fit first',UserWarning)
555 | return None
556 |
557 | class transmission_port(circlefit,save_load,plotting):
558 | '''
559 | a class for handling transmission measurements
560 | '''
561 |
562 | def __init__(self,f_data=None,z_data_raw=None):
563 | self.porttype = 'transm'
564 | self.fitresults = {}
565 | if f_data is not None:
566 | self.f_data = np.array(f_data)
567 | else:
568 | self.f_data=None
569 | if z_data_raw is not None:
570 | self.z_data_raw = np.array(z_data_raw)
571 | else:
572 | self.z_data=None
573 |
574 | def _S21(self,f,fr,Ql,A):
575 | return A**2/(1.+4.*Ql**2*((f-fr)/fr)**2)
576 |
577 | def fit(self):
578 | self.ampsqr = (np.absolute(self.z_data_raw))**2
579 | p = [self.f_data[np.argmax(self.ampsqr)],1000.,np.amax(self.ampsqr)]
580 | popt, pcov = spopt.curve_fit(self._S21, self.f_data, self.ampsqr,p)
581 | errors = np.sqrt(np.diag(pcov))
582 | self.fitresults = {'fr':popt[0],'fr_err':errors[0],'Ql':popt[1],'Ql_err':errors[1],'Ampsqr':popt[2],'Ampsqr_err':errors[2]}
583 |
584 | class resonator(object):
585 | '''
586 | Universal resonator analysis class
587 | It can handle different kinds of ports and assymetric resonators.
588 | '''
589 | def __init__(self, ports = {}, comment = None):
590 | '''
591 | initializes the resonator class object
592 | ports (dictionary {key:value}): specify the name and properties of the coupling ports
593 | e.g. ports = {'1':'direct', '2':'notch'}
594 | comment: add a comment
595 | '''
596 | self.comment = comment
597 | self.port = {}
598 | self.transm = {}
599 | if len(ports) > 0:
600 | for key, pname in iter(ports.items()):
601 | if pname=='direct':
602 | self.port.update({key:reflection_port()})
603 | elif pname=='notch':
604 | self.port.update({key:notch_port()})
605 | else:
606 | warnings.warn("Undefined input type! Use 'direct' or 'notch'.", SyntaxWarning)
607 | if len(self.port) == 0: warnings.warn("Resonator has no coupling ports!", UserWarning)
608 |
609 | def add_port(self,key,pname):
610 | if pname=='direct':
611 | self.port.update({key:reflection_port()})
612 | elif pname=='notch':
613 | self.port.update({key:notch_port()})
614 | else:
615 | warnings.warn("Undefined input type! Use 'direct' or 'notch'.", SyntaxWarning)
616 | if len(self.port) == 0: warnings.warn("Resonator has no coupling ports!", UserWarning)
617 |
618 | def delete_port(self,key):
619 | del self.port[key]
620 | if len(self.port) == 0: warnings.warn("Resonator has no coupling ports!", UserWarning)
621 |
622 | def get_Qi(self):
623 | '''
624 | based on the number of ports and the corresponding measurements
625 | it calculates the internal losses
626 | '''
627 | pass
628 |
629 | def get_single_photon_limit(self,port):
630 | '''
631 | returns the amout of power necessary to maintain one photon
632 | on average in the cavity
633 | '''
634 | pass
635 |
636 | def get_photons_in_resonator(self,power,port):
637 | '''
638 | returns the average number of photons
639 | for a given power
640 | '''
641 | pass
642 |
643 | def add_transm_meas(self,port1, port2):
644 | '''
645 | input: port1
646 | output: port2
647 | adds a transmission measurement
648 | connecting two direct ports S21
649 | '''
650 | key = port1 + " -> " + port2
651 | self.port.update({key:transm()})
652 | pass
653 |
654 |
655 | class batch_processing(object):
656 | '''
657 | A class for batch processing of resonator data as a function of another variable
658 | Typical applications are power scans, magnetic field scans etc.
659 | '''
660 |
661 | def __init__(self,porttype):
662 | '''
663 | porttype = 'notch', 'direct', 'transm'
664 | results is an array of dictionaries containing the fitresults
665 | '''
666 | self.porttype = porttype
667 | self.results = []
668 |
669 | def autofit(self,cal_dataslice = 0):
670 | '''
671 | fits all data
672 | cal_dataslice: choose scatteringdata which should be used for calibration
673 | of the amplitude and phase, default = 0 (first)
674 | '''
675 | pass
676 |
677 | class coupled_resonators(batch_processing):
678 | '''
679 | A class for fitting a resonator coupled to a second one
680 | '''
681 |
682 | def __init__(self,porttype):
683 | self.porttype = porttype
684 | self.results = []
685 |
686 | #def GUIfit(porttype,f_data,z_data_raw):
687 | # '''
688 | # GUI based fitting process enabeling cutting the data and manually setting the delay
689 | # It employs the Matplotlib widgets
690 | # return f1, f2 and delay, which should be employed for the real fitting
691 | # '''
692 | # if porttype=='direct':
693 | # p = reflection_port(f_data=f_data,z_data_raw=z_data_raw)
694 | # elif porttype =='notch':
695 | # p = notch_port(f_data=f_data,z_data_raw=z_data_raw)
696 | # else:
697 | # warnings.warn('Not supported!')
698 | # return None
699 | # import matplotlib.pyplot as plt
700 | # from matplotlib.widgets import Slider, Button, RadioButtons
701 | # #plt.style.use('ggplot')
702 | # fig, axes = plt.subplots(nrows=2,ncols=2)
703 | #
704 | # return f1,f2,delay
--------------------------------------------------------------------------------
/resonator_tools/noise.py:
--------------------------------------------------------------------------------
1 |
2 | ######
3 | ## Functions to evaluate noise data
4 | ######
5 |
6 | import warnings
7 | import numpy as np
8 | from scipy.signal import periodogram
9 |
10 |
11 | class noisedata(object):
12 |
13 | def __init__(self,IQ,IQref,fr,Ql,fs,gain_corr=[1.,1.],Z=50):
14 | '''
15 | units are assumed to be in volts
16 | -> IQ = I+1j*Q ; with amplitude signal on Q and phase on I
17 | this signal is measured on resonance
18 | -> IQref = Iref+1j*Qref ; with amplitude signal on Qref and phase on Iref
19 | this signal is measured far off resonance
20 | IMPORTANT: IQ and IQref describe signals on opposite sides of the resonance circle
21 | Therefore, take care that Q and Qref have the correct signs in order that
22 | the program can determine the diameter of the resonance circle.
23 | -> fr: resonance frequency
24 | -> Ql: loaded Q of the resonator
25 | -> fs: sampling rate
26 | -> gain_corr = [1.,1.] ; enter here if the gain of IQ and IQref signals
27 | are different
28 | -> Z: impedance
29 | The signals will be normalized to the reference such that IQref = 1.
30 | '''
31 | self.Z = Z
32 | self.fr = fr
33 | self.Ql = Ql
34 | self.offrespoint = np.mean(np.imag(IQref))
35 | self.respoint = np.mean(np.imag(IQref))
36 | self.radius = (self.offrespoint - self.respoint)/self.offrespoint
37 | self.P_I = periodogram(self._demean(np.real(IQ)),fs=fs)
38 | self.P_Q = periodogram(self._demean(np.imag(IQ)),fs=fs)
39 | self.P_Iref = periodogram(self._demean(np.real(IQref)),fs=fs)
40 | self.P_Qref = periodogram(self._demean(np.imag(IQref)),fs=fs)
41 |
42 | #################################
43 | #functions to evalate multiple things
44 | def P_I_eval_all(self):
45 | '''
46 | returns a 2D numpy array with all the results
47 | and a 1D list with the description
48 | '''
49 | comment = ['P_I','P_Inorm','P_Ipower','P_dtheta','P_dphi','P_df','P_']
50 | return np.vstack((self.P_I,self.P_Inorm(),self.P_Ipower(),self.P_dtheta(),self.P_dphi(),self.P_df(),self.P_())), comment
51 |
52 | def P_Iref_eval_all(self):
53 | '''
54 | returns a 2D numpy array with all the results
55 | and a 1D list with the description
56 | '''
57 | comment = ['P_Iref','P_Irefnorm','P_Irefpower','P_refdtheta','P_refdphi','P_refdf','P_ref']
58 | return np.vstack((self.P_Iref,self.P_Irefnorm(),self.P_Irefpower(),self.P_refdtheta(),self.P_refdphi(),self.P_refdf(),self.P_ref())), comment
59 |
60 | def P_Q_eval_all(self):
61 | '''
62 | returns a 2D numpy array with all the results
63 | and a 1D list with the description
64 | '''
65 | comment = ['P_Q','P_Qnorm','P_Qpower']
66 | return np.vstack((self.P_Q,self.P_Qnorm(),self.P_Qpower())), comment
67 |
68 | def P_Qref_eval_all(self):
69 | '''
70 | returns a 2D numpy array with all the results
71 | and a 1D list with the description
72 | '''
73 | comment = ['P_Qref','P_Qrefnorm','P_Qrefpower']
74 | return np.vstack((self.P_Qref,self.P_Qrefnorm(),self.P_Qrefpower())), comment
75 |
76 | #################################
77 | #helpers
78 | def _demean(self,x):
79 | '''
80 | removes the mean value from x
81 | '''
82 | return x - x.mean()
83 |
84 |
85 | #################################
86 | #noise on I
87 |
88 | def P_Inorm(self):
89 | '''
90 | V^2/Hz
91 | '''
92 | return self.P_I/(self.offrespoint**2)
93 |
94 | def P_Ipower(self):
95 | '''
96 | W/Hz
97 | '''
98 | return self.P_I/self.Z
99 |
100 | def P_dtheta(self):
101 | '''
102 | rad^2/Hz
103 | phase noise on the resonator circle phase
104 | (this is not the real measured phase)
105 | '''
106 | return self.P_Inorm()/self.r**2
107 |
108 | def P_dphi(self):
109 | '''
110 | rad^2/Hz
111 | phase noise on the phase measured with the VNA
112 | '''
113 | return self.P_Inorm()/np.absolute(self.respoint**2)
114 |
115 | def P_df(self):
116 | '''
117 | Hz^2/Hz
118 | frequency noise
119 | '''
120 | return self.P_theta() * self.fr**2 / (16.*self.Ql**2)
121 |
122 | def P_(self):
123 | '''
124 | 1/Hz
125 | fractional frequency noise
126 | '''
127 | return self.P_theta() / (16.*self.Ql**2)
128 |
129 | #################################
130 | #noise on Iref
131 |
132 | def P_Irefnorm(self):
133 | '''
134 | V^2/Hz
135 | '''
136 | return self.P_Iref/(self.offrespoint**2)
137 |
138 | def P_Irefpower(self):
139 | '''
140 | W/Hz
141 | '''
142 | return self.P_Iref/self.Z
143 |
144 | def P_refdtheta(self):
145 | '''
146 | rad^2/Hz
147 | phase noise on the resonator circle phase
148 | (this is not the real measured phase)
149 | '''
150 | return self.P_Irefnorm()/self.r**2
151 |
152 | def P_refdphi(self):
153 | '''
154 | rad^2/Hz
155 | phase noise on the phase measured with the VNA
156 | '''
157 | return self.P_Irefnorm()/np.absolute(self.respoint**2)
158 |
159 | def P_refdf(self):
160 | '''
161 | Hz^2/Hz
162 | frequency noise
163 | '''
164 | return self.P_reftheta() * self.fr**2 / (16.*self.Ql**2)
165 |
166 | def P_ref(self):
167 | '''
168 | 1/Hz
169 | fractional frequency noise
170 | '''
171 | return self.P_reftheta() / (16.*self.Ql**2)
172 |
173 | #################################
174 | #noise on Q
175 |
176 | def P_Qnorm(self):
177 | '''
178 | V^2/Hz
179 | '''
180 | return self.P_Q/(self.offrespoint**2)
181 |
182 | def P_Qpower(self):
183 | '''
184 | W/Hz
185 | '''
186 | return self.P_Q/self.Z
187 |
188 | #################################
189 | #noise on Qref
190 |
191 | def P_Qrefnorm(self):
192 | '''
193 | V^2/Hz
194 | '''
195 | return self.P_Qref/(self.offrespoint**2)
196 |
197 | def P_Qrefpower(self):
198 | '''
199 | W/Hz
200 | '''
201 | return self.P_Qref/self.Z
202 |
203 |
--------------------------------------------------------------------------------
/resonator_tools/utilities.py:
--------------------------------------------------------------------------------
1 | import warnings
2 | import numpy as np
3 | import matplotlib.pyplot as plt
4 |
5 | def Watt2dBm(x):
6 | '''
7 | converts from units of watts to dBm
8 | '''
9 | return 10.*np.log10(x*1000.)
10 |
11 | def dBm2Watt(x):
12 | '''
13 | converts from units of watts to dBm
14 | '''
15 | return 10**(x/10.) /1000.
16 |
17 | class plotting(object):
18 | '''
19 | some helper functions for plotting
20 | '''
21 | def plotall(self):
22 | real = self.z_data_raw.real
23 | imag = self.z_data_raw.imag
24 | real2 = self.z_data_sim.real
25 | imag2 = self.z_data_sim.imag
26 | plt.subplot(221)
27 | plt.plot(real,imag,label='rawdata')
28 | plt.plot(real2,imag2,label='fit')
29 | plt.xlabel('Re(S21)')
30 | plt.ylabel('Im(S21)')
31 | plt.legend()
32 | plt.subplot(222)
33 | plt.plot(self.f_data*1e-9,np.absolute(self.z_data_raw),label='rawdata')
34 | plt.plot(self.f_data*1e-9,np.absolute(self.z_data_sim),label='fit')
35 | plt.xlabel('f (GHz)')
36 | plt.ylabel('|S21|')
37 | plt.legend()
38 | plt.subplot(223)
39 | plt.plot(self.f_data*1e-9,np.angle(self.z_data_raw),label='rawdata')
40 | plt.plot(self.f_data*1e-9,np.angle(self.z_data_sim),label='fit')
41 | plt.xlabel('f (GHz)')
42 | plt.ylabel('arg(|S21|)')
43 | plt.legend()
44 | plt.show()
45 |
46 | def plotcalibrateddata(self):
47 | real = self.z_data.real
48 | imag = self.z_data.imag
49 | plt.subplot(221)
50 | plt.plot(real,imag,label='rawdata')
51 | plt.xlabel('Re(S21)')
52 | plt.ylabel('Im(S21)')
53 | plt.legend()
54 | plt.subplot(222)
55 | plt.plot(self.f_data*1e-9,np.absolute(self.z_data),label='rawdata')
56 | plt.xlabel('f (GHz)')
57 | plt.ylabel('|S21|')
58 | plt.legend()
59 | plt.subplot(223)
60 | plt.plot(self.f_data*1e-9,np.angle(self.z_data),label='rawdata')
61 | plt.xlabel('f (GHz)')
62 | plt.ylabel('arg(|S21|)')
63 | plt.legend()
64 | plt.show()
65 |
66 | def plotrawdata(self):
67 | real = self.z_data_raw.real
68 | imag = self.z_data_raw.imag
69 | plt.subplot(221)
70 | plt.plot(real,imag,label='rawdata')
71 | plt.xlabel('Re(S21)')
72 | plt.ylabel('Im(S21)')
73 | plt.legend()
74 | plt.subplot(222)
75 | plt.plot(self.f_data*1e-9,np.absolute(self.z_data_raw),label='rawdata')
76 | plt.xlabel('f (GHz)')
77 | plt.ylabel('|S21|')
78 | plt.legend()
79 | plt.subplot(223)
80 | plt.plot(self.f_data*1e-9,np.angle(self.z_data_raw),label='rawdata')
81 | plt.xlabel('f (GHz)')
82 | plt.ylabel('arg(|S21|)')
83 | plt.legend()
84 | plt.show()
85 |
86 | class save_load(object):
87 | '''
88 | procedures for loading and saving data used by other classes
89 | '''
90 | def _ConvToCompl(self,x,y,dtype):
91 | '''
92 | dtype = 'realimag', 'dBmagphaserad', 'linmagphaserad', 'dBmagphasedeg', 'linmagphasedeg'
93 | '''
94 | if dtype=='realimag':
95 | return x+1j*y
96 | elif dtype=='linmagphaserad':
97 | return x*np.exp(1j*y)
98 | elif dtype=='dBmagphaserad':
99 | return 10**(x/20.)*np.exp(1j*y)
100 | elif dtype=='linmagphasedeg':
101 | return x*np.exp(1j*y/180.*np.pi)
102 | elif dtype=='dBmagphasedeg':
103 | return 10**(x/20.)*np.exp(1j*y/180.*np.pi)
104 | else: warnings.warn("Undefined input type! Use 'realimag', 'dBmagphaserad', 'linmagphaserad', 'dBmagphasedeg' or 'linmagphasedeg'.", SyntaxWarning)
105 |
106 | def add_data(self,f_data,z_data):
107 | self.f_data = np.array(f_data)
108 | self.z_data_raw = np.array(z_data)
109 |
110 | def cut_data(self,f1,f2):
111 | def findpos(f_data,val):
112 | pos = 0
113 | for i in range(len(f_data)):
114 | if f_data[i]