From 017676a08f82576d2af417c576c8153b13e290eb Mon Sep 17 00:00:00 2001 From: Stephan Philips <s.g.j.philips@tudelft.nl> Date: Wed, 3 Jun 2020 10:53:39 +0200 Subject: [PATCH] added d5a --- core_tools.egg-info/SOURCES.txt | 6 +- .../data_getter/scan_generator_Keysight.py | 4 +- .../GUI/keysight_videomaps/liveplotting.py | 2 +- .../HVI/__pycache__/__init__.cpython-37.pyc | Bin 142 -> 135 bytes .../HVI_charge_stability_diagram.py | 26 +- ...VI_charge_stability_diagram.cpython-37.pyc | Bin 3990 -> 4056 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 184 -> 160 bytes .../HVI/single_shot_exp/HVI_single_shot.py | 34 +-- .../HVI_single_shot.cpython-37.pyc | Bin 2767 -> 3079 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 158 -> 151 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 138 -> 131 bytes core_tools/drivers/D5a.py | 150 +++++++++ core_tools/drivers/M3102A.py | 285 +++++++++--------- core_tools/drivers/M3102_firmware_loader.py | 33 ++ .../__pycache__/harware.cpython-37.pyc | Bin 5155 -> 5148 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 145 -> 138 bytes .../pulse_lib_sweep.cpython-37.pyc | Bin 8825 -> 8818 bytes core_tools/sweeps/exp_readout_runner.py | 145 +++++++++ core_tools/utility/dig_utility.py | 6 +- .../utility/digitizer_param_conversions.py | 210 +++++++++++++ core_tools/utility/powerpoint.py | 2 +- example_T2Hahn.py | 48 +++ .../__pycache__/__init__.cpython-37.pyc | Bin 69531 -> 69524 bytes 23 files changed, 774 insertions(+), 177 deletions(-) create mode 100644 core_tools/drivers/D5a.py create mode 100644 core_tools/drivers/M3102_firmware_loader.py create mode 100644 core_tools/sweeps/exp_readout_runner.py create mode 100644 core_tools/utility/digitizer_param_conversions.py create mode 100644 example_T2Hahn.py diff --git a/core_tools.egg-info/SOURCES.txt b/core_tools.egg-info/SOURCES.txt index 57af58f2..87e3eea8 100644 --- a/core_tools.egg-info/SOURCES.txt +++ b/core_tools.egg-info/SOURCES.txt @@ -1,3 +1,4 @@ +README.md setup.py core_tools/__init__.py core_tools.egg-info/PKG-INFO @@ -34,13 +35,8 @@ core_tools/GUI/param_viewer/param_viewer_GUI_window.py core_tools/HVI/__init__.py core_tools/HVI/charge_stability_diagram/HVI_charge_stability_diagram.py core_tools/HVI/charge_stability_diagram/__init__.py -core_tools/HVI/charge_stability_diagram_fast/HVI_charge_stability_diagram.py -core_tools/HVI/charge_stability_diagram_fast/__init__.py core_tools/HVI/single_shot_exp/HVI_single_shot.py core_tools/HVI/single_shot_exp/__init__.py -core_tools/HVI/single_shot_exp_SD_corr/HVI_single_shot.py -core_tools/HVI/single_shot_exp_SD_corr/__init__.py -core_tools/HVI/single_shot_exp_SD_corr/generate_SD_corr_sequence.py core_tools/sweeps/__init__.py core_tools/sweeps/pulse_lib_sweep.py core_tools/sweeps/Modulated_scans/DEMOD_tests.py diff --git a/core_tools/GUI/keysight_videomaps/data_getter/scan_generator_Keysight.py b/core_tools/GUI/keysight_videomaps/data_getter/scan_generator_Keysight.py index 5d003b66..efa219dd 100644 --- a/core_tools/GUI/keysight_videomaps/data_getter/scan_generator_Keysight.py +++ b/core_tools/GUI/keysight_videomaps/data_getter/scan_generator_Keysight.py @@ -5,8 +5,8 @@ Created on Fri Aug 9 16:50:02 2019 @author: V2 """ from qcodes import MultiParameter -from projects.keysight_measurement.HVI.ChargeStabilityDiagram.HVI_charge_stability_diagram import load_HVI, set_and_compile_HVI, excute_HVI, HVI_ID -from projects.keysight_measurement.M3102A import DATA_MODE +from core_tools.HVI.charge_stability_diagram.HVI_charge_stability_diagram import load_HVI, set_and_compile_HVI, excute_HVI, HVI_ID +from core_tools.drivers.M3102A import DATA_MODE import matplotlib.pyplot as plt import numpy as np import time diff --git a/core_tools/GUI/keysight_videomaps/liveplotting.py b/core_tools/GUI/keysight_videomaps/liveplotting.py index 359c2ab3..a1bf6fdb 100644 --- a/core_tools/GUI/keysight_videomaps/liveplotting.py +++ b/core_tools/GUI/keysight_videomaps/liveplotting.py @@ -13,7 +13,7 @@ from .data_getter import scan_generator_Virtual from .plotter.plotting_functions import _1D_live_plot, _2D_live_plot from qcodes import MultiParameter from qcodes.measure import Measure -from qtt.utilities.tools import addPPTslide +from core_tools.utility.powerpoint import addPPTslide import time import logging diff --git a/core_tools/HVI/__pycache__/__init__.cpython-37.pyc b/core_tools/HVI/__pycache__/__init__.cpython-37.pyc index af264deeb0e449be89943581b48da81e7bec6a57..e4c2bbbd43a89f35f89686d4f261a45c61a94348 100644 GIT binary patch delta 45 zcmeBUY-i+l;^pOH0D?W%hbD4ch#4eX#grMvC+DZ6#w6z#rN)=!=jRkpOwa=W20#s~ delta 52 zcmZo?>|^A1;^pOH0D@o2TPJc`$eJfx#Z=^^#3$#cq{gJAmZj$87v!eqm4F2%M(P0o DeJBvm diff --git a/core_tools/HVI/charge_stability_diagram/HVI_charge_stability_diagram.py b/core_tools/HVI/charge_stability_diagram/HVI_charge_stability_diagram.py index f9090862..949d19ae 100644 --- a/core_tools/HVI/charge_stability_diagram/HVI_charge_stability_diagram.py +++ b/core_tools/HVI/charge_stability_diagram/HVI_charge_stability_diagram.py @@ -8,7 +8,7 @@ try: except: warnings.warn("\nAttemting to use a file that needs Keysight AWG libraries. Please install if you need them.\n") -import V2_software.HVI_files.charge_stability_diagram as ct +import core_tools.HVI.charge_stability_diagram as ct import time HVI_ID = "HVI_charge_stability_diagram.HVI" @@ -33,12 +33,12 @@ def load_HVI(AWGs, channel_map, *args,**kwargs): HVI = keysightSD1.SD_HVI() a = HVI.open(ct.__file__[:-11] + "HVI_charge_stability_diagram.HVI") - error = HVI.assignHardwareWithUserNameAndSlot("Module 0",0,2) - error = HVI.assignHardwareWithUserNameAndSlot("Module 1",0,3) - error = HVI.assignHardwareWithUserNameAndSlot("Module 2",0,4) - error = HVI.assignHardwareWithUserNameAndSlot("Module 3",0,5) - error = HVI.assignHardwareWithUserNameAndSlot("Module 4",0,6) - + error1 = HVI.assignHardwareWithUserNameAndSlot("Module 0",0,2) + error2 = HVI.assignHardwareWithUserNameAndSlot("Module 1",0,3) + error3 = HVI.assignHardwareWithUserNameAndSlot("Module 2",0,4) + error4 = HVI.assignHardwareWithUserNameAndSlot("Module 3",0,5) + error5 = HVI.assignHardwareWithUserNameAndSlot("Module 4",0,6) + print(a, error1, error2, error3, error4, error5) HVI.compile() HVI.load() @@ -87,7 +87,7 @@ def excute_HVI(HVI, AWGs, channel_map, playback_time, n_rep, *args, **kwargs): length = int(playback_time/10 + 20) for awgname, awg in AWGs.items(): - awg.writeRegisterByNumber(3, int(length)) + awg.awg.writeRegisterByNumber(3, int(length)) dig = kwargs['digitizer'] t_single_point = kwargs['t_measure'] @@ -95,12 +95,12 @@ def excute_HVI(HVI, AWGs, channel_map, playback_time, n_rep, *args, **kwargs): t_single_point_formatted = int((t_single_point)/10) # divide by 10 since 100MHz clock (160 ns HVI overhead) - dig.writeRegisterByNumber(2, npt) - dig.writeRegisterByNumber(3, t_single_point_formatted) - + dig.SD_AIN.writeRegisterByNumber(2, npt) + dig.SD_AIN.writeRegisterByNumber(3, t_single_point_formatted) + if 'averaging' in kwargs: - dig.set_meas_time(kwargs['t_measure']) - dig.set_MAV_filter(16,1) + dig.set_meas_time(kwargs['t_measure'], fourchannel = True) + dig.set_MAV_filter(16,1, fourchannel = True) HVI.start() diff --git a/core_tools/HVI/charge_stability_diagram/__pycache__/HVI_charge_stability_diagram.cpython-37.pyc b/core_tools/HVI/charge_stability_diagram/__pycache__/HVI_charge_stability_diagram.cpython-37.pyc index 86e01ff890b58bae64f67c5126c2de13adcca9b7..025292859ab786d3674da877c1187e7e8d03aca9 100644 GIT binary patch delta 874 zcmY*Y&rcIU6yDiwx7+TI5`xf@2!=p$6U7Lkk;Ev7U@@uuP-94OQ#wN_w7bo8k&rB2 z^x%aUnP@y|d(?x8;b!86#FKx3X5!5gi6?Jz^39egZZhASZ{FLNZ@#ztviDoBIboU! z37#KM_8<KIVEVFU0*k@A4Xgf>J(FK&<AK`HaRMW(H<j%~$P8d6Fg;`zup}_UH-cE8 z1@Rye=z;NAMH1xArW8hN4=XPaO0vU9qbpjYW!LAiqF1ezD}+ZXUIE)Cdl$WSS0$8s z^gM6H;iEWm6fYdb(YF%q2bG6Q#j*UuVW;R}k}rCcIKJmq>c_V??`8Asc_hVh>N(WI z9;w}N)Q&Wy$uzU~M%_o3L?b&&PeR~kty0)pE)>@tzg#6e>N=FvXc|(qTY#u-!2o-u z^&^{o($eT7`>LJl$^@u^n$o1S)SZ{N6X1`&CN~sj#4paTMH&j$0;?&59Y)9^K~gXb z7O$)HJ)A}Z6{~3p?ACW$bt)ES3$DO>QX?kp#O8uzTYFFA-_g_^8*zQb+n~kOg6opX zK^q9n*&0{CVX6V)N@26aPi)e%Pv%LfT=xl`*vf5GmkH(S!lW~v&9NQbo)Pz_T>?@9 z1_hiJ@b~sS;({AI0xfD>tq`~5ukskQcMDZQN1&D~xLo49Mn{IHe5YP^OBLeOJka8- zc(hvZeS-h<aLnlI?37^|Fb_kvkOlj8)F#t$MvePuk$o{Pt68C9h9%5W+u*+;55Z)I z#AIWw(WSyEe>OYP8BuQw7#Er}#}NV@XOaCf&qlAq*&^$=&OrA$YdAS63U3IQ3NyRb uXx}vKLUSgw)AWkS-4Y;v3_2@djvZK6dxSk;0LBhzId-q`D;Z!@$=N@P?CW~~ delta 784 zcmY+C&ubGw6vuaVvy)BtM~d2*lw#AGgF#y%SWBy7Eu}v|R0tF;Tb3oWNu$Z`GP`Xr zTfFK)1c!Q*%~9|oy@?*Qe}Eo5$Y2j1{TKA&ytIV6FdyFc&6{~|-<u!fugA?r(;Sk- zS3la{eD&UpWh*BX7VExP5oa&uH?vxTQ=JSEMD(7rcdQJd%z?6m%AY8sCm~6kFb{T= zeS|D#sOfOF5p=_L$K#n!;F4;N9jXg=RgcnuzLn^>$n|HtF>mkGoJK%AI||$WR7iuz zUL%g|?Z~5%9mQU_<@)w|&543$yz5fWUR_^vn&R5XX5Y*r3-MJn#!@_*l{KWvbmHI; ze?b~tUsdTCd!dbv6osHA0Jx7)W*@Z*s<2;L3B6-~wem<MK`H7<OVVc1miLDC^h8f( zR?A&qPGzDcR!<iHXb3x#<iRGn1V6zv6+R`w1ec^9>PKXtZ~bT~RiQIPuS-?q;6v^w zI`ey2lyI+#xzhGystLh9=|y&=UwS$Q#T5YO0h54>fI<B{<5Mr>8R!eg9nWvYTN_z- zx8=KCk1N993Td}Ctk{X#eyig-VIb0Q#Si0+;{Q&k8PKj9#~wN9iVCU9?71;nI0wBH z-85ta8N#*%=`8zfJVcz0nsayoV(+j=W~(rLYB<w_;jph}$>h0#=0!2B64R`+r3pA& z0n7?;&2gZ5$KmXnHKophk2S3;A``P}`FRMu0l3-U`EJcj-U18Pmz<@w6*>cZi-2Xo e3SgC8&fmTOz2jMz5J!}8YV`d_P-f5a5B>q%*3l9G diff --git a/core_tools/HVI/charge_stability_diagram/__pycache__/__init__.cpython-37.pyc b/core_tools/HVI/charge_stability_diagram/__pycache__/__init__.cpython-37.pyc index dca38e504ef20a07126f6bdee1ad32042b8a70d8..a1d7f140b103c6c8d3f43764e3f5466a6d5dd128 100644 GIT binary patch delta 61 zcmdnNxPXzziI<m)0SNY3ABvmEW3K9%Y!y>x6rY@*k{XkoUz8eOlAoVbjLh^1^PJdV F0RS%A6n6js delta 85 zcmZ3$xPy_$iI<m)0SI2YUW}Q@V{V(6Y!y>x6rY@*k{VN7keR1jP?VpQnp{#GQ(Bx_ nR2)-Wl3I|Fm=_af6knX5R#Ki=lp5m^<{6)snUh*PF~b4?u3R2d diff --git a/core_tools/HVI/single_shot_exp/HVI_single_shot.py b/core_tools/HVI/single_shot_exp/HVI_single_shot.py index e87c7ce3..dacc568d 100644 --- a/core_tools/HVI/single_shot_exp/HVI_single_shot.py +++ b/core_tools/HVI/single_shot_exp/HVI_single_shot.py @@ -4,7 +4,7 @@ define a function that loads the HVI file that will be used thoughout the experi import keysightSD1 import core_tools.HVI.single_shot_exp as ct -HVI_ID = "HVI_single_shot_test.HVI" +HVI_ID = "HVI_single_shot.HVI" def load_HVI(AWGs, channel_map, *args,**kwargs): @@ -24,7 +24,7 @@ def load_HVI(AWGs, channel_map, *args,**kwargs): HVI = keysightSD1.SD_HVI() - error = HVI.open(ct.__file__[:-11] + "HVI_single_shot_test.HVI") + error = HVI.open(ct.__file__[:-11] + "HVI_single_shot.HVI") print(error) error = HVI.assignHardwareWithUserNameAndSlot("Module 0",0,2) @@ -33,6 +33,10 @@ def load_HVI(AWGs, channel_map, *args,**kwargs): print(error) error = HVI.assignHardwareWithUserNameAndSlot("Module 2",0,4) print(error) + error = HVI.assignHardwareWithUserNameAndSlot("Module 3",0,5) + print(error) + error = HVI.assignHardwareWithUserNameAndSlot("Module 4",0,6) + print(error) error = HVI.compile() print(error) @@ -87,23 +91,19 @@ def excute_HVI(HVI, AWGs, channel_map, playback_time, n_rep, *args, **kwargs): for awgname, awg in AWGs.items(): err = awg.awg.writeRegisterByNumber(2, int(nrep)) - print(err) err = awg.awg.writeRegisterByNumber(3, int(length)) - print(err) - - # dig = kwargs['digitizer'] - # dig_wait = kwargs['dig_wait'] - - # delay_1 = int(dig_wait/10) - # dig.writeRegisterByNumber(2, int(nrep)) - # dig.writeRegisterByNumber(4, int(delay_1)) - # dig.writeRegisterByNumber(3, int(length-delay_1-2)) - # if 'averaging' in kwargs: - # dig.set_meas_time(kwargs['t_measure']) - # dig.set_MAV_filter(16,1) + dig = kwargs['digitizer'] + dig_wait = kwargs['dig_wait'] + print(dig_wait) + delay_1 = int(dig_wait/10) + err = dig.SD_AIN.writeRegisterByNumber(2, int(nrep)) + err = dig.SD_AIN.writeRegisterByNumber(4, int(delay_1)) + err = dig.SD_AIN.writeRegisterByNumber(3, int(length-delay_1-2)) + + if 'averaging' in kwargs: + dig.set_meas_time(kwargs['t_measure'], fourchannel=True) + dig.set_MAV_filter(16,1, fourchannel=True) # start sequence err = AWGs['AWG1'].awg.writeRegisterByNumber(1, 0) - print(err) err = AWGs['AWG1'].awg.writeRegisterByNumber(0,int(1)) - print(err) diff --git a/core_tools/HVI/single_shot_exp/__pycache__/HVI_single_shot.cpython-37.pyc b/core_tools/HVI/single_shot_exp/__pycache__/HVI_single_shot.cpython-37.pyc index e6205378733f97db7ef69f3e3ed3f863a0013a72..11561082c9b27a133d61f22a935dc0989b3894a3 100644 GIT binary patch delta 956 zcmZ8g%}*0S6rbsC_p9A)DUq}^VnIx-G2ufKzfL72hzWSW$OV|JJ3}cfyExqfl5IF} zFlszBd-DW;fTteyq(=|j_dudIj^2#M#5Y?5gxSoSdB6AOH*ep2bA07>(V8+%1Ht(5 z_Up=%T*vyH>wo-wmNXk)-DRY?=66oYsav@7=lE)tW+|rTk<?a$OsF1Uj6&rwOD#Zi z(I;HP`R-plgfBBhW71@KPn+{;%Vm{2r)jwEOuc)mbXO!Dmn(q&o^c*7ZBG)%r)<gb zIU|AZyUpm0T*KqhH+d-fE)U?5?l1WZz9$Y;(|ib)*xYjMS1)X5g9MFD7N<SJ*%luJ z6E6!<ITORtPo;SC0qD&X2$bPBKsq8OF>){!m``Cg4IE9V<^B61KEy|88ZF;mO11U2 z5gO~MLy1ZO5?MG(wKM+_84#_9yc}7C?9g-xwX?7)u$qA!nj&l9Wl~&52e@s8+4b}# zt{$R-mnFFNfxZVN^r2NmR4T$@aWU0GWkca7;Gw`ZdI?d3X5OcuG}(0(3T7s{1UjZx z2_=D>G?xT@j^qMFA+&@szksTJ_B)J_p}W3KyC>=gyrR=ay%99_7>_mBk{!DdaFMlG zx3?L$>(DT<9*|9DH(Q)NtKvAb>bJPFW_uoUPxIi)MaE;fwm37vfga6QwODF+0oS6A zUfJ&#R%KzD)Mn>nv&nj7y^2~wovS@3s|`0`yqZhu&WnPzB*b+gMuj-5dMta;1+n5X zuO6($s=ZV9>`lhU!7G*+=dlET!mC16DO-jXA`=%|MHmdW>$Cz!;87$!F#;emG@MTr zZ~+gbG%UU>><f4hv_fLxkHD*H#3~`wcL?E`XvP?wN_sVS{<Z?bcDHz+xJMDMZg!dr W{-h-niVM+Hgkd=PXk3%Vw1I!%X7REB delta 718 zcmZuv&1(}u6rZ<~O*Wg4YHZVlgr<!>GzfwP4~mzDf-OQsMSF=3>CO<>=F8csO(7vd z4jv`!T^hu{AU6?&{sTR`ckg=f;6Z$|RcOS4_nVL3@4cD#-n_}3Ev2ieludAae*5v+ z`}8FJX)(9+WS4nvr`ZzBd)`${32*YHVEiJJA7}n|*o5S4-B^MD3jGIkb2g<>D6e49 zpEc)pz2D-@>2gu$;+1H1du`EC;eme|*;?Gtm&Y?k7K%`$7UaM({F0f6)!8lc6h=Bs z#gs*yf>f{7INonK2TZwb5ttn&MNj6Cl6ehUdk!Tnzv2nS8XbLmyXRsynAlAuJOhCw z<W)q+)N33`v?$trH18dPB7?{nM#C5`D2D>!#xfbh(CY6D-~^^*n>@W!H-_<{J+NOG zCzMlE#>Ox;h6xoJB*p;b4--MgnrB{?_s9UanJ1xdl*i`${xSv1@c}$K@64@7q!ORK zwmtxhZ0+5>A$3X;5NZ`Opl(M=olHO*N6ldANV-Zq6iwGtLROD!hwXhK<z*C9l3`_K zR=Y22Skq9}a9&scn_YOUn-oy=`M1Qj=sSlhtn5A1csdTTEx2T4AOjX!GOgz<$m_^d z>>$P%?>dahxIap)SHr$8T>NdK-;)cd4WjxV?rzIf+=RUfLtJ=4*zS`5HBqA1tn6=) Cm8r}C diff --git a/core_tools/HVI/single_shot_exp/__pycache__/__init__.cpython-37.pyc b/core_tools/HVI/single_shot_exp/__pycache__/__init__.cpython-37.pyc index f1adf6021ec9e7217b4e4cc083e02aa377af54c3..a0ccd6ef1aadb3bc5a81e6231ed0a2fd5d30a2f5 100644 GIT binary patch delta 45 zcmbQoIGvH(iI<m)0SNY3ADYN*A?A>56;oyupPZkP8k3w~lp0@>pPy4aF~JT14PXuH delta 52 zcmbQvIFFIriI<m)0SJC6Z=J|(A?u!O6;qLu5}%x(k{XkeT9%rVUyz%cR{|E87-<Ip Dg_sc! diff --git a/core_tools/__pycache__/__init__.cpython-37.pyc b/core_tools/__pycache__/__init__.cpython-37.pyc index 67a257e43c02d86619b43d0eafc7d3dfd5a51709..f5eacf945784c6cb047c3403090c6003467ba161 100644 GIT binary patch delta 45 zcmeBTY-Z$k;^pOH0D?W%hbD4ci0LF-#grMvC+DZ6#w6z#rN)=!=jRkpOwa-V1b7Xb delta 52 zcmZo>>|*40;^pOH0D@o2TPJc`$QmbG#Z=^^#3$#cq{gJAmZj$87v!eqm4F2%Mrr{7 Ddkhf2 diff --git a/core_tools/drivers/D5a.py b/core_tools/drivers/D5a.py new file mode 100644 index 00000000..3c090ab6 --- /dev/null +++ b/core_tools/drivers/D5a.py @@ -0,0 +1,150 @@ +from qcodes.instrument.base import Instrument +from qcodes.utils.validators import Enum, Numbers +import numpy as np + +try: + from spirack import D5a_module +except ImportError: + raise ImportError(('The D5a_module class could not be found. ' + 'Try installing it using pip install spirack')) + +from functools import partial + + +class D5a(Instrument): + """ + Qcodes driver for the D5a DAC SPI-rack module. + + functions: + - set_dacs_zero set all DACs to zero voltage + + parameters: + - dacN: get and set DAC voltage + - stepsizeN get the minimum step size corresponding to the span + - spanN get and set the DAC span: '4v uni', '4v bi', or '2.5v bi' + + where N is the DAC number from 1 up to 16 + + """ + + def __init__(self, name, spi_rack, module, inter_delay=0.1, dac_step=10e-3, + reset_voltages=False, mV=False, number_dacs=16, **kwargs): + """ Create instrument for the D5a module. + + The D5a module works with volts as units. For backward compatibility + there is the option to allow mV for the dacX parameters. + + The output span of the DAC module can be changed with the spanX + command. Be carefull when executing this command with a sample + connected as voltage jumps can occur. + + Args: + name (str): name of the instrument. + + spi_rack (SPI_rack): instance of the SPI_rack class as defined in + the spirack package. This class manages communication with the + individual modules. + + module (int): module number as set on the hardware. + inter_delay (float): time in seconds, passed to dac parameters of the object + dac_step (float): max step size (V or mV), passed to dac parameters of the object + reset_voltages (bool): passed to D5a_module constructor + mV (bool): if True, then use mV as units in the dac parameters + number_dacs (int): number of DACs available. This is 8 for the D5mux + """ + super().__init__(name, **kwargs) + + self.d5a = D5a_module(spi_rack, module, reset_voltages=reset_voltages) + self._number_dacs = number_dacs + + self._span_set_map = { + '4v uni': 0, + '4v bi': 2, + '2v bi': 4, + } + + self._span_get_map = {v: k for k, v in self._span_set_map.items()} + + self.add_function('set_dacs_zero', call_cmd=self._set_dacs_zero, + docstring='Reset all dacs to zero voltage. No ramping is performed.') + + if mV: + self._gain = 1e3 + unit = 'mV' + else: + self._gain = 1 + unit = 'V' + + # make a cache, to get a numerically not rounded value. + self.voltage_cache = np.zeros([number_dacs]) + for i in range(number_dacs): + self.voltage_cache[i] = self.__get_dac(i) + + for i in range(self._number_dacs): + validator = self._get_validator(i) + + self.add_parameter('dac{}'.format(i + 1), + label='DAC {}'.format(i + 1), + get_cmd=partial(self._get_dac, i), + set_cmd=partial(self._set_dac, i), + unit=unit, + vals=validator, + step=dac_step, + inter_delay=inter_delay) + + self.add_parameter('stepsize{}'.format(i + 1), + get_cmd=partial(self.d5a.get_stepsize, i), + unit='V', + docstring='Returns the smallest voltage step of the DAC.') + + self.add_parameter('span{}'.format(i + 1), + get_cmd=partial(self._get_span, i), + set_cmd=partial(self._set_span, i), + vals=Enum(*self._span_set_map.keys()), + docstring='Change the output span of the DAC. This command also updates the validator.') + + def set_dac_unit(self, unit: str) -> None: + """Set the unit of dac parameters""" + allowed_values = Enum('mV', 'V') + allowed_values.validate(unit) + self._gain = {'V': 1, 'mV': 1e3}[unit] + for i in range(1, self._number_dacs + 1): + setattr(self.parameters[f'dac{i}'], 'unit', unit) + setattr(self.parameters[f'dac{i}'], 'vals', self._get_validator(i - 1)) + + def _set_dacs_zero(self): + for i in range(self._number_dacs): + self._set_dac(i, 0.0) + + def _set_dac(self, dac, value): + self.voltage_cache[dac] = value + return self.d5a.set_voltage(dac, value / self._gain) + + def _get_dac(self, dac): + return self.voltage_cache[dac] + + def __get_dac(self, dac): + return self._gain * self.d5a.voltages[dac] + + def _get_span(self, dac): + return self._span_get_map[self.d5a.span[dac]] + + def _set_span(self, dac, span_str): + self.d5a.change_span_update(dac, self._span_set_map[span_str]) + self.parameters['dac{}'.format( + dac + 1)].vals = self._get_validator(dac) + + def _get_validator(self, dac): + span = self.d5a.span[dac] + + if span == D5a_module.range_2V_bi: + validator = Numbers(-2 * self._gain, 2 * self._gain) + elif span == D5a_module.range_4V_bi: + validator = Numbers(-4 * self._gain, 4 * self._gain) + elif span == D5a_module.range_4V_uni: + validator = Numbers(0, 4 * self._gain) + else: + msg = 'The found DAC span of {} does not correspond to a known one' + raise Exception(msg.format(span)) + + return validator diff --git a/core_tools/drivers/M3102A.py b/core_tools/drivers/M3102A.py index e33a5eed..ced545c3 100644 --- a/core_tools/drivers/M3102A.py +++ b/core_tools/drivers/M3102A.py @@ -1,6 +1,5 @@ from qcodes import Instrument, MultiParameter from dataclasses import dataclass -from si_prefix import si_format import warnings import logging import time @@ -62,7 +61,6 @@ class line_trace(MultiParameter): """ def __init__(self, name, instrument, inst_name , raw=False): self.my_instrument = instrument - self.name = name super().__init__(name=inst_name, names = (name +'_ch1', name +'_ch2'), shapes=((1,),(1,)), @@ -85,11 +83,10 @@ class line_trace(MultiParameter): """ generate channels mask for start multiple control functions """ - channel_mask = list('0000') # TODO make general version for n channels + channel_mask = 0 for i in self.channels: - channel_mask[-i] = '1' - channel_mask = int(''.join(channel_mask), 2) + channel_mask += 1 << (i - 1) return channel_mask @@ -102,104 +99,133 @@ class line_trace(MultiParameter): return self.get_data() - def get_data(self): - """ - Get data from the cards - TODO : IMPLEMENT BUFFERING METHODS for faster data transfers. - """ + def _read_channel_data(self, channel_number, channel_data_raw): + start = time.perf_counter() + i = 0 + points_aquired = 0 + while points_aquired < len(channel_data_raw): + np_ready = self.my_instrument.SD_AIN.DAQcounterRead(channel_number) + check_error(np_ready) + + if np_ready + points_aquired > len(channel_data_raw): + np_ready = len(channel_data_raw) - points_aquired + logging.error("more data points in digitizer ram then what is being collected.") + + + if np_ready > 0: + # Always read with a timeout to prevent infinite blocking of HW (and reboot of system). + # There are np_ready points available. This can be read in 1 second. + req_points = self.my_instrument.SD_AIN.DAQread(channel_number, np_ready, 1000) + check_error(req_points) + if not type(req_points) is int and len(req_points) != np_ready: + logging.error(f'DAQread failure. ready:{np_ready} read:{len(req_points)}') + + channel_data_raw[points_aquired: points_aquired + np_ready] = req_points + points_aquired = points_aquired + np_ready + i = 0 + + if np_ready == 0: + i+=1 + time.sleep(0.001) + if i > 100: + logging.error(f"digitizer did not manage to collect enough data points for channel {channel_number}, " + f"returning zeros. ({points_aquired})") + break + + logging.info(f'channel {channel_number}: retrieved {points_aquired} points in {(time.perf_counter()-start)*1000:3.1f} ms') + + + def _get_data_normal(self): data_out = tuple() for channel_property in self.my_instrument.channel_properties.values(): - start = time.perf_counter() - if self.my_instrument.mode == MODES.AVERAGE and channel_property.number in [2,4]: - continue if channel_property.active == False: continue # make flat data structures. - if self.my_instrument.mode == MODES.AVERAGE: - channel_data_raw = np.zeros( [ channel_property.cycles*10], np.uint16) - else: - channel_data_raw = np.zeros( [ channel_property.cycles*channel_property.points_per_cycle], np.double) - - # get data out of the buffer - np_ready = self.my_instrument.SD_AIN.DAQcounterRead(channel_property.number) - check_error(np_ready) - - i = 0 - points_aquired = 0 - while points_aquired < len(channel_data_raw): -# print('np_ready = %i' % np_ready) - if np_ready + points_aquired > len(channel_data_raw): - np_ready = len(channel_data_raw) - points_aquired - logging.error("more data points in digitizer ram then what is being collected.") + channel_data_raw = np.zeros([channel_property.cycles*channel_property.points_per_cycle], np.double) + + self._read_channel_data(channel_property.number, channel_data_raw) + + # format the data with correct amplitude + # convert 16-bit to relative scale (-1.0 .. 1.0) + f = 1 / 32768 + # multiply with the relevant channel amplitude (standard in volt -> mV!) + f *= channel_property.full_scale*1000 + # inplace multiplication on numpy array is fast + channel_data_raw *= f + + # reshape for [repetitions, time] and average + channel_data_raw = channel_data_raw.reshape([channel_property.cycles, channel_property.points_per_cycle]) + + if self.my_instrument.data_mode == DATA_MODE.FULL: + data_out += (channel_data_raw, ) + elif self.my_instrument.data_mode == DATA_MODE.AVERAGE_TIME: + data_out += (np.average(channel_data_raw, axis = 1), ) + elif self.my_instrument.data_mode == DATA_MODE.AVERAGE_CYCLES: + data_out += (np.average(channel_data_raw, axis = 0), ) + elif self.my_instrument.data_mode == DATA_MODE.AVERAGE_TIME_AND_CYCLES: + data_out += (np.average(channel_data_raw), ) + return data_out - if np_ready > 0: - # Always read with a timeout to prevent infinite blocking of HW (and reboot of system). - # There are np_ready points available. This can be read in 1 second. - req_points = self.my_instrument.SD_AIN.DAQread(channel_property.number, np_ready, 1000) - check_error(req_points) - if not type(req_points) is int and len(req_points) != np_ready: - logging.error(f'DAQread failure. ready:{np_ready} read:{len(req_points)}') - channel_data_raw[points_aquired: points_aquired + np_ready] = req_points - points_aquired = points_aquired + np_ready - i = 0 + def _get_data_average(self): + data_out = tuple() - if np_ready == 0: - i+=1 - time.sleep(0.001) - if i > 100: - logging.error(f"digitizer did not manage to collect enough data points, returning zeros. {points_aquired}, {channel_property}") - break + # note that we are acquirering two channels at the same time in this mode. + for channel_property in self.my_instrument.channel_properties.values(): + # averaging mode: channels are read in pairs. + if channel_property.number in [2,4]: + # even numbers are read with odd channel. + continue + if channel_property.number not in self.channels and channel_property.number+1 not in self.channels: + # don't read anything if both channels not active. + continue - np_ready = self.my_instrument.SD_AIN.DAQcounterRead(channel_property.number) + # make flat data structures. + channel_data_raw = np.zeros([channel_property.cycles*10], np.uint16) - logging.info(f'channel {channel_property.number}: retrieved {points_aquired} points in {(time.perf_counter()-start)*1000:3.1f} ms') + self._read_channel_data(channel_property.number, channel_data_raw) # format the data - if self.my_instrument.mode == MODES.AVERAGE: - # note that we are acquirering two channels at the same time in this mode.. - channel_data_raw = channel_data_raw.reshape([channel_property.cycles, 10]).transpose().astype(np.int32) - channel_data = np.empty([2,channel_property.cycles]) - channel_data[0] = ((channel_data_raw[1] & 2**16-1) << 16) | (channel_data_raw[0] & 2**16-1) - channel_data[1] = ((channel_data_raw[3] & 2**16-1) << 16) | (channel_data_raw[2] & 2**16-1) - - # correct amplitude, - channel_data[0] *= 5 * 2/(channel_property.t_measure-160)*channel_property.full_scale / 2**15 # outputs V, 5 for the aquisition in blocks of 5 - channel_data[1] *= 5 * 2/(channel_property.t_measure-160)*channel_property.full_scale / 2**15 # outputs V - - # make sure only the data of the wanted channel is returned. - if channel_property.number in self.channels: - if self.my_instrument.data_mode in [DATA_MODE.AVERAGE_CYCLES, DATA_MODE.AVERAGE_TIME_AND_CYCLES]: - data_out += (np.average(channel_data[0]), ) - else: - data_out += (channel_data[0], ) - - if channel_property.number + 1 in self.channels: - if self.my_instrument.data_mode in [DATA_MODE.AVERAGE_CYCLES, DATA_MODE.AVERAGE_TIME_AND_CYCLES]: - data_out += (np.average(channel_data[1]), ) - else: - data_out += (channel_data[1], ) - else: - # correct amplitude, - channel_data_raw /= 32768. #convert bit to relative scale (-1/1) - channel_data_raw *= channel_property.full_scale*1000 #multiply with the relevant channel amplitude (standard in volt -> mV!) - channel_data_raw = channel_data_raw.reshape([channel_property.cycles, channel_property.points_per_cycle]) - - if self.my_instrument.data_mode == DATA_MODE.FULL: - data_out += (channel_data_raw, ) - elif self.my_instrument.data_mode == DATA_MODE.AVERAGE_TIME: - data_out += (np.average(channel_data_raw, axis = 1), ) - elif self.my_instrument.data_mode == DATA_MODE.AVERAGE_CYCLES: - data_out += (np.average(channel_data_raw, axis = 0), ) - elif self.my_instrument.data_mode == DATA_MODE.AVERAGE_TIME_AND_CYCLES: - data_out += (np.average(channel_data_raw), ) + channel_data_raw = channel_data_raw.reshape([channel_property.cycles, 10]).transpose().astype(np.int32) + channel_data = np.empty([2,channel_property.cycles]) + channel_data[0] = ((channel_data_raw[1] & 2**16-1) << 16) | (channel_data_raw[0] & 2**16-1) + channel_data[1] = ((channel_data_raw[3] & 2**16-1) << 16) | (channel_data_raw[2] & 2**16-1) + + # correct amplitude, + # outputs V, 5 for the aquisition in blocks of 5 + channel_data[0] *= 5 * 2/(channel_property.t_measure-160)*channel_property.full_scale / 2**15 + channel_data[1] *= 5 * 2/(channel_property.t_measure-160)*channel_property.full_scale / 2**15 + + # only add the data of the selected channels. + if channel_property.number in self.channels: + if self.my_instrument.data_mode in [DATA_MODE.AVERAGE_CYCLES, DATA_MODE.AVERAGE_TIME_AND_CYCLES]: + data_out += (np.average(channel_data[0]), ) + else: + data_out += (channel_data[0], ) + + if channel_property.number + 1 in self.channels: + if self.my_instrument.data_mode in [DATA_MODE.AVERAGE_CYCLES, DATA_MODE.AVERAGE_TIME_AND_CYCLES]: + data_out += (np.average(channel_data[1]), ) + else: + data_out += (channel_data[1], ) return data_out + + def get_data(self): + """ + Get data from the cards + """ + if self.my_instrument.mode == MODES.NORMAL: + return self._get_data_normal() + else: + return self._get_data_average() + + def start_digitizers(self): # start digizers. self.my_instrument.daq_start_multiple(self.channel_mask) @@ -277,13 +303,11 @@ class SD_DIG(Instrument): super().__init__(name) """ init keysight digitizer - Args: name (str) : name of the digitizer chassis (int) : chassis number slot (int) : slot in the chassis where the digitizer is. n_channels (int) : number of channels on the digitizer card. - NOTE: channels start for number 1! (e.g. channel 1, channel 2, channel 3, channel 4) """ self.SD_AIN = keysightSD1.SD_AIN() @@ -350,7 +374,7 @@ class SD_DIG(Instrument): def set_operating_mode(self, operation_mode): """ Modes for operation - + Only affects daq start and daq trigger in get_raw(). Args: operation_mode (int) : mode of operation 0 : use software triggers (does call start and trigger in software) @@ -362,7 +386,6 @@ class SD_DIG(Instrument): def set_active_channels(self, channels): """ set the active channels: - Args: channels (list) : channels numbers that need to be used """ @@ -393,7 +416,6 @@ class SD_DIG(Instrument): def set_daq_settings(self, channel, n_cycles, t_measure, sample_rate = 500e6, DAQ_trigger_delay = 0, DAQ_trigger_mode = 1): """ quickset for the daq settings - Args: n_cycles (int) : number of trigger to record. t_measure (float) : time to measure (unit : ns) @@ -455,7 +477,6 @@ class SD_DIG(Instrument): def daq_flush(self, daq, verbose=False): """ Flush the specified DAQ - Args: daq (int) : the DAQ you are flushing """ @@ -463,7 +484,6 @@ class SD_DIG(Instrument): def daq_stop(self, daq, verbose=False): """ Stop acquiring data on the specified DAQ - Args: daq (int) : the DAQ you are disabling """ @@ -472,7 +492,6 @@ class SD_DIG(Instrument): def writeRegisterByNumber(self, regNumber, varValue): """ Write to a register of the AWG, by reffreing to the register number - Args: regNumber (int) : number of the registry (0 to 16) varValue (int/double) : value to be written into the registry @@ -483,7 +502,6 @@ class SD_DIG(Instrument): def daq_start_multiple(self, daq_mask, verbose=False): """ Start acquiring data or waiting for a trigger on the specified DAQs - Args: daq_mask (int) : the input DAQs you are enabling, composed as a bitmask where the LSB is for DAQ_0, bit 1 is for DAQ_1 etc. @@ -492,7 +510,6 @@ class SD_DIG(Instrument): def daq_trigger_multiple(self, daq_mask, verbose=False): """ Manually trigger the specified DAQs - Args: daq_mask (int) : the DAQs you are triggering, composed as a bitmask where the LSB is for DAQ_0, bit 1 is for DAQ_1 etc. @@ -541,7 +558,6 @@ class SD_DIG(Instrument): def set_digitizer_software(self, t_measure, cycles, sample_rate= 500e6, data_mode = DATA_MODE.FULL, channels = [1,2], Vmax = 2, fourchannel = False): """ quick set of minumal settings to make it work. - Args: t_measure (float) : time to measure in ns cycles (int) : number of cycles @@ -568,7 +584,6 @@ class SD_DIG(Instrument): def set_digitizer_analog_trg(self, t_measure, cycles, sample_rate= 500e6, data_mode = DATA_MODE.FULL, channels = [1,2], Vmax = 2): """ quick set of minumal settings to make it work. - Args: t_measure (float) : time to measure in ns cycles (int) : number of cycles @@ -592,10 +607,9 @@ class SD_DIG(Instrument): self.set_meas_time(t_measure) self.set_MAV_filter(16,1) - def set_digitizer_HVI(self, t_measure, cycles, sample_rate= 500e6, data_mode = DATA_MODE.FULL, channels = [1,2], Vmax = 2): + def set_digitizer_HVI(self, t_measure, cycles, sample_rate=500e6, data_mode=DATA_MODE.FULL, channels=[1,2], Vmax=2): """ - quick set of minumal settings to make it work. - + quick set of minimal settings to make it work. Args: t_measure (float) : time to measure in ns cycles (int) : number of cycles @@ -617,8 +631,8 @@ class SD_DIG(Instrument): if __name__ == '__main__': #%% # load digitizer - digitizer1.close() - digitizer1 = SD_DIG("digitizer1", chassis = 0, slot = 5) + # digitizer1.close() + digitizer1 = SD_DIG("digitizer1", chassis = 0, slot = 6) # clear all ram (normally not needed, but just to sure) digitizer1.daq_flush(1) @@ -626,44 +640,45 @@ if __name__ == '__main__': digitizer1.daq_flush(3) digitizer1.daq_flush(4) - digitizer1.set_aquisition_mode(MODES.AVERAGE) + # digitizer1.set_aquisition_mode(MODES.AVERAGE) #%% # simple example - + digitizer1.set_digitizer_software(1e3, 10, sample_rate=500e6, data_mode=DATA_MODE.AVERAGE_TIME_AND_CYCLES, channels=[1,2], Vmax=0.25, fourchannel=False) + print(digitizer1.measure()) #################################### # settings (feel free to change) # - #################################### - t_list = np.logspace(2.3, 2.7, 20) - res =[] - for t in t_list: - cycles = 1000 - t_measure = t #e3 # ns - #################################### - - - # show some multiparameter properties - # print(digitizer1.measure.shapes) - # print(digitizer1.measure.setpoint_units) - # print(digitizer1.measure.setpoints) - # # measure the parameter - digitizer1.set_digitizer_software(t_measure, cycles, data_mode=DATA_MODE.FULL, channels = [1,2]) - digitizer1.set_MAV_filter() - data = digitizer1.measure() - # print(data) - # plt.clf() - # plt.plot(data[0][:,2], 'o-') - # plt.plot(data[0][:,3], 'o-') - # plt.plot(data[1], 'o-') - # print(data[0].shape, data[1].shape) - - res.append(np.mean(data[1])) - - #t_list = t_list-166 - #res = np.array(res)/np.array(t_list) - plt.figure(2) - plt.clf() - plt.plot(t_list, res, 'o-') + # #################################### + # t_list = np.logspace(2.3, 2.7, 20) + # res =[] + # for t in t_list: + # cycles = 1000 + # t_measure = t #e3 # ns + # #################################### + + + # # show some multiparameter properties + # # print(digitizer1.measure.shapes) + # # print(digitizer1.measure.setpoint_units) + # # print(digitizer1.measure.setpoints) + # # # measure the parameter + # digitizer1.set_digitizer_software(t_measure, cycles, data_mode=DATA_MODE.FULL, channels = [1,2]) + # digitizer1.set_MAV_filter() + # data = digitizer1.measure() + # # print(data) + # # plt.clf() + # # plt.plot(data[0][:,2], 'o-') + # # plt.plot(data[0][:,3], 'o-') + # # plt.plot(data[1], 'o-') + # # print(data[0].shape, data[1].shape) + + # res.append(np.mean(data[1])) + + # #t_list = t_list-166 + # #res = np.array(res)/np.array(t_list) + # plt.figure(2) + # plt.clf() + # plt.plot(t_list, res, 'o-') #def fit_func(x, m, q): # return x*m+q @@ -672,4 +687,4 @@ if __name__ == '__main__': #param, var = scipy.optimize.curve_fit(fit_func, t_list, res) #plt.plot(np.linspace(0, max(t_list), 50), fit_func(np.linspace(0, max(t_list), 50), *param)) #plt.xlabel('Integration time (ns)') - #plt.title('Intercept: %.2f' %param[1]) + #plt.title('Intercept: %.2f' %param[1]) \ No newline at end of file diff --git a/core_tools/drivers/M3102_firmware_loader.py b/core_tools/drivers/M3102_firmware_loader.py new file mode 100644 index 00000000..b864d4a7 --- /dev/null +++ b/core_tools/drivers/M3102_firmware_loader.py @@ -0,0 +1,33 @@ +""" +Standard firmware files for the digitizer of the V2 setup. + +CLEAN : normal image, revert to the normal AWG. +AVG : special image with MAV and interator. A custom qcodes driver needs to be used for that. +""" +M3102A_CLEAN = "C:/V2_code/FPGA_Bitstreams/Digitizer_FW1.41/clean_4_41.sbp" +M3102A_AVG = "C:/V2_code/FPGA_Bitstreams/Digitizer_FW1.41/averaging_firmware_1_41.sbp" + +from core_tools.drivers.M3102A import MODES + +def firmware_loader(dig, file): + """ + load a custom firmware image on board of the digitizer + + Args: + dig <SD_dig (qcodes instrument) : digitzer object + file (string) : location where to find the new firmware + """ + err = dig.SD_AIN.FPGAload(file) + if file == M3102A_CLEAN: + dig.set_aquisition_mode(MODES.NORMAL) + else: + dig.set_aquisition_mode(MODES.AVERAGE) + + + if err == 0 : + print("Succesful upload of the firmware") + else: + print("upload failed, error code {} (see keysight manual for instructions)".format(err)) + +if __name__ == '__main__': + firmware_loader(dig, M3102A_CLEAN) \ No newline at end of file diff --git a/core_tools/drivers/__pycache__/harware.cpython-37.pyc b/core_tools/drivers/__pycache__/harware.cpython-37.pyc index 32c2c717096282368fea81d1b9cb50781245af55..c3e4adfe5a18a54939049a4880a82f3b6e1e8b51 100644 GIT binary patch delta 568 zcmY+B%}X0W7{;A^ZnIgln@A*n1>L5}f|`<m2_{x-i&WZPq`eejY2(xcH5+DEMbQ61 z5As6k!J7xqCf6QH{R2FC*^`&{-dmxU&a-;y!v2_f-kFE@dFP^ZUQ(ZHT4G3k-x@!z z)XQ+T+FIP$uh=bTlW(*f!EMiRcHF^D_$<VH`WWl8aT<yLVkZ5KPqM-wr;LUQ)6zf` zB>c!WKXgSD`z#O#9s?%5Pt;hEP7{A-N>cE{ov!y#!dA8IE$($ZzH8eePnYVHUc@~e zFo4S7R(;3PmRws=k%ANfo>D`zSe3Ze%uhg=1g3yApaB)2O5e5obYL4eno?YlzpF?n zEE!E^laGYiA8xZ)&~%-;sVy~#HwOcg?ouVCDVG)#Mbh;h_L7eEF;=Fp`Z^uyV-zt? zVlQxZj=mVPY?ZE!&t?NRBBBg^83-E3F)MVRWS-unUw`<&eLrs7n@&s4137%9C!8J^ z-r>E^Dzuo(J&z0V3Z^w6m=}N!Ap}Y5^gEqnby72*o-9EP13@qh!B4DpT~F-oa``58 ZlqQHWE5=*YLhS=T+7o!LGX2av`v*rgdvE{% delta 582 zcmYk4&r2Io5XXJHn|0kEX0rjM@kioD(ky61kp`j&4FoAx55<#+3ns5gAg(gIY73rw zsZeB&?V->^&l)@k{sBF;=kB2w|B1E->6_h47v6{2@67k@%zOK(`lV_#ElVE}&)@Rx zweeM+X|x;rZw4K|eca*u9e&0K$0tWTh!SD=O}>)Y9`30(tbo7rlQ=*6qv#4dI0CT| zz75(w54!z;dopAxF+X&)Nl7gwF)ry()G~!G?&x(^!FT#^_o)zKxgSK3rs&o1{VtFC z5kK;Mn8nY=tX(0WO~?_Jhu@7|=2S)OWzugcq%YyB<*^k!u-1!HBuo=#2-GB4gk{1C z-dV-DWZPs%8swQ+p(da)Gh<GeW8e<|SUr|@UB_;=Ym`J976>l>%vQBE5qb<NIA#y< z!7fNp!z=q0YvP4cz(@PN+DshyA-BL<c%OS+ZjeQR8tEH^q;)Fuq;!@=Y&l!Te*@r0 zXL>s^v_x5~hCGTmz$Uq=>-1>oe5e-^lA-D%>WLMa0vc18X_|_ujE_PcmHc64ohoHQ ni9lx%>o0;Zf>XM8AU{muW&U~YCFP{vd7L=`x~-b{1vdTxjq!Wn diff --git a/core_tools/sweeps/__pycache__/__init__.cpython-37.pyc b/core_tools/sweeps/__pycache__/__init__.cpython-37.pyc index 650a11821c64ae38743818bdb25ae9b01d2f65f5..29eb9bf6d3c33b76b1150636201cf6da20d80b84 100644 GIT binary patch delta 45 zcmbQp*u}{0#LLUY00eui4^8B@5Hn7;iYYUSPtH$CjY-ZgN{uhc&(A5Im|zG12bK-D delta 52 zcmeBToXE)S#LLUY00h63w@&1?khMy-imAv+iBHZ?NsUQKElbVGFUU>JD*+2kj5GuQ De!URe diff --git a/core_tools/sweeps/__pycache__/pulse_lib_sweep.cpython-37.pyc b/core_tools/sweeps/__pycache__/pulse_lib_sweep.cpython-37.pyc index e6dbc34485b95182467b711fabed9cfe25d189c8..f93f2884ba64901205a20bd2845f59363058b6e0 100644 GIT binary patch delta 521 zcmezA^2vqUiI<m)0SG33I=qoPmr2Yj*(#>YC_XtqB{e2FzbG}nBtJi=c=J@IgM56q zI7?ECOXBkqb5k`LZ*5KyOk`w?o_tIwlQD6#f$%d%ff%4cMX?|v4n)LHRukRBm@xUV zs3K$HWLB{NAZZ{hFPsXLoDamsEI@*Tk&mw^b@D<9$;}JJc$pb9CO66`u|<RQOH7_8 zuQ2($WENW*h?_n+U8;gHd-6w7;mMz+a)2rmq(y<`LW!iwH>4XmvVe*-8H+L}C&~!( zf;n78z95Y`=tiED$r6GX3DUw;1PXy7h`|xEkx(m+%I1jY042@?aWMyw;9z87<YDJv z1)2x4a+O@K5XhDyuvJV&nILxNWKVf%1CYqeS|FhbbwMsjju%9Tfe3jJAqyfbK}7WA zDe_ZrImlN5=Ac~)IpQFL9s)7KK^#B_<xaL$oTHu$G7Ic2PypXz%TLNmO)e?21qo+> a2#{}zawjP%vK4?>DwA#b#3$P+SpxuCsDWhw delta 516 zcmez5^3#ReiI<m)0SKx(c5UR&Ws-GFwu-69Nr_L+Pf3kQNi9pw$uG!F%_{*5Z0=(^ z$j2AOS&~{@5}%ito2tnewK-NWk&!WS@_wOA#`sB!@|!(`k24BH0gWt*1`#nJB6hO8 z=pM$n$#+B*8RIAa6Ab_>6;1}q%?ILQ79hdF$j4Wdytz?KjhQiRa+Qn{(9pRus*^uR zX0fG!3`w1wAXUMbIr$-n@Z>jAIpS$R!F?dz9AMonj6CcdtVL;)9p#cHUzBdt$N&m! zG8UzSsVcTgg~W=?;vyFyw+Jl7Rpbj|XTk027lPOW(!f*%3YH>>ZGp0pP<!{u=7?tj zCC&pes=Zl2d*9oG42GD_1hyDrJ5v=~1=w~>SG=qR>d=HbC3|wdye!b$z4B9VImJx@ z=9J9}IgHtp6%<8*q?zIz^+b@>U=M(T^%h%xQdVkmNs%o`7!*`RAa@sKPyVT>$e1^I LJ)6vAb0up4l$V5D diff --git a/core_tools/sweeps/exp_readout_runner.py b/core_tools/sweeps/exp_readout_runner.py new file mode 100644 index 00000000..94a777ed --- /dev/null +++ b/core_tools/sweeps/exp_readout_runner.py @@ -0,0 +1,145 @@ +from core_tools.utility.digitizer_param_conversions import IQ_to_scalar, down_sampler, Elzerman_param, get_phase_compentation_IQ_signal + +from core_tools.GUI.keysight_videomaps.data_getter.scan_generator_Keysight import construct_1D_scan_fast +from core_tools.HVI.single_shot_exp.HVI_single_shot import load_HVI, set_and_compile_HVI, excute_HVI, HVI_ID +from core_tools.sweeps.pulse_lib_sweep import spin_qubit_exp +from core_tools.utility.mk_digitizer_param import get_digitizer_param +from core_tools.utility.dig_utility import autoconfig_digitizer +from core_tools.drivers.M3102_firmware_loader import M3102A_CLEAN, M3102A_AVG +from core_tools.drivers.M3102A import DATA_MODE + +import qcodes as qc + +def measure_optimal_phase_IQ_sigal(SD = 'vSD2_P'): + ''' + Measure the phase rotation that is needed to rotate the sigal of the SD into the I line of the IQ plane + + Args: + SD (str) : gates name to sweep (sigal generator) + Returns : + phase (double) : phase rotation in the IQ plane + ''' + station = qc.Station.default + #make scan around SD to make phase estimation + param = construct_1D_scan_fast(SD, 10, 400, 50000, False, station.pulse, station.dig, [1,2], 100e6) + return get_phase_compentation_IQ_signal(param) + +def run_readout_exp(name, segment, t_meas, n_rep, show_raw_traces, threshold, blib_down, phase): + ''' + autoconfig utility for runing a readout experiment + + Args: + name (str) : name of the measurement to be run + segment (segment_container) : segment to be played on the AWG + t_meas (double) : measurement time to set to the digitizer (will be removed when digitzer updates) + n_rep (double) : number times a experiment needs to be repeated + show_raw_traces (bool) : show raw traces + threshold (double) : threadhold for the detection + blib_down (bool) : direction of the blib (if true, downward blib expected). + phase (double) : phase rotation in the IQ plane for SD + Returns: + data (qCoDeS dataset) : returns the dataset of the measured data. + ''' + + station = qc.Station.default + + data_mode = DATA_MODE.FULL + if n_rep == 1: + data_mode = DATA_MODE.AVERAGE_CYCLES + + dig_param = get_digitizer_param(station.dig, t_meas, n_rep, data_mode) + IQ_meas_param = IQ_to_scalar(dig_param, phase) + down_sampled_seq = down_sampler(IQ_meas_param, 0.3e6, None) + elzerman_det = Elzerman_param(down_sampled_seq, threshold, blib_down) + + if not isinstance(segment, list): + segment = [segment] + + my_seq = station.pulse.mk_sequence(segment) + + settings = dict() + settings['averaging'] = False + + my_seq.add_HVI(HVI_ID, load_HVI, set_and_compile_HVI, excute_HVI, digitizer = station.dig, **settings) + my_seq.n_rep = n_rep + my_seq.neutralise = True + + if show_raw_traces == True: + my_exp = spin_qubit_exp(name, my_seq, down_sampled_seq) + else: + my_exp = spin_qubit_exp(name, my_seq, elzerman_det) + data = my_exp.run() + + elzerman_pulse = None + my_exp = None + my_seq = None + station.pulse.uploader.release_memory() + + return data + + +def run_PSB_exp(name, segment, t_meas, n_rep, raw_traces, phase): + ''' + autoconfig utility for runing a readout experiment with PSB + (will use fpga averaging when possible) + + Args: + name (str) : name of the measurement to be run + segment (segment_container) : segment to be played on the AWG + t_meas (double) : measurement time to set to the digitizer (will be removed when digitzer updates) + n_rep (double) : number times a experiment needs to be repeated + raw_traces (bool) : show raw traces + phase (double) : phase rotation in the IQ plane for SD + Returns: + data (qCoDeS dataset) : returns the dataset of the measured data. + ''' + station = qc.Station.default + + if raw_traces == False: + autoconfig_digitizer(M3102A_AVG) + data_mode = DATA_MODE.AVERAGE_TIME_AND_CYCLES + if n_rep == 1: + data_mode = DATA_MODE.AVERAGE_CYCLES + station.dig.set_data_handling_mode(data_mode) + else: + autoconfig_digitizer(M3102A_CLEAN) + data_mode = DATA_MODE.FULL + station.dig.set_data_handling_mode(data_mode) + + + + dig_param = get_digitizer_param(station.dig, t_meas, n_rep, data_mode) + IQ_meas_param = IQ_to_scalar(dig_param, phase) + + if raw_traces == True: + down_sampled_seq = down_sampler(IQ_meas_param, 5e6) + + my_seq = station.pulse.mk_sequence([segment]) + + settings = dict() + settings['averaging'] = True + if raw_traces == True: + settings['averaging'] = False + + + my_seq.add_HVI(HVI_ID, load_HVI, set_and_compile_HVI, excute_HVI, digitizer = station.dig, **settings) + my_seq.n_rep = n_rep + my_seq.neutralise = True + + if raw_traces == True: + my_exp = spin_qubit_exp(name, my_seq, down_sampled_seq) + else: + my_exp = spin_qubit_exp(name, my_seq, IQ_meas_param) + data = my_exp.run() + + elzerman_pulse = None + my_exp = None + my_seq = None + station.pulse.uploader.release_memory() + + autoconfig_digitizer(M3102A_AVG) + + return data + + + diff --git a/core_tools/utility/dig_utility.py b/core_tools/utility/dig_utility.py index 693f7e3c..f608bd69 100644 --- a/core_tools/utility/dig_utility.py +++ b/core_tools/utility/dig_utility.py @@ -1,5 +1,5 @@ -from V2_software.drivers.M3102A.M3102A import SD_DIG, MODES, DATA_MODE -from V2_software.drivers.M3102A.M3102_firmware_loader import firmware_loader, M3102A_CLEAN, M3102A_AVG +from core_tools.drivers.M3102A import SD_DIG, MODES, DATA_MODE +from core_tools.drivers.M3102_firmware_loader import firmware_loader, M3102A_CLEAN, M3102A_AVG import qcodes as qc def autoconfig_digitizer(firmware = M3102A_AVG): @@ -12,7 +12,7 @@ def autoconfig_digitizer(firmware = M3102A_AVG): t_measure = 1e4 #1ms (unit ns) cycles = 1 # just measure once. - station.dig.set_digitizer_software(t_measure, cycles, data_mode=DATA_MODE.AVERAGE_TIME_AND_CYCLES, channels = [1,2]) + station.dig.set_digitizer_software(t_measure, cycles, data_mode=DATA_MODE.AVERAGE_TIME_AND_CYCLES, channels = [1,2], fourchannel=True ) station.dig.daq_flush(1) station.dig.daq_flush(2) diff --git a/core_tools/utility/digitizer_param_conversions.py b/core_tools/utility/digitizer_param_conversions.py new file mode 100644 index 00000000..e9584d73 --- /dev/null +++ b/core_tools/utility/digitizer_param_conversions.py @@ -0,0 +1,210 @@ +from qcodes import MultiParameter +from scipy import signal +import numpy as np +import matplotlib.pyplot as plt +import lmfit + + +def lin_func(x, a, b): + return x*a + b + + +#TODO move to better location at later point +def get_phase_compentation_IQ_signal(param): + ''' + Args: + param (Multiparameter) : parameter with a get method that returns an I and Q array of a signal. + Return: + rotation_angle (double) : angle at which to rotate the signal to project it to the I plane. + ''' + data_in = param.get() + + model = lmfit.Model(lin_func) + + a = np.average(data_in[0])/np.average(data_in[1]) + b = 0 + param = model.make_params(a=a, b=b) + result = model.fit(data_in[1], param, x=data_in[0]) + + angle = np.angle(1+1j*result.best_values['a']) + + # print(result.best_values['a']) + # print(angle) + # x= np.linspace(-120, 20, 100) + # plt.plot(x, lin_func(x, result.best_values['a'], result.best_values['b'])) + # plt.plot(data_in[0], data_in[1]) + # new_data = data_in[0] +1j*data_in[1] + # new_data *= np.exp(1j*(-angle)) + # plt.plot(np.real(new_data), np.imag(new_data)) + + # new_data = x +1j*lin_func(x, result.best_values['a'], result.best_values['b']) + # new_data *= np.exp(1j*(-angle)) + # plt.plot(np.real(new_data), np.imag(new_data)) + return angle + +class IQ_to_scalar(MultiParameter): + ''' + parameter that converts IQ data of the digitizer into scalar data + NOTE : ONLY ONE IQ CHANNEL PAIR SUPPORTED ATM !!! + ''' + def __init__(self, digitizer, phase_rotation): + ''' + Args: + digitizer (MultiParameter) : instrument class of the digitizer + phase_rotation (double) : rotation in the IQ plane (will keep only I) + ''' + self.dig = digitizer + self.phase_rotation = phase_rotation + self.sample_rate = digitizer.sample_rate + + names = ('RF_readout_amplitude',) + super().__init__('IQ_to_scalar_convertor', names=names, shapes=(self.dig.shapes[0],), + labels=(self.dig.labels[0],), units=(self.dig.units[0],), + setpoints=(self.dig.setpoints[0],), + setpoint_names=(self.dig.setpoint_names[0],), + setpoint_labels=(self.dig.setpoint_labels[0],), + setpoint_units=(self.dig.setpoint_units[0],)) + + def get_raw(self): + data_in = self.dig.get_raw() + data_out = (data_in[0] + 1j*data_in[1])*np.exp(1j*self.phase_rotation) + + return (data_out.real, ) + + +class down_sampler(MultiParameter): + ''' + Down sampler for a digitizer, given a certain bandwidth, take make blibs for example more clear. + ''' + def __init__(self, digitizer, bandwidth, highpass = None): + ''' + Args: + digitizer (MultiParameter) : instrument class of the digitizer + bandwidth (double) : wanted bandwidth (3db point of a butterworth filter) + highpass (double) : if defined, sets a highpass filter at a given freq + ''' + self.dig = digitizer + self.bandwidth = bandwidth + self.highpass = highpass + self.sample_rate = digitizer.sample_rate + self.sample_drop_rate = int(self.dig.sample_rate/bandwidth/2) + + shapes, setpoints = self.get_shape() + super().__init__('Elzerman_state_differentiator', names=digitizer.names, shapes=shapes, + labels=digitizer.labels, units=digitizer.units, setpoints=setpoints, + setpoint_names=digitizer.setpoint_names, + setpoint_labels=digitizer.setpoint_labels, + setpoint_units=digitizer.setpoint_units) + + def get_raw(self): + data_out = tuple() + data_in = self.dig.get() + + for i in range(len(data_in)): + filtered_data = np.empty(self.shapes[0]) + + if filtered_data.ndim == 2: + for j in range(len(filtered_data)): + filtered_data[j,:] = filter_data(data_in[i][j], self.bandwidth, self.dig.sample_rate, 'lowpass')[::self.sample_drop_rate] + + if self.highpass is not None: + filtered_data[j,:] = filter_data(filtered_data[j], self.highpass, self.sample_rate/self.sample_drop_rate, 'highpass') + else: + filtered_data[:] = filter_data(data_in[i], self.bandwidth, self.dig.sample_rate, 'lowpass')[::self.sample_drop_rate] + + if self.highpass is not None: + filtered_data[:] = filter_data(filtered_data[:], self.highpass, self.sample_rate/self.sample_drop_rate, 'highpass') + + data_out += (filtered_data,) + + return tuple(data_out) + + def get_shape(self): + shapes, setpoints = tuple(), tuple() + + for i in range(len(self.dig.names)): + setpt = self.dig.setpoints[i] + shape = tuple() + + if len(setpt) > 1: + setpt = (setpt[0], np.asarray(setpt[1]).flatten()[::self.sample_drop_rate], ) + shape = (len(setpt[0]), len(setpt[1])) + else: + setpt = (np.asarray(setpt).flatten()[::self.sample_drop_rate], ) + shape = setpt[0].shape + + shapes += (shape, ) + setpoints += (setpt, ) + + return shapes, setpoints + + def update_shape(self): + self.shapes, self.setpoints = self.get_shape() + +class Elzerman_param(MultiParameter): + """ + parameter that aims to detect blibs. + expected that the input data is already well filtered. + """ + def __init__(self, digitizer, threshold, blib_down): + ''' + Args: + digitizer (MultiParameter) : parameter providing the data for the dip detection + threshold (double) : threadhold for the detection + blib_down (bool) : direction of the blib (if true, downward blib expected). + ''' + self.dig = digitizer + self.threshold = threshold + self.blib_down = blib_down + + names = tuple() + shapes = tuple() + labels = tuple() + units = tuple() + setpoints = tuple() + + for i in range(len(digitizer.names)): + names += ("readout_signal_ch{}".format(i), ) + shapes += ((), ) + labels += ('Spin probability' ,) + units += ('%', ) + + setpoints += ((),) + + super().__init__('Elzerman_state_differentiaor', names=names, shapes=shapes, + labels=labels, units=units, setpoints=setpoints) + + + def get_raw(self): + # expected format from the getter <tuple<np.ndarray[ndim=2,dtype=double]>> + data_in = self.dig.get() + data_out = [] + + for data in data_in: + if self.blib_down == True: + blib_pt = np.where(data<self.threshold)[0] + else : + blib_pt = np.where(data>self.threshold)[0] + + data_out.append(np.unique(blib_pt).size/data.shape[0]) + + return data_out + +def filter_data(data, cutoff, fs, pass_zero, order = 4): + ''' + filter noise out of a dataset + Args: + data (np.ndarray) : data array to filter + cutoff (double) : cutoff in HZ (not that this is the last 0db point and not -3db) + fs (double) : sample rate of the signal + pass_zero (str) : 'lowpass' or 'highpass' + ''' + b, a = signal.butter(order, cutoff/(fs/2), pass_zero) + return signal.filtfilt(b, a, data) + + +if __name__ == '__main__': + a = np.zeros([1000]) + a[100:400] = 1 + + filter_data(a, 10e3, 2e6, 'highpass') \ No newline at end of file diff --git a/core_tools/utility/powerpoint.py b/core_tools/utility/powerpoint.py index 4761a3ee..324aacb2 100644 --- a/core_tools/utility/powerpoint.py +++ b/core_tools/utility/powerpoint.py @@ -309,7 +309,7 @@ try: notes = '\n' + extranotes + '\n' + notes if gates is not None: notes = 'gates: ' + str(gates.allvalues()) + '\n\n' + notes - if isinstance(notes, qcodes.DataSet): + if isinstance(notes, qcodes.data.data_set.DataSet): notes = reshape_metadata(notes, printformat='s', add_gates=True) if notes is not None: diff --git a/example_T2Hahn.py b/example_T2Hahn.py new file mode 100644 index 00000000..6544e84e --- /dev/null +++ b/example_T2Hahn.py @@ -0,0 +1,48 @@ +from pulse_templates.utility.plotting import plot_seg +from pulse_templates.demo_pulse_lib.virtual_awg import get_demo_lib +from pulse_templates.utility.oper import add_block, add_ramp +from pulse_templates.utility.plotting import plot_seg + +from pulse_templates.coherent_control.single_qubit_gates.standard_set import single_qubit_std_set +from pulse_templates.coherent_control.single_qubit_gates.single_qubit_gates import single_qubit_gate_spec +from pulse_templates.elzerman_pulses.basic_elzerman_pulse import elzerman_read +from pulse_templates.coherent_control.single_qubit_gates.T2_meas import T2_hahn + +from pulse_lib.segments.utility.looping import linspace + +pulse = get_demo_lib('quad') + +INIT = pulse.mk_segment() +MANIP = pulse.mk_segment() +READ = pulse.mk_segment() + +# assume 1QD -- elzerman init +t_init = 50e3 +gates = ('vP4',) +p_0 = (0, ) + +add_block(INIT, t_init, gates, p_0) + + + +# T2 hahn +MANIP.vP4 += 20 +xpi2 = single_qubit_gate_spec('qubit4_MW', 1.1e8, 1000, MW_power=120, padding=2) #X +xpi = single_qubit_gate_spec('qubit4_MW', 1.1e8, 2000, MW_power=120, padding=2) #X2 + +ss_set = single_qubit_std_set() +ss_set.X = xpi2 +ss_set.X2 = xpi + +times = linspace(100, 1e5, 100, axis=0, name='time', unit='ns') + +T2_hahn(MANIP, ss_set, times, 1e6) + +# +p_read = (0, ) +t_read = 100e3 + +elzerman_read(READ, gates, t_read, p_read, disable_trigger=False) + +# run exp() +run_exp([INIT, MANIP, READ], nrep = 100, ..) diff --git a/keysightSD1/__pycache__/__init__.cpython-37.pyc b/keysightSD1/__pycache__/__init__.cpython-37.pyc index 6d004f27c47df9774e6f467424ec2855aaa75840..407f3c1af412b5f482b6cd8d7407260cfda814db 100644 GIT binary patch delta 432 zcmbO|pJmE?7Ct9lUM>b8*kgStu10nvpBA&2Zn9NOnNfUleoAUga(+>2d`W(OPVweY z=59X5sLc-r?HCztCMyVw1Idj7CX;i7<ArU3CUgREF$<93U}Rw|vIWXXPOcSHpDZUb zQ_>D7+zXNi*#(k^z#==as+S`3#GQc>Q$Q*>kW>^ogKfAZ>Lct16rKf=huh#b*-)%g z*b^u=4@KM)C~h&CRoq9|2PnP>Ma~D}DsewHcc6HY$K;FR@{GQdKZ*-aP8OG%EGH4c zev8%3Gs4wn@<(3L$sfd7xK_grm?UAj`KCm45gW+PBJa&s-4l%1Kt3z7pL}7jxP$|c z86^-B<mvA28Wiv2A08hZ>E~SJIQjoxaYm=j;`^p)L$rEr-u&{iilz-nD=6fOz=nWA Ypa|s6BCz=&#~1m62*2s;`54~-0B&bxH2?qr delta 454 zcmbO-pJn!Z7Ct9lUM>b8m_2z{T)F5*J}qWhlVq!yiky`A<ouM>n3UAA)SUc++|;}h zu)t<N=59X5TbpkQ+A&Jn0yQ=QaWTjU4n`IbWMW|~vYl)wJbCg45f=VVkSq&Sw#W`B zE;;#w@Bv2q$s0w)f#gCto5`%A)r>Ba8%0Hdq@l3M<kO-)!tOvVvrzQ9gXQAHLWRA6 z;`31Cyufn5!~%qUf#Qo$<b1()mWlhZc>u+WJSU$LmlyQ|GM9mru>lE)!;AdDh8RiM zGDb}<kdPMk2TH95sewD+AEaXQC5h-FHjo>Nd^Q_*PcV|R2eBQ1M3i7ikf*!5Yf!w0 zr@KddaHOAek>litd&MN3P-KHVgIyuA&YK1HP1A;$=Dm5%%gZX7pfD}60})_zT|g{Q WXcU311o^KB<oY82=_~jc-v9tb`Drr% -- GitLab