def _detect_resonator(self, plot=True): """ Finds frequency of the resonator visible on the VNA screen """ vna = self._vna tries_number = 3 for i in range(0, tries_number): vna.avg_clear(); vna.prepare_for_stb(); vna.sweep_single(); vna.wait_for_stb() frequencies, sdata = vna.get_frequencies(), vna.get_sdata() scan_range = frequencies[-1]-frequencies[0] port = circuit.notch_port(frequencies, sdata) port.autofit() fit_min_idx = argmin(abs(port.z_data_sim)) estimated_frequency = frequencies[argmin(abs(sdata))] estimated_amplitude = min(abs(sdata)) fit_frequency = frequencies[fit_min_idx] fit_amplitude = min(abs(port.z_data_sim)) if abs(fit_frequency-estimated_frequency)<0.1*scan_range and \ abs(fit_amplitude-estimated_amplitude)<5*estimated_amplitude: # Success! break else: # print(estimated_amplitude, fit_amplitude, estimated_frequency, fit_frequency) print("\rFit was inaccurate, retrying", end = "") if plot: port.plotall() return fit_frequency, fit_amplitude, angle(port.z_data_sim)[fit_min_idx]
def test_fit(f_data, z_data, fit_results, test): port1 = circuit.notch_port() port1.add_data(f_data, z_data) results = slf.fit(port1) assert fit_results[0] == pytest.approx( results[4], abs=0.02 * results[4]) and fit_results[1] == pytest.approx( results[5], 0.02 * results[5]), test
def test_fit(f_data, z_data, fit_results, test): port1 = circuit.notch_port() port1.add_data(f_data, z_data) delay, results = fitting_tool.fit(port1) assert fit_results[0] == pytest.approx(results[4],abs=0.02*results[4])\ and fit_results[1] == pytest.approx(results[5],0.02*results[5])\ and fit_results[2] == pytest.approx(delay, 0.02*delay), test
def detect_resonator(pna, type="AMP"): """ Finds a resonator on the screen """ freq = 1 if type == "AMP": Y = 20 * np.log10(abs(pna.get_sdata())) idx = np.where(Y == np.min(Y))[0][0] freq = pna.get_frequencies()[idx] amp = (Y[idx]) return freq, amp elif type == "PHAS": Y = np.diff(np.unwrap(np.angle(pna.get_sdata()))) idx = np.where(Y == np.max(Y))[0][0] freq = pna.get_frequencies()[idx] phas_derivative = Y[idx] return freq, phas_derivative elif type == "FIT": port = circuit.notch_port(pna.get_frequencies(), pna.get_sdata()) port.autofit() # port.plotall() # print(port.fitresults) return pna.get_frequencies()[np.argmin(abs( port.z_data_sim))], 20 * np.log10(min(abs(port.z_data_sim)))
def __init__(self, frequencies, s_data, plot=True, fast=False): self._freqs = frequencies self._s_data = s_data self._plot = plot self._port = notch_port(frequencies, s_data) # self._s_data_filtered = (savgol_filter(real(self._s_data), 21, 2)\ # + 1j*savgol_filter(imag(self._s_data), 21, 2)) # self._filtered_port = notch_port(frequencies, self._s_data_filtered) self._fast = fast
def resonator_quality_factor_fit(measurement, sweep_parameter_values, sweep_parameter_name='power', resonator_type='notch_port', delay=None, use_calibrate=False): from resonator_tools import circuit fitresults = [] sweep_parameter = measurement.datasets['S-parameter'].parameters[0].values f_data = measurement.datasets['S-parameter'].parameters[1].values z_data = measurement.datasets['S-parameter'].data if use_calibrate: max_power_id = np.argmax(sweep_parameter) if resonator_type == 'notch_port': fitter = circuit.notch_port(f_data = f_data, z_data_raw=z_data[max_power_id,:]) else: fitter = circuit.reflection_port(f_data = f_data, z_data_raw=z_data[max_power_id,:]) delay, amp_norm, alpha, fr, Ql, A2, frcal = \ fitter.do_calibration(f_data, z_data[max_power_id,:],ignoreslope=True,guessdelay=False) for power_id, power in enumerate(sweep_parameter_values): try: if use_calibrate: fitter.z_data = fitter.do_normalization(fitter.f_data,z_data[power_id,:],delay,amp_norm,alpha,A2,frcal) fitter.fitresults = fitter.circlefit(fitter.f_data,fitter.z_data,fr,Ql,refine_results=True,calc_errors=True) else: if resonator_type == 'notch_port': #print ('notch_port') fitter = circuit.notch_port(f_data = f_data, z_data_raw=z_data[power_id,:]) elif resonator_type == 'reflection_port': #print ('reflection_port') fitter = circuit.reflection_port(f_data = f_data, z_data_raw=z_data[power_id,:]) #print (power_id) fitter.autofit(electric_delay=delay) #print (fitter.fitresults) fitter.fitresults[sweep_parameter_name] = power fitter.fitresults['single_photon_limit'] = fitter.get_single_photon_limit() fitresults.append(fitter.fitresults.copy()) #fitter.plotall() #break except: pass #plt.figure(power_id) #fitter.plotall() #print(fitter.fitresults) return pd.DataFrame(fitresults)
def fit_resonator(array, fit_axis, plot_fit=False): """ Takes an xarray with data variables called 'amplitude' and 'phase' and returns an xarray consisting of the original raw data and the resonator fit parameters as a function of the coordinate 'fit_axis' (which is one of the coordinates of the input xarray). Fitting is performed using the 'notch_port' class of the circle-fit routine provided by https://github.com/sebastianprobst/resonator_tools @param array: xarray with the data variables amplitude (linear units) and phase (radians), has to have the coordinate frequency, and at least one further coordinate @param fit_axis: coordinate of the xarray along which the fits should be performed @param plot_fit: If True shows all raw data with fits overlay @return: xarray consisting of the raw input data plus the complex data, the complex data produced by the fit, and all fit parameters with fit_axis as coordinate. """ _z = array.amplitude.values * np.exp(1j * array.phase.values) z = DataArray(_z, name='complex', coords={fit_axis: getattr(array, fit_axis), 'frequency': array.frequency}, dims=[fit_axis, 'frequency']) array = merge([array, z]) fitresults = np.zeros((getattr(array, fit_axis).shape[0], 15)) fit_data = np.empty_like(array.complex.values) for i in range(getattr(array, fit_axis).shape[0]): z_dat = array.complex.isel({fit_axis: [i]}).values[0] res_fit = notch_port(f_data=array.frequency.values, z_data_raw=z_dat) res_fit.autofit() fitresults[i, :] = list(res_fit.fitresults.values()) fit_data[i, :] = res_fit.z_data_sim if plot_fit: fig2, ax2 = plt.subplots(1, 1, figsize=(10, 6)) ax2.plot(array.frequency.values, 20 * np.log10(np.abs(z_dat))) ax2.plot(array.frequency.values, 20 * np.log10(np.abs(res_fit.z_data_sim)), color='blue') ax2_2 = ax2.twinx() ax2_2.plot(array.frequency.values, np.angle(z_dat), color='tab:orange') ax2_2.plot(array.frequency.values, np.angle(res_fit.z_data_sim), color='orange') _fxA = [] for i in range(fitresults.shape[1]): _fxA += [DataArray(fitresults[:, i], name=list(res_fit.fitresults.keys())[i], coords={fit_axis: getattr(array, fit_axis).values}, dims=[fit_axis])] _zfitxA = DataArray(fit_data, name='complex_fit', coords={fit_axis: getattr(array, fit_axis), 'frequency': array.frequency}, dims=[fit_axis, 'frequency']) array = merge([array, *_fxA, _zfitxA]) return array
def resonator_tools_notch_port(f, S): ''' :param iterable_of_float f: frequencies at which the S-parameter has been sampled :param iterable_of_complex S: measured S-parameters :return x,z,parameters: fit results ''' from resonator_tools import circuit fitter = circuit.notch_port(f, S.ravel()) fitter.autofit() return f, fitter.z_data_sim, fitter.fitresults
def onselect(xmin, xmax): port = circuit.notch_port(self.freq_arr, self.resp_arr) port.autofit(fcrop=(xmin * 1e9, xmax * 1e9)) sim_db = 20 * np.log10(np.abs(port.z_data_sim)) line_fit_a.set_data(1e-9 * port.f_data, sim_db) line_fit_p.set_data(1e-9 * port.f_data, np.angle(port.z_data_sim)) f_min = port.f_data[np.argmin(sim_db)] print("----------------") print(f"fr = {port.fitresults['fr']}") print(f"Qi = {port.fitresults['Qi_dia_corr']}") print(f"Qc = {port.fitresults['Qc_dia_corr']}") print(f"Ql = {port.fitresults['Ql']}") print( f"kappa = {port.fitresults['fr'] / port.fitresults['Qc_dia_corr']}" ) print(f"f_min = {f_min}") print("----------------") fig1.canvas.draw()
def plots2p(): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from io import BytesIO import base64 from resonator_tools import circuit port1 = circuit.notch_port() port1.add_froms2p('c:/Users/3333.s2p', 3, 4, 'realimag', fdata_unit=1e9, delimiter=None) port1.autofit() print("Fit results:", port1.fitresults) port1.plotall() print("single photon limit:", port1.get_single_photon_limit(diacorr=True), "dBm") print("photons in reso for input -140dBm:", port1.get_photons_in_resonator(-140, unit='dBm', diacorr=True), "photons") print("done") sio = BytesIO() plt.savefig(sio, format='png') data = base64.encodebytes(sio.getvalue()).decode() html = ''' <html> <body> <img src="data:image/png;base64,{}" /> </body> <html> ''' plt.close() return html.format(data)
def onselect(xmin, xmax): port = circuit.notch_port(self.freq_arr, self.resp_arr[self._AMP_IDX]) port.autofit(fcrop=(xmin * 1e9, xmax * 1e9)) if norm: line_fit_a.set_data( 1e-9 * port.f_data, 20 * np.log10( np.abs(port.z_data_sim / self.amp_arr[self._AMP_IDX]))) else: line_fit_a.set_data(1e-9 * port.f_data, 20 * np.log10(np.abs(port.z_data_sim))) line_fit_p.set_data(1e-9 * port.f_data, np.angle(port.z_data_sim)) # print(port.fitresults) print("----------------") print(f"fr = {port.fitresults['fr']}") print(f"Qi = {port.fitresults['Qi_dia_corr']}") print(f"Qc = {port.fitresults['Qc_dia_corr']}") print(f"Ql = {port.fitresults['Ql']}") print( f"kappa = {port.fitresults['fr'] / port.fitresults['Qc_dia_corr']}" ) print("----------------") # ax2.set_title( # f"fr = {1e-6*fr:.0f} MHz, Ql = {Ql:.0f}, Qi = {Qi:.0f}, Qc = {Qc:.0f}, kappa = {1e-3*kappa:.0f} kHz") if blit: fig1.canvas.restore_region(self._bg) ax1.draw_artist(line_sel) ax2.draw_artist(line_a) ax2.draw_artist(line_fit_a) ax3.draw_artist(line_p) ax3.draw_artist(line_fit_p) fig1.canvas.blit(fig1.bbox) fig1.canvas.flush_events() else: fig1.canvas.draw()
def analyze(self, all_plots: bool = False): assert self.t_arr is not None assert self.store_arr is not None assert self.readout_freq_arr is not None assert self.readout_if_arr is not None assert self.readout_nco is not None assert len(self.readout_freq_arr) == self.readout_freq_nr assert len(self.readout_if_arr) == self.readout_freq_nr import matplotlib.pyplot as plt from scipy.optimize import curve_fit try: from resonator_tools import circuit _has_resonator_tools = True except ImportError: _has_resonator_tools = False ret_fig = [] idx = np.arange(IDX_LOW, IDX_HIGH) t_low = self.t_arr[IDX_LOW] t_high = self.t_arr[IDX_HIGH] nr_samples = IDX_HIGH - IDX_LOW if all_plots: # Plot raw store data for first iteration as a check fig1, ax1 = plt.subplots(2, 1, sharex=True, tight_layout=True) ax11, ax12 = ax1 ax11.axvspan(1e9 * t_low, 1e9 * t_high, facecolor="#dfdfdf") ax12.axvspan(1e9 * t_low, 1e9 * t_high, facecolor="#dfdfdf") ax11.plot(1e9 * self.t_arr, np.abs(self.store_arr[0, 0, :])) ax12.plot(1e9 * self.t_arr, np.angle(self.store_arr[0, 0, :])) ax12.set_xlabel("Time [ns]") fig1.show() ret_fig.append(fig1) # Analyze data = self.store_arr[:, 0, idx] data.shape = (self.readout_freq_nr, 2, nr_samples) resp_I_arr = np.zeros((2, self.readout_freq_nr), np.complex128) resp_Q_arr = np.zeros((2, self.readout_freq_nr), np.complex128) dt = self.t_arr[1] - self.t_arr[0] t = dt * np.arange(nr_samples) for ii, readout_if in enumerate(self.readout_if_arr): cos = np.cos(2 * np.pi * readout_if * t) sin = np.sin(2 * np.pi * readout_if * t) for jj in range(2): data_slice = data[ii, jj, :] # TODO: low-pass filter the demodulated signal? I_real = np.sum(data_slice.real * cos) / nr_samples I_imag = -np.sum(data_slice.real * sin) / nr_samples resp_I_arr[jj, ii] = I_real + 1j * I_imag Q_real = np.sum(data_slice.imag * cos) / nr_samples Q_imag = -np.sum(data_slice.imag * sin) / nr_samples resp_Q_arr[jj, ii] = Q_real + 1j * Q_imag _, resp_H_arr = untwist_downconversion(resp_I_arr, resp_Q_arr) resp_dB = 20 * np.log10(np.abs(resp_H_arr)) resp_phase = np.angle(resp_H_arr) # resp_phase *= -1 resp_phase = np.unwrap(resp_phase, axis=-1) N = self.readout_freq_nr // 4 idx = np.zeros(self.readout_freq_nr, bool) idx[:N] = True idx[-N:] = True pfit_g = np.polyfit(self.readout_freq_arr[idx], resp_phase[0, idx], 1) pfit_e = np.polyfit(self.readout_freq_arr[idx], resp_phase[1, idx], 1) pfit = 0.5 * (pfit_g + pfit_e) background = np.polyval(pfit, self.readout_freq_arr) resp_phase[0, :] -= background resp_phase[1, :] -= background separation = np.abs(resp_H_arr[1, :] - resp_H_arr[0, :]) p0 = [ self.readout_freq_arr[np.argmax(separation)], 1 / self.readout_duration, np.max(separation), 0.0, ] popt, pcov = curve_fit(_gaussian, self.readout_freq_arr, separation, p0) print("----------------") if _has_resonator_tools: port_g = circuit.notch_port( self.readout_freq_arr, resp_H_arr[0, :] * np.exp(-1j * background)) port_e = circuit.notch_port( self.readout_freq_arr, resp_H_arr[1, :] * np.exp(-1j * background)) port_g.autofit() port_e.autofit() f_g = port_g.fitresults['fr'] f_e = port_e.fitresults['fr'] chi_hz = (f_e - f_g) / 2 print(f"ω_g / 2π = {f_g * 1e-9:.6f} GHz") print(f"ω_e / 2π = {f_e * 1e-9:.6f} GHz") print(f"χ / 2π = {chi_hz * 1e-3:.2f} kHz") print(f"ω_opt / 2π = {popt[0] * 1e-9:.6f} GHz") print("----------------") fig2, ax2 = plt.subplots(3, 1, sharex=True, tight_layout=True, figsize=(6.4, 6.4)) ax21, ax22, ax23 = ax2 for ax_ in ax2: if _has_resonator_tools: ax_.axvline(1e-9 * f_g, ls='--', c='tab:red', alpha=0.5) ax_.axvline(1e-9 * f_e, ls='--', c='tab:purple', alpha=0.5) ax_.axvline(1e-9 * popt[0], ls='--', c='tab:brown', alpha=0.5) ax21.plot(1e-9 * self.readout_freq_arr, resp_dB[0, :], c="tab:blue", label='|g>') ax21.plot(1e-9 * self.readout_freq_arr, resp_dB[1, :], c="tab:orange", label='|e>') ax22.plot(1e-9 * self.readout_freq_arr, resp_phase[0, :], c="tab:blue") ax22.plot(1e-9 * self.readout_freq_arr, resp_phase[1, :], c="tab:orange") ax23.plot(1e-9 * self.readout_freq_arr, 1e3 * separation, c='tab:green', label='||e> - |g>|') if _has_resonator_tools: ax21.plot(1e-9 * port_g.f_data, 20 * np.log10(np.abs(port_g.z_data_sim)), c="tab:red", ls='--') ax21.plot(1e-9 * port_e.f_data, 20 * np.log10(np.abs(port_e.z_data_sim)), c="tab:purple", ls='--') ax22.plot(1e-9 * port_g.f_data, np.angle(port_g.z_data_sim), c="tab:red", ls='--') ax22.plot(1e-9 * port_e.f_data, np.angle(port_e.z_data_sim), c="tab:purple", ls='--') ax23.plot(1e-9 * self.readout_freq_arr, 1e3 * _gaussian(self.readout_freq_arr, *popt), c='tab:brown', ls='--') ax21.set_ylabel("Amplitude [dBFS]") ax22.set_ylabel("Phase [rad]") ax23.set_ylabel("Separation [mFS]") ax2[-1].set_xlabel("Readout frequency [GHz]") ax21.legend(ncol=2, loc="lower right") ax23.legend(loc="upper right") fig2.show() ret_fig.append(fig2) return ret_fig
from resonator_tools import circuit port1 = circuit.notch_port() port1.add_froms2p('S21testdata.s2p', 3, 4, 'realimag', fdata_unit=1e9, delimiter=None) port1.autofit() print "Fit results:", port1.fitresults port1.plotall() print "single photon limit:", port1.get_single_photon_limit( diacorr=True), "dBm" print "photons in reso for input -140dBm:", port1.get_photons_in_resonator( -140, unit='dBm', diacorr=True), "photons" print "done"
def fit_S21(self): from resonator_tools.circuit import notch_port fitter = notch_port(f_data=self.frequency.real, z_data_raw=self.S21) fitter.autofit() return fitter
def set_data(self, frequencies, s_data): self._freqs = frequencies self._s_data = s_data self._port = notch_port(frequencies, s_data)
import matplotlib.pyplot as plt import numpy as np from resonator_tools import circuit from IPython.display import display #%% table = pd.read_csv(r"./Projects/SFS_transmon/Simulations/res7.2_330.csv", header=None, skiprows=2, names=[ "Frequency (GHz)", "RE[S11]", "IM[S11]", "RE[S12]", "IM[S12]", "RE[S21]", "IM[S21]", "RE[S22]", "IM[S22]" ], delimiter=" ") table.head() #%% port = circuit.notch_port(table["Frequency (GHz)"], table["RE[S21]"] + 1j * table["IM[S21]"]) port.autofit() port.plotall() #%% display( pd.DataFrame([port.fitresults]).applymap(lambda x: "{0:.2e}".format(x))) #%% port.fitresults['fr'] #%%
from resonator_tools import circuit port1 = circuit.notch_port() port1.add_froms2p('S21testdata.s2p',3,4,'realimag',fdata_unit=1e9,delimiter=None) port1.autofit() print "Fit results:", port1.fitresults port1.plotall() print "single photon limit:", port1.get_single_photon_limit(diacorr=True), "dBm" print "photons in reso for input -140dBm:", port1.get_photons_in_resonator(-140,unit='dBm',diacorr=True), "photons" print "done"