def NqpfromQi(S21data, uselowtempapprox=True, SC=SuperCond.Al()): """Calculates the number of quasiparticles from the measured temperature dependence of Qi. Returns temperatures in K, along with the calculated quasiparticle numbers. If uselowtempapprox, the complex impedence is calculated directly with a low temperature approximation, else it\'s calculated with the cinduct function in kidcalc (slow).""" ak_ = ak(S21data) hw = S21data[:, 5] * const.Plack / const.e * 1e6 kbT = S21data[:, 1] * const.Boltzmann / const.e * 1e6 if uselowtempapprox: beta_ = kidcalc.beta(kbT[0], SC.D0, SuperCond.Sheet(SC, d=S21data[0, 25])) def minfunc(kbT, s2s1, hw, D0): xi = hw / (2 * kbT) return np.abs(np.pi / 4 * ((np.exp(D0 / kbT) - 2 * np.exp(-xi) * i0(xi)) / (np.sinh(xi) * k0(xi))) - s2s1) Nqp = np.zeros(len(kbT)) for i in range(len(kbT)): s2s1 = S21data[i, 4] * (ak_ * beta_) / 2 res = minisc( minfunc, args=(s2s1, hw[i], SC.D0), bounds=(0, SC.kbTc), method="bounded", ) kbTeff = res.x Nqp[i] = S21data[0, 14] * kidcalc.nqp(kbTeff, SC.D0, SC) return kbT / (const.Boltzmann / const.e * 1e6), Nqp else: def minfunc(kbT, s2s1, hw, SC): D_ = kidcalc.D(kbT, SC) s1, s2 = kidcalc.cinduct(hw, D_, kbT) return np.abs(s2s1 - s2 / s1) Nqp = np.zeros(len(kbT)) for i in range(len(kbT)): D_0 = kidcalc.D(kbT[i], SC) beta_ = kidcalc.beta(kbT[i], D_0, SuperCond.Sheet(SC, d=S21data[0, 25])) s2s1 = S21data[i, 4] * (ak_ * beta_) / 2 res = minisc(minfunc, args=(s2s1, hw[i], SC), bounds=(0, SC.kbTc), method="bounded") kbTeff = res.x D_ = kidcalc.D(kbTeff, SC) Nqp[i] = S21data[0, 14] * kidcalc.nqp(kbTeff, D_, SC) return kbT / (const.Boltzmann / const.e * 1e6), Nqp
def calc_params(self, e, nrTraps, t1, t2, xi, eta, P, kbT): D = kidcalc.D(kbT, self.SC) c = nrTraps / self.V / (2 * self.SC.N0 * D) NT = kidcalc.nqp(kbT, D, self.SC) * self.V R = (2 * D / self.SC.kbTc)**3 / (4 * D * self.SC.N0 * self.SC.t0) Rstar = R / (1 + self.tesc / self.SC.tpb) Rtstar = xi / (t1 * self.SC.N0 * D) * (1 + e / D) Gd = (np.sqrt(np.pi) / 4 * (kbT / D)**(3 / 2) * np.exp(-(D - e) / kbT) * (1 / t1 * (3 + 2 * ((D - e) / kbT)) * kbT / D + 4 / t2 * (1 + (D - e) / kbT))) Gt = (2 * c / t2 * (1 - e / D) * (1 / (np.exp( (D - e) / kbT) - 1) + 1) * (1 - 1 / (np.exp(e / kbT) + 1))) GB = 1 / self.SC.tpb Ges = 1 / self.tesc NTw = R * NT**2 / (2 * self.V * GB) return [ R, self.V, GB, Gt, Gd, Rtstar, Ges, NTw, eta, P, D, ], NT, Rstar
def calc_params(self, e, nrTraps, Gt, Gd, xi, kbT): D = kidcalc.D(kbT, self.SC) c = nrTraps / self.V / (2 * self.SC.N0 * D) NT = kidcalc.nqp(kbT, D, self.SC.N0) * self.V NtT = self.V * 2 * self.SC.N0 * D * c * kidcalc.f(e, kbT) R = (2 * D / self.SC.kbTc)**3 / (4 * D * self.SC.N0 * self.SC.t0) Rstar = R / (1 + self.tesc / self.SC.tpb) Rtstar = R * xi return [Rstar, self.V, NT, NtT, Gt, Gd, Rtstar]
def calc_params(self, e, nrTraps, t1, xi, kbT): D = kidcalc.D(kbT, self.N0, self.kbTc, self.kbTD) c = (nrTraps / self.V / (2 * self.N0 * D)) NT = kidcalc.nqp(kbT, D, self.N0) * self.V NtT = self.V * 2 * self.N0 * D * c / kidcalc.f(e, kbT) R = (2 * D / self.kbTc)**3 / (4 * D * self.N0 * self.t0) Rstar = R / (1 + self.tesc / self.tpb) Rtstar = xi * (1 + e / D) / (t1 * self.N0 * D) return [Rstar, self.V, NT, NtT, Rtstar]
def calc_params(self, Gt, Gd, eta, P, kbT): D = kidcalc.D(kbT, self.N0, self.kbTc, self.kbTD) NT = kidcalc.nqp(kbT, D, self.N0) * self.V R = (2 * D / self.kbTc)**3 / (4 * D * self.N0 * self.t0) Rstar = R / (1 + self.tesc / self.tpb) Ges = 1 / self.tesc GB = 1 / self.tpb NTw = R * NT**2 / (2 * self.V * GB) return [R, self.V, GB, Gt, Gd, Ges, NTw, eta, P, D], NT, Rstar
def calc_S21(self, Nqp, hwread, s20, dhw=0): kbTeff = kidcalc.kbTeff(Nqp / self.V, self.SC) D = kidcalc.D(kbTeff, self.SC) s1, s2 = kidcalc.cinduct(hwread + dhw, D, kbTeff) Qi = interpolate.splev(kbTeff, self.Qispl) hwres = kidcalc.hwres(s2, self.hw0, s20, self.ak, self.kbT, D, SC.Sheet(self.SC, self.d)) return kidcalc.S21(Qi, self.Qc, hwread, dhw, hwres)
def calc_linresp(self, Nqp, hwread, D_0): s_0 = kidcalc.cinduct(hwread, D_0, self.kbT) Qi_0 = kidcalc.Qi(s_0[0], s_0[1], self.ak, self.kbT, D_0, SC.Sheet(self.SC, self.d)) Q = Qi_0 * self.Qc / (Qi_0 + self.Qc) beta = kidcalc.beta(self.kbT, D_0, SC.Sheet(self.SC, self.d)) kbTeff = kidcalc.kbTeff(Nqp / self.V, self.SC) D = kidcalc.D(kbTeff, self.SC) s1, s2 = kidcalc.cinduct(hwread, D, kbTeff) lindA = self.ak * beta * Q * (s1 - s_0[0]) / s_0[1] lintheta = -self.ak * beta * Q * (s2 - s_0[1]) / s_0[1] return lindA, lintheta
def calc_params(self, e, nrTraps, t1, t2, xi, kbT): D = kidcalc.D(kbT, self.SC) c = nrTraps / self.V / (2 * self.SC.N0 * D) NT = kidcalc.nqp(kbT, D, self.SC) * self.V NtT = self.V * 2 * self.SC.N0 * D * c * kidcalc.f(e, kbT) R = (2 * D / self.SC.kbTc)**3 / (4 * D * self.SC.N0 * self.SC.t0) Rstar = R / (1 + self.tesc / self.SC.tpb) Rtstar = xi / (t1 * self.SC.N0 * D) * (1 + e / D) Gd = (np.sqrt(np.pi) / 4 * (kbT / D)**(3 / 2) * np.exp(-(D - e) / kbT) * (1 / t1 * (3 + 2 * ((D - e) / kbT)) * kbT / D + 4 / t2 * (1 + (D - e) / kbT))) Gt = (2 * c / t2 * (1 - e / D) * (1 / (np.exp( (D - e) / kbT) - 1) + 1) * (1 - 1 / (np.exp(e / kbT) + 1))) return [Rstar, self.V, NT, NtT, Gt, Gd, Rtstar]
def calc_params(self, e, nrTraps, t1, t2, eta, P, kbT): D = kidcalc.D(kbT, self.SCvol.SC) NT = kidcalc.nqp(kbT, D, self.SCvol.SC) * self.SCvol.SC.V R = (2 * D / self.SCvol.SC.kbTc)**3 / (4 * D * self.SCvol.SC.N0 * self.SCvol.SC.t0) Rstar = R / (1 + self.SCvol.SC.tesc / self.SCvol.SC.tpb) Ges = 1 / self.SCvol.SC.tesc GB = 1 / self.SCvol.SC.tpb NwT = R * NT**2 / (2 * self.SCvol.SC.V * GB) Nqp0 = np.sqrt(self.SCvol.SC.V * ((1 + GB / Ges) * eta * P / D + 2 * GB * NwT) / R) kbTeff = kidcalc.kbTeff(Nqp0, self.SCvol.SC) Gd = (np.sqrt(np.pi) / 4 * (kbTeff / D)**(3 / 2) * np.exp(-(D - e) / kbTeff) * (1 / t1 * (3 + 2 * ((D - e) / kbTeff)) * kbTeff / D + 4 / t2 * (1 + (D - e) / kbTeff))) Gt = (2 * (nrTraps / self.SCvol.SC.V / (2 * self.SCvol.SC.N0 * D)) / t2 * (1 - e / D) * (1 / (np.exp((D - e) / kbTeff) - 1) + 1) * (1 - 1 / (np.exp(e / kbTeff) + 1))) return [R, self.SCvol.SC.V, GB, Gt, Gd, Ges, NwT, eta, P, D], NT, Rstar
def minfunc(kbT, s2s1, hw, SC): D_ = kidcalc.D(kbT, SC) s1, s2 = kidcalc.cinduct(hw, D_, kbT) return np.abs(s2s1 - s2 / s1)
def NLcomp(Chipnum, KIDnum, Pread, SCvol=None, method="", var="cross"): """Returns a spline representation of a Noise Level (non-dB) vs Temperature (K), with which the measured noise level can be compensated. For example, the method \'Resp\' gives the responsivity squared. If the measured noise level is divided by the responsivity squared, one is left with the quasiparticle fluctuation level. Arguments: Chipnum, KIDnum, Pread -- define which data is to be used (S21data and/or pulse data) SCvol -- a Volume object (see SC module), which defines superconductor properties method -- defines which level is to be returned. See if statements in the function for the options. (future: multiply every individual method stated in the method string) var -- gives the type of PSD to be compensated - cross, amp or phase - and is used if \'Reps\' is in the method """ if SCvol is None and method != "": S21data = io.get_S21data(Chipnum, KIDnum, Pread) SCvol = SuperCond.Volume(SuperCond.Al(Tc=S21data[0, 21]), V=S21data[0, 14], d=S21data[0, 25]) if method != "": S21data = io.get_S21data(Chipnum, KIDnum, Pread) if "ak" in method: akin = ak(S21data) if method == "QakV": lvlcompspl = interpolate.splrep( S21data[:, 1], (S21data[:, 2] * akin)**2 / SCvol.V**2, s=0) elif method == "QaksqrtV": lvlcompspl = interpolate.splrep( S21data[:, 1], (S21data[:, 2] * akin)**2 / (SCvol.V), s=0) elif method == "QaksqrtVtesc": lvlcompspl = interpolate.splrep( S21data[:, 1], (S21data[:, 2] * akin)**2 / (SCvol.V * (1 + SCvol.tesc / SCvol.SC.tpb)), s=0, ) elif method == "QaksqrtVtescTc": lvlcompspl = interpolate.splrep( S21data[:, 1], (S21data[:, 2] * akin)**2 / (SCvol.V * (1 + SCvol.tesc / SCvol.SC.tpb) * (const.Boltzmann / const.e * 1e6 * S21data[0, 21])**3 / (SCvol.SC.D0 / const.e * 1e6)**2), s=0, ) elif method == "Resp": lvlcompspl = interpolate.splrep( S21data[:, 1], interpolate.splev(S21data[:, 1], Respspl(Chipnum, KIDnum, Pread, var=var))**2, ) elif method == "RespPulse": lvlcompspl = interpolate.splrep( S21data[:, 1], interpolate.splev( S21data[:, 1], Respspl(Chipnum, KIDnum, Pread, ampmethod="pulse", var=var), )**2, ) elif method == "RespPint": Pint = 10**(-Pread / 10) * S21data[:, 2]**2 / (S21data[:, 3] * np.pi) Pint /= Pint[0] lvlcompspl = interpolate.splrep( S21data[:, 1], interpolate.splev(S21data[:, 1], Respspl(Chipnum, KIDnum, Pread, var=var)) / Pint**(1 / 2), s=0, ) elif method == "RespV": lvlcompspl = interpolate.splrep( S21data[:, 1], interpolate.splev(S21data[:, 1], Respspl(Chipnum, KIDnum, Pread, var=var)) * SCvol.V, s=0, ) elif method == "RespVtescTc": kbTc = const.Boltzmann / const.e * 1e6 * S21data[0, 21] lvlcompspl = interpolate.splrep( S21data[:, 1], interpolate.splev(S21data[:, 1], Respspl(Chipnum, KIDnum, Pread, var=var)) * SCvol.V * (1 + SCvol.tesc / SCvol.tpb) * (kbTc)**3 / (kidcalc.D(const.Boltzmann / const.e * 1e6 * S21data[:, 1], SCvol.SC))**2, s=0, ) elif method == "RespLowT": lvlcompspl = interpolate.splrep( S21data[:, 1], np.ones(len(S21data[:, 1])) * interpolate.splev( S21data[0, 1], Respspl(Chipnum, KIDnum, Pread, var=var)), ) elif method == "Resptres": lvlcompspl = interpolate.splrep( S21data[:, 1], interpolate.splev(S21data[:, 1], Respspl(Chipnum, KIDnum, Pread, var=var))**2 * (1 + (S21data[:, 1] * 2 * S21data[:, 2] / S21data[:, 5])**2), ) else: raise ValueError( "{} is an invalid compensation method".format(method)) Pint = 10 * np.log10( 10**(-1 * Pread / 10) * S21data[0, 2]**2 / S21data[0, 3] / np.pi) else: lvlcompspl = interpolate.splrep(np.linspace(0.01, 10, 10), np.ones(10)) return lvlcompspl
def ak(S21data, SC=None, plot=False, reterr=False, method="df", Tmin=.25): """Calculates the kinetic induction fraction, based on Goa2008, PhD Thesis. Arguments: S21data -- the content of the .csv from the S21-analysis. SC -- Superconductor object, from SC module, default: Al plot -- boolean to plot the fit over temperature. reterr -- boolean to return fitting error. method -- either df or Qi, which is fitted linearly over temperature. Returns: ak optionally: the error in ak from fitting.""" if SC is None: SC = SuperCond.Al(Tc=S21data[0, 21]) # Extract relevant data hw = S21data[:, 5] * const.Planck / const.e * 1e6 # µeV kbT = S21data[:, 1] * const.Boltzmann / const.e * 1e6 # µeV hw0 = hw[0] # define y to fit: if method == "df": y = (hw - hw0) / hw0 elif method == "Qi": y = 1 / S21data[:, 4] - 1 / S21data[0, 4] # Mask the double measured temperatures, and only fit from 250 mK mask1 = np.zeros(len(y), dtype="bool") mask1[np.unique(np.round(S21data[:, 1], decimals=2), return_index=True)[1]] = True mask = np.logical_and(mask1, (kbT >= Tmin * const.Boltzmann / const.e * 1e6)) if mask.sum() > 3: y = y[mask] else: warnings.warn( "Not enough high temperature S21data, taking the last 10 points") y = y[mask1][-10:] # define x to fit: x = np.zeros(len(y)) i = 0 s0 = kidcalc.cinduct(hw0, kidcalc.D(kbT[0], SC), kbT[0]) for kbTi in kbT[mask]: D_0 = kidcalc.D(kbTi, SC) s = kidcalc.cinduct(hw[i], D_0, kbTi) if method == "df": x[i] = (s[1] - s0[1]) / s0[1] * kidcalc.beta( kbTi, D_0, SuperCond.Sheet(SC, d=S21data[0, 25])) / 4 elif method == "Qi": x[i] = (s[0] - s0[0]) / s0[1] * kidcalc.beta( kbTi, D_0, SuperCond.Sheet(SC, d=S21data[0, 25])) / 2 i += 1 # do the fit: fit = curve_fit(lambda t, ak: ak * t, x, y) if plot: plt.figure() plt.plot(x, y, "o") plt.plot(x, fit[0] * x) plt.legend(["Data", "Fit"]) if method == "df": plt.ylabel(r"$\delta f/f_0$") plt.xlabel(r"$\beta \delta \sigma_2/4\sigma_2 $") elif method == "Qi": plt.ylabel(r"$\delta(1/Q_i)$") plt.xlabel(r"$\beta \delta \sigma_1/2\sigma_2 $") if reterr: return fit[0][0], np.sqrt(fit[1][0]) else: return fit[0][0]
def Nqp( Chipnum, KIDnum, pltPread="all", spec="cross", startstopf=(None, None), delampNoise=False, del1fNoise=False, del1fnNoise=False, Tminmax=None, relerrthrs=0.3, pltThrm=True, pltNqpQi=False, splitT=0, pltNqptau=False, SCvol=None, SCkwargs={}, nqpaxis=True, fig=None, ax=None, label=None, color=None, fmt="-o", ): """Plots the number of quasiparticle calculated from the noise levels and lifetimes from PSDs. options similar to options in ltnlvl. pltThrm -- also plot thermal line (needs constants) pltNqpQi -- plot Nqp from Qi as well (needs constants) splitT -- makes NqpQi line dashed below this T pltNqptau -- plot Nqp from lifetime only (need constants) nqpaxis -- also shows density on right axis.""" TDparam = io.get_grTDparam(Chipnum) if ax is None: fig, ax = plt.subplots() Preadar = _selectPread(pltPread, io.get_grPread(TDparam, KIDnum)) if Preadar.size > 1: cmap = matplotlib.cm.get_cmap("plasma") norm = matplotlib.colors.Normalize(-1.05 * Preadar.max(), -0.95 * Preadar.min()) clb = fig.colorbar(matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax) clb.ax.set_title(r"$P_{read}$ (dBm)") if SCvol is None: SCvol = SuperCond.init_SCvol(Chipnum, KIDnum, set_tesc=pltNqptau, **SCkwargs) for Pread in Preadar: S21data = io.get_S21data(Chipnum, KIDnum, Pread) Respspl = calc.Respspl(Chipnum, KIDnum, Pread, var=spec) Temp = io.get_grTemp(TDparam, KIDnum, Pread) if Tminmax is not None: if Tminmax[0] is not None: Temp = Temp[Temp > Tminmax[0]] if Tminmax[1] is not None: Temp = Temp[Temp < Tminmax[1]] Nqp, Nqperr, taut = np.zeros((3, len(Temp))) for i in range(len(Temp)): freq, SPR = io.get_grdata(TDparam, KIDnum, Pread, Temp[i], spec=spec) if delampNoise: freq, SPR = filters.del_ampNoise(freq, SPR) if del1fNoise: freq, SPR = filters.del_1fNoise(freq, SPR) if del1fnNoise: freq, SPR = filters.del_1fnNoise(freq, SPR) taut[i], tauterr, lvl, lvlerr = calc.tau(freq, SPR, retfnl=True, startf=startstopf[0], stopf=startstopf[1]) lvl = lvl / interpolate.splev(Temp[i] * 1e-3, Respspl)**2 lvlerr = lvlerr / interpolate.splev(Temp[i] * 1e-3, Respspl)**2 Nqp[i] = lvl / (4 * taut[i] * 1e-6) Nqperr[i] = np.sqrt((lvlerr / (4 * taut[i] * 1e-6))**2 + (-lvl * tauterr * 1e-6 / (4 * (taut[i] * 1e-6)**2))**2) mask = ~np.isnan(Nqp) mask[mask] = Nqperr[mask] / Nqp[mask] <= relerrthrs if color is None: if Preadar.size > 1: color = cmap(norm(-1 * Pread)) elif pltPread == "min": color = "purple" elif pltPread == "max": color = "gold" dataline = ax.errorbar( Temp[mask], Nqp[mask], yerr=Nqperr[mask], color=color, fmt=fmt, mec="k", capsize=2.0, label=label, ) if pltNqptau: Nqp_ = SCvol.V * kidcalc.nqpfromtau(taut, SCvol) (tauline, ) = ax.plot( Temp[mask], Nqp_[mask], color=color, zorder=len(ax.lines) + 1, label="$\\tau_{qp}^*$", ) if pltNqpQi: Preadar = io.get_S21Pread(Chipnum, KIDnum) for Pread in Preadar: S21data = io.get_S21data(Chipnum, KIDnum, Pread) T, Nqp = calc.NqpfromQi(S21data, SC=SCvol.SC) mask = np.logical_and(T * 1e3 > ax.get_xlim()[0], T * 1e3 < ax.get_xlim()[1]) totalT = T[mask] totalNqp = Nqp[mask] if len(Preadar) == 1: color = "g" else: color = cmap(norm(closestPread)) (Qline, ) = ax.plot( totalT[totalT > splitT] * 1e3, totalNqp[totalT > splitT], linestyle="-", color=color, zorder=len(ax.lines) + 1, label="$Q_i$", ) ax.plot( totalT[totalT < splitT] * 1e3, totalNqp[totalT < splitT], linestyle="--", color=color, zorder=len(ax.lines) + 1, ) if pltThrm: T = np.linspace(*ax.get_xlim(), 100) NqpT = np.zeros(100) for i in range(len(T)): D_ = kidcalc.D(const.Boltzmann / const.e * 1e6 * T[i] * 1e-3, SCvol.SC) NqpT[i] = SCvol.V * kidcalc.nqp( const.Boltzmann / const.e * 1e6 * T[i] * 1e-3, D_, SCvol.SC) (Thline, ) = ax.plot(T, NqpT, color="k", zorder=len(ax.lines) + 1, label="Thermal $N_{qp}$") handles, labels = ax.get_legend_handles_labels() by_label = dict(zip(labels, handles)) ax.legend(by_label.values(), by_label.keys()) ax.set_ylabel("$N_{qp}$") ax.set_xlabel("Temperature (mK)") ax.set_yscale("log") if nqpaxis: def nqptoNqp(x): return x * SCvol.V def Nqptonqp(x): return x / SCvol.V ax2 = ax.secondary_yaxis("right", functions=(Nqptonqp, nqptoNqp)) ax2.set_ylabel("$n_{qp}$ ($\\mu m^{-3}$)") if Preadar.size > 1: l, b, w, h = clb.ax.get_position().bounds clb.ax.set_position([l + 0.12, b, w, h])
def s20(self): D_0 = kidcalc.D(self.kbT0, self.SC) return kidcalc.cinduct(self.hw0, D_0, self.kbT0)[1]
def Nqp(Chipnum, KIDnum, pltPread='all', spec='cross', startstopf=(None, None), delampNoise=False, del1fNoise=False, del1fnNoise=False, Tmax=500, relerrthrs=.3, pltThrm=True, pltNqpQi=False, splitT=0, pltNqptau=False, tescPread='max', nqpaxis=True, fig=None, ax=None, label=None, clr=None, N0=1.72e4, kbTD=37312.0, kb=86.17): '''Plots the number of quasiparticle calculated from the noise levels and lifetimes from PSDs. options similar to options in ltnlvl. TODO: delete double code in ltnlvl and Nqp pltThrm -- also plot thermal line (needs constants) pltNqpQi -- plot Nqp from Qi as well (needs constants) splitT -- makes NqpQi line dashed below this T pltNqptau -- plot Nqp from lifetime only (need constants) nqpaxis -- also shows density on right axis. ''' TDparam = io.get_grTDparam(Chipnum) if ax is None or fig is None: fig, ax = plt.subplots() Preadar = _selectPread(pltPread, io.get_grPread(TDparam, KIDnum)) if Preadar.size > 1: cmap = matplotlib.cm.get_cmap('plasma') norm = matplotlib.colors.Normalize(-1.05 * Preadar.max(), -.95 * Preadar.min()) clb = fig.colorbar(matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax) clb.ax.set_title(r'$P_{read}$ (dBm)') for Pread in Preadar: S21data = io.get_S21data(Chipnum, KIDnum, Pread) if spec == 'cross': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, np.sqrt(S21data[:, 10] * S21data[:, 18]), s=0) elif spec == 'amp': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 18], s=0) elif spec == 'phase': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 10], s=0) Temp = io.get_grTemp(TDparam, KIDnum, Pread) Temp = Temp[Temp < Tmax] Nqp, Nqperr, taut = np.zeros((3, len(Temp))) for i in range(len(Temp)): freq, SPR = io.get_grdata(TDparam, KIDnum, Pread, Temp[i], spec=spec) if delampNoise: freq, SPR = filters.del_ampNoise(freq, SPR) if del1fNoise: freq, SPR = filters.del_1fNoise(freq, SPR) if del1fnNoise: freq, SPR = filters.del_1fnNoise(freq, SPR) taut[i],tauterr,lvl,lvlerr = \ calc.tau(freq,SPR,retfnl = True, startf=startstopf[0],stopf=startstopf[1]) lvl = lvl / interpolate.splev(Temp[i], Respspl)**2 lvlerr = lvlerr / interpolate.splev(Temp[i], Respspl)**2 Nqp[i] = lvl / (4 * taut[i] * 1e-6) Nqperr[i] = np.sqrt((lvlerr/(4*taut[i]*1e-6))**2+\ (-lvl*tauterr*1e-6/(4*(taut[i]*1e-6)**2))**2) mask = ~np.isnan(Nqp) mask[mask] = Nqperr[mask] / Nqp[mask] <= relerrthrs if Preadar.size > 1: clr = cmap(norm(-1 * Pread)) elif pltPread == 'min': clr = 'purple' elif pltPread == 'max': clr = 'gold' dataline = ax.errorbar(Temp[mask], Nqp[mask], yerr=Nqperr[mask], color=clr, marker='o', mec='k', capsize=2., label=label) if pltNqptau: tesc = calc.tesc(Chipnum, KIDnum, Pread=tescPread) Nqp_ = S21data[0, 14] * kidcalc.nqpfromtau(taut, tesc, kb * S21data[0, 21]) tauline, = ax.plot(Temp[mask], Nqp_[mask], color=clr, zorder=len(ax.lines) + 1, label='$\\tau_{qp}^*$') if pltNqpQi: Preadar = io.get_S21Pread(Chipnum, KIDnum) for Pread in Preadar: S21data = io.get_S21data(Chipnum, KIDnum, Pread) T, Nqp = calc.NqpfromQi(S21data) mask = np.logical_and(T * 1e3 > ax.get_xlim()[0], T * 1e3 < ax.get_xlim()[1]) totalT = T[mask] totalNqp = Nqp[mask] if len(Preadar) == 1: clr = 'g' else: clr = cmap(norm(closestPread)) Qline, = ax.plot(totalT[totalT > splitT] * 1e3, totalNqp[totalT > splitT], linestyle='-', color=clr, zorder=len(ax.lines) + 1, label='$Q_i$') ax.plot(totalT[totalT < splitT] * 1e3, totalNqp[totalT < splitT], linestyle='--', color=clr, zorder=len(ax.lines) + 1) if pltThrm: T = np.linspace(*ax.get_xlim(), 100) NqpT = np.zeros(100) for i in range(len(T)): D_ = kidcalc.D(kb * T[i] * 1e-3, N0, kb * S21data[0, 21], kbTD) NqpT[i] = S21data[0, 14] * kidcalc.nqp(kb * T[i] * 1e-3, D_, N0) Thline, = ax.plot(T, NqpT, color='k', zorder=len(ax.lines) + 1, label='Thermal $N_{qp}$') handles, labels = ax.get_legend_handles_labels() by_label = dict(zip(labels, handles)) ax.legend(by_label.values(), by_label.keys()) ax.set_ylabel('$N_{qp}$') ax.set_xlabel('Temperature (mK)') ax.set_yscale('log') if nqpaxis: def nqptoNqp(x): return x * S21data[0, 14] def Nqptonqp(x): return x / S21data[0, 14] ax2 = ax.secondary_yaxis('right', functions=(Nqptonqp, nqptoNqp)) ax2.set_ylabel('$n_{qp}$ ($\\mu m^{-3}$)') if Preadar.size > 1: l, b, w, h = clb.ax.get_position().bounds clb.ax.set_position([l + .12, b, w, h])
def D_0(self): """Energy gap at T""" return kidcalc.D(self.kbT, self.SC)
def ltnlvl(Chipnum, KIDlist=None, pltPread='all', spec='cross', Tminmax=None, startstopf=(None, None), decades=3, minfreq=1e2, lvlcomp='', delampNoise=False, del1fNoise=False, del1fnNoise=False, suboffres=False, relerrthrs=.2, pltKIDsep=True, pltthlvl=False, pltkaplan=False, pltthmfnl=False, plttres=False, fig=None, ax12=None, color='Pread', pltclrbar=True, fmt='-o', label=None, defaulttesc=0, tescPread='max', tescpltkaplan=False, tescTminmax=(300, 400), showfit=False, savefig=False): '''Plots the results from a Lorentzian fit to the PSDs of multiple KIDs, read powers and temperatures. Two axes: 0: lifetimes 1: noise levels, both with temperature on the x-axis. The color can be specified and is Pread by default. Options: startstopf -- defines the fitting window decades,minfreq -- fitting options, see kidata.calc.tau method lvlcomp -- defines how the levels are compensated. Use Resp for responsivity compensation. (will be moved in the future) del{}Noise -- filter options {amp,1f,1fn} spectrum before fitting, see kidata.filters module. relerrthrs -- only plot fits with a relative error threshold in lifetime less than this. pltKIDsep -- if True, different KIDs get a new figure. pltthlvl -- expected noise level is plotted as dashed line pltkaplan -- a kaplan fit (tesc as parameter) is plotted in the lifetime axis. pltthmfnl -- a noise level from the fitted lifetime and theoretical Nqp is plotted as well plttres -- the resonator ring time is plotted in the lifetime axis. ... multiple figure handling options ... ... options for the tesc deteremination ... showfit -- the fits are displayed in numerous new figures, for manual checking.''' def _make_fig(): fig, axs = plt.subplots(1, 2, figsize=(8, 3)) return fig, axs def _get_cmap(**kwargs): if color == 'Pread': cmap = matplotlib.cm.get_cmap('plasma') norm = matplotlib.colors.Normalize(-1.05 * kwargs['Preadar'].max(), -.95 * kwargs['Preadar'].min()) clb = fig.colorbar( matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)) clb.ax.set_title(r'$P_{read}$ (dBm)') elif color == 'Pint': cmap = matplotlib.cm.get_cmap('plasma') norm = matplotlib.colors.Normalize(kwargs['Pintar'].min() * 1.05, kwargs['Pintar'].max() * .95) clb = fig.colorbar( matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)) clb.ax.set_title(r'$P_{int}$ (dBm)') elif color == 'V': cmap = matplotlib.cm.get_cmap('cividis') norm = matplotlib.colors.Normalize( np.array(list(Vdict.values())).min(), np.array(list(Vdict.values())).max()) clb = fig.colorbar( matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)) clb.ax.set_title(r'Al Vol. ($\mu m^3$)') elif color == 'KIDnum': cmap = matplotlib.cm.get_cmap('Paired') norm = matplotlib.colors.Normalize( np.array(KIDlist).min(), np.array(KIDlist).max()) clb = fig.colorbar( matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)) clb.ax.set_title('KID nr.') else: raise ValueError( '{} is not a valid variable as color'.format(color)) return cmap, norm TDparam = io.get_grTDparam(Chipnum) if suboffres: TDparamoffres = io.get_grTDparam(Chipnum, offres=True) if KIDlist is None: KIDlist = io.get_grKIDs(TDparam) elif type(KIDlist) is int: KIDlist = [KIDlist] if color == 'Pint': Pintdict = io.get_Pintdict(Chipnum) if not pltKIDsep: if ax12 is None: fig, axs = _make_fig() else: axs = ax12 if color == 'Pint': Pintar = np.array([Pintdict[k] for k in KIDlist]) cmap, norm = _get_cmap(Pintar=Pintar) elif color == 'V': Vdict = io.get_Vdict(Chipnum) cmap, norm = _get_cmap(Vdict=Vdict) elif color == 'Pread': Preaddict = io.get_Preaddict(Chipnum) Preadar = np.array([Preaddict[k] for k in KIDlist]) cmap, norm = _get_cmap(Preadar=Preadar) elif color == 'KIDnum': cmap, norm = _get_cmap(KIDlist=KIDlist) for KIDnum in KIDlist: Preadar = _selectPread(pltPread, io.get_grPread(TDparam, KIDnum)) if pltKIDsep: if ax12 is None: fig, axs = _make_fig() else: axs = ax12 if len(KIDlist) > 1: fig.suptitle(f'KID{KIDnum}') if color == 'Pread': cmap, norm = _get_cmap(Preadar=Preadar) elif color == 'Pint': cmap, norm = _get_cmap(Pintar=np.array(Pintdict[KIDnum])) if pltthlvl or 'tesc' in lvlcomp or pltkaplan: tesc_ = calc.tesc(Chipnum, KIDnum, defaulttesc=defaulttesc, minTemp=tescTminmax[0], maxTemp=tescTminmax[1], relerrthrs=relerrthrs, Pread=tescPread, pltkaplan=tescpltkaplan) for Pread in Preadar: Temp = np.trim_zeros(io.get_grTemp(TDparam, KIDnum, Pread)) if lvlcomp != '': S21data = io.get_S21data(Chipnum, KIDnum, Pread) if 'ak' in lvlcomp: akin = calc.ak(S21data) V = S21data[0, 14] if spec == 'cross': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, np.sqrt(S21data[:, 10] * S21data[:, 18]), s=0) elif spec == 'amp': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 18], s=0) elif spec == 'phase': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 10], s=0) if lvlcomp == 'QakV': sqrtlvlcompspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 2] * akin / V, s=0) elif lvlcomp == 'QaksqrtV': sqrtlvlcompspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 2] * akin / np.sqrt(V), s=0) elif lvlcomp == 'QaksqrtVtesc': sqrtlvlcompspl = interpolate.splrep( S21data[:,1]*1e3, S21data[:,2]*akin/np.sqrt(V*\ (1+tesc_/.28e-3)),s=0) elif lvlcomp == 'QaksqrtVtescTc': sqrtlvlcompspl = interpolate.splrep( S21data[:,1]*1e3, S21data[:,2]*akin/np.sqrt(V*\ (1+tesc_/.28e-3)*\ (86.17*S21data[0,21])**3/\ (S21data[0,15]/1.6e-19*1e6)**2),s=0) elif lvlcomp == 'Resp': sqrtlvlcompspl = Respspl elif lvlcomp == 'RespPulse': pulsePreadar = io.get_pulsePread(Chipnum, KIDnum) pulsePreadselect = pulsePreadar[np.abs(pulsePreadar - Pread).argmin()] pulseTemp = io.get_pulseTemp(Chipnum, KIDnum, pulsePreadselect).min() pulsewvl = io.get_pulsewvl(Chipnum, KIDnum, pulsePreadselect, pulseTemp).min() phasepulse, amppulse = io.get_pulsedata( Chipnum, KIDnum, pulsePreadselect, pulseTemp, pulsewvl) phtau = calc.tau_pulse(phasepulse) amptau = calc.tau_pulse(amppulse) assert np.abs( 1 - phtau / amptau ) < .1, 'Amp and Phase lifetimes differ by more than 10%' dAdTheta = -1 * (amppulse / phasepulse )[600:int(600 + 2 * phtau)].mean() if spec == 'cross': Respspl = interpolate.splrep( S21data[:, 1] * 1e3, np.sqrt(S21data[:, 10]**2 * dAdTheta), s=0) elif spec == 'amp': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 10] * dAdTheta, s=0) elif spec == 'phase': Respspl = interpolate.splrep(S21data[:, 1] * 1e3, S21data[:, 10], s=0) sqrtlvlcompspl = Respspl elif lvlcomp == 'RespPint': Pint = 10**(-Pread / 10) * S21data[:, 2]**2 / ( S21data[:, 3] * np.pi) Pint /= Pint[0] sqrtlvlcompspl = interpolate.splrep( S21data[:, 1] * 1e3, interpolate.splev(S21data[:, 1] * 1e3, Respspl) / Pint**(1 / 4), s=0) elif lvlcomp == 'RespV': sqrtlvlcompspl = interpolate.splrep( S21data[:, 1] * 1e3, interpolate.splev(S21data[:, 1] * 1e3, Respspl) * np.sqrt(V), s=0) elif lvlcomp == 'RespVtescTc': kbTc = 86.17 * S21data[0, 21] sqrtlvlcompspl = interpolate.splrep( S21data[:,1]*1e3, interpolate.splev(S21data[:,1]*1e3, Respspl)*\ np.sqrt(V*(1+tesc_/.28e-3)*\ (kbTc)**3/\ (kidcalc.D(86.17*S21data[:,1],1.72e4,kbTc,37312.))**2),s=0) elif lvlcomp == 'RespLowT': sqrtlvlcompspl = interpolate.splrep( S21data[:,1]*1e3,np.ones(len(S21data[:,1]))*\ interpolate.splev(S21data[0,1]*1e3,Respspl)) else: raise ValueError( '{} is an invalid compensation method'.format(lvlcomp)) Pint = 10 * np.log10(10**(-1 * Pread / 10) * S21data[0, 2]**2 / S21data[0, 3] / np.pi) else: sqrtlvlcompspl = interpolate.splrep(Temp, np.ones(len(Temp))) if suboffres: Temp = np.intersect1d( Temp, io.get_grTemp(TDparamoffres, KIDnum, Pread)) if Tminmax != None: if Tminmax[0] != None: Temp = Temp[Temp > Tminmax[0]] if Tminmax[1] != None: Temp = Temp[Temp < Tminmax[1]] taut = np.zeros((len(Temp))) tauterr = np.zeros((len(Temp))) lvl = np.zeros((len(Temp))) lvlerr = np.zeros((len(Temp))) for i in range(len(Temp)): freq, SPR = io.get_grdata(TDparam, KIDnum, Pread, Temp[i], spec) if suboffres: orfreq, orSPR = io.get_grdata(TDparamoffres, KIDnum, Pread, Temp[i], spec) freq, SPR = filters.subtr_spec(freq, SPR, orfreq, orSPR) if delampNoise: freq, SPR = filters.del_ampNoise(freq, SPR) if del1fNoise: freq, SPR = filters.del_1fNoise(freq, SPR) if del1fnNoise: freq, SPR = filters.del_1fnNoise(freq, SPR) if showfit: print('{}, KID{}, -{} dBm, T={}, {}'.format( Chipnum, KIDnum, Pread, Temp[i], spec)) taut[i],tauterr[i],lvl[i],lvlerr[i] = \ calc.tau(freq,SPR,plot=showfit,retfnl=True, startf=startstopf[0],stopf=startstopf[1], decades=decades,minfreq=minfreq) if showfit: print(tauterr[i] / taut[i]) lvl[i] = lvl[i] / interpolate.splev(Temp[i], sqrtlvlcompspl)**2 lvlerr[i] = lvlerr[i] / interpolate.splev( Temp[i], sqrtlvlcompspl)**2 #Deleting bad fits and plotting: mask = ~np.isnan(taut) mask[mask] = tauterr[mask] / taut[mask] <= relerrthrs if color == 'Pread': clr = cmap(norm(-1 * Pread)) elif color == 'Pint': clr = cmap(norm(Pint)) elif color == 'V': clr = cmap(norm(Vdict[KIDnum])) elif color == 'KIDnum': clr = cmap(norm(KIDnum)) else: clr = color axs[0].errorbar(Temp[mask], taut[mask], yerr=tauterr[mask], fmt=fmt, capsize=3., color=clr, mec='k', label=label if Pread == Preadar[-1] else '') axs[1].errorbar(Temp[mask], 10 * np.log10(lvl[mask]), yerr=10 * np.log10( (lvlerr[mask] + lvl[mask]) / lvl[mask]), fmt=fmt, capsize=3., color=clr, mec='k', label=label if Pread == Preadar[-1] else '') if pltthlvl: if Tminmax is not None: Tstartstop = Tminmax else: Tstartstop = (Temp[mask].min(), Temp[mask].max()) Ttemp = np.linspace(*Tstartstop, 100) explvl = interpolate.splev(Ttemp, Respspl)**2 explvl *= 4*.44e-6*S21data[0,14]*1.72e4*(86.17*S21data[0,21])**3/\ (2*(S21data[0,15]/1.602e-19*1e6)**2)*(1+tesc_/.28e-3)/2 explvl /= interpolate.splev(Ttemp, sqrtlvlcompspl)**2 thlvlplot, = axs[1].plot(Ttemp, 10 * np.log10(explvl), color=clr, linestyle='--', linewidth=2.) axs[1].legend((thlvlplot, ), (r'Expected noise level', )) if pltkaplan and Temp[mask].size != 0 and Pread == Preadar.max(): if Tminmax is not None: Tstartstop = Tminmax else: Tstartstop = (Temp[mask].min(), Temp[mask].max()) T = np.linspace(*Tstartstop, 100) * 1e-3 taukaplan = kidcalc.tau_kaplan(T, tesc=tesc_, kbTc=86.17 * S21data[0, 21]) kaplanfit, = axs[0].plot(T * 1e3, taukaplan, color=clr, linestyle='--', linewidth=2.) axs[0].legend((kaplanfit, ), ('Kaplan', )) if pltthmfnl: try: tauspl = interpolate.splrep(Temp[mask], taut[mask], s=0) T = np.linspace(Temp[mask].min(), Temp[mask].max(), 100) Nqp = np.zeros(len(T)) for i in range(len(T)): Nqp[i] = V * nqp(T[i] * 86.17 * 1e-3, S21data[0, 15] / 1.602e-19 * 1e6, 1.72e4) thmfnl = 4*interpolate.splev(T,tauspl)*1e-6*\ Nqp*interpolate.splev(T,Respspl)**2 thmfnl /= interpolate.splev(T, sqrtlvlcompspl)**2 thmfnlplot, = axs[1].plot(T, 10 * np.log10(thmfnl), color=clr, linestyle='--', linewidth=3.) axs[1].legend( (thmfnlplot, ), ('Thermal Noise Level \n with measured $\\tau_{qp}^*$', )) except: warnings.warn( 'Could not make Thermal Noise Level, {},KID{},-{} dBm,{}' .format(Chipnum, KIDnum, Pread, spec)) if plttres: tresline, = axs[0].plot(S21data[:, 1] * 1e3, S21data[:, 2] / (np.pi * S21data[:, 5]) * 1e6, color=clr, linestyle=':') axs[0].legend((tresline, ), ('$\\tau_{res}$', )) axs[0].set_yscale('log') for i in range(2): axs[i].set_xlabel('Temperature (mK)') axs[0].set_ylabel(r'$\tau_{qp}^*$ (µs)') if lvlcomp == 'Resp': axs[1].set_ylabel(r'Noise Level/$\mathcal{R}^2(T)$ (dB/Hz)') elif lvlcomp == 'RespV': axs[1].set_ylabel(r'Noise Level/$(\mathcal{R}^2(T)V)$ (dB/Hz)') elif lvlcomp == 'RespVtescTc': axs[1].set_ylabel(r'Noise Level/$(\mathcal{R}^2(T)\chi)$ (dB/Hz)') elif lvlcomp == '': axs[1].set_ylabel(r'Noise Level (dB/Hz)') elif lvlcomp == 'RespLowT': axs[1].set_ylabel(r'Noise Level/$\mathcal{R}^2(T=50 mK)$ (dB/Hz)') else: axs[1].set_ylabel(r'comp. Noise Level (dB/Hz)') plt.tight_layout() if savefig: plt.savefig('GR_{}_KID{}_{}.pdf'.format(Chipnum, KIDnum, spec)) plt.close() if ax12 is None: return fig, axs