Exemple #1
0
    def measure_2D(self):

        if self.x_set_obj == None or self.y_set_obj == None:
            print 'axes parameters not properly set...aborting'
            return
        if self.ReadoutTrace:
            raise ValueError('ReadoutTrace is currently not supported for 2D measurements')
        
        qt.mstart()
        self.mode = 2 #1: 1D, 2: 2D, 3:1D_AWG/2D_AWG
        self._prepare_measurement_file()
        #self._create_dat_plots(mode='2d')

        if self.show_progress_bar: p = Progress_Bar(len(self.x_vec)*len(self.y_vec),name=self.dirname)
        try:
            # measurement loop
            for x in self.x_vec:
                self.x_set_obj(x)
                for y in self.y_vec:
                    qt.msleep() 
                    self.y_set_obj(y)
                    qt.msleep() 
                    self._append_data()
                    if self.show_progress_bar: p.iterate()
                self._hdf_amp.next_matrix()
                self._hdf_pha.next_matrix()
        finally:
            self._end_measurement()
            qt.mend()
Exemple #2
0
    def measure_3D_AWG(self):
        '''
        x_vec is sequence in AWG
        '''

        if self.z_set_obj is None or self.y_set_obj is None:
            raise ValueError('x-axes parameters not properly set')
        if self.ReadoutTrace:
            raise ValueError(
                'ReadoutTrace is currently not supported for 3D_AWG measurements'
            )

        self.mode = 4  # 1: 1D, 2: 2D, 3:1D_AWG/2D_AWG, 4:3D_AWG
        self._prepare_measurement_file()

        if self.show_progress_bar:
            p = Progress_Bar(len(self.y_vec) * len(self.z_vec),
                             name=self.dirname)
        try:
            # measurement loop
            for z in self.z_vec:
                self.z_set_obj(z)
                for y in self.y_vec:
                    qkit.flow.sleep()
                    self.y_set_obj(y)
                    qkit.flow.sleep()
                    self._append_data()
                    if self.show_progress_bar: p.iterate()
                for i in range(self.ndev):
                    self._hdf_amp[i].next_matrix()
                    self._hdf_pha[i].next_matrix()
        finally:
            self._end_measurement()
Exemple #3
0
	def measure_2D_AWG(self):
		'''
		x_vec is sequence in AWG
		'''
		
		if self.y_set_obj == None:
			print 'axes parameters not properly set...aborting'
			return
	
		qt.mstart()
		qt.msleep()   #if stop button was pressed by now, abort without creating data files
		
		self._prepare_measurement_dat_file(mode='2dAWG')
		self._create_dat_plots(mode='2dAWG')

		p = Progress_Bar(len(self.y_vec),name=self.dirname)
		try:
			# measurement loop
			for it in range(len(self.y_vec)):
				qt.msleep() # better done during measurement (waiting for trigger)
				self.y_set_obj(self.y_vec[it])
				self._append_data([self.y_vec[it]],trace=True,it=it)
				self._update_plots()
				p.iterate()
		#except Exception as e:
		#	print e
		
		finally:
			self._safe_plots()
			self._generate_avg_data(final=True)
			self._close_files()
		
			qt.mend()
Exemple #4
0
 def measure_2D_AWG(self):
     '''
     x_vec is sequence in AWG
     '''
     
     if self.y_set_obj == None:
         print 'axes parameters not properly set...aborting'
         return
 
     qt.mstart()
     qt.msleep()   #if stop button was pressed by now, abort without creating data files
     
     self.mode = 3 #1: 1D, 2: 2D, 3:1D_AWG/2D_AWG
     self._prepare_measurement_file()
     
     if self.show_progress_bar: 
         p = Progress_Bar(len(self.y_vec),name=self.dirname)
     try:
         # measurement loop
         for it in range(len(self.y_vec)):
             qt.msleep() # better done during measurement (waiting for trigger)
             self.y_set_obj(self.y_vec[it])
             self._append_data(iteration=it)
             if self.show_progress_bar: p.iterate()
     finally:
         self._end_measurement()
     
         qt.mend()
Exemple #5
0
    def measure_2D_ddc_time_trace(self):
        """
        Performs a digital down conversion for exactly one value in your awg sequence. But you can sweep other
        parameters, such as mw-power or so.
        :return:
        """
        if self.y_set_obj is None:
            raise ValueError('y-axes parameters not properly set')
        time_end = float(self.sample.mspec.get_samples()
                         ) / self.sample.mspec.get_samplerate()
        time_array = np.linspace(0, time_end, self.sample.mspec.get_samples())
        self.set_x_parameters(time_array, 'time', True, 'sec')

        self.mode = 2  # 1: 1D, 2: 2D, 3:1D_AWG/2D_AWG
        self._prepare_measurement_file()

        if self.show_progress_bar:
            p = Progress_Bar(len(self.y_vec), name=self.dirname)
        try:
            for y in self.y_vec:
                qkit.flow.sleep()
                self.y_set_obj(y)
                qkit.flow.sleep()
                self._append_data(ddc=True)
                if self.show_progress_bar: p.iterate()
        finally:
            self._end_measurement()
Exemple #6
0
	def measure_2D(self):

		if self.x_set_obj == None or self.y_set_obj == None:
			print 'axes parameters not properly set...aborting'
			return
		
		qt.mstart()
		self._prepare_measurement_dat_file(mode='2d')
		self._create_dat_plots(mode='2d')

		p = Progress_Bar(len(self.x_vec)*len(self.y_vec),name=self.dirname)
		try:
			# measurement loop
			for x in self.x_vec:
				self.x_set_obj(x)
				if self.save_dat: self.data_raw.new_block()
				for y in self.y_vec:
					qt.msleep() # better done during measurement (waiting for trigge
					self.y_set_obj(y)
					#sleep(self.tdy)
					qt.msleep() # better done during measurement (waiting for trigger)
					self._append_data([x,y],trace=False)
					self._update_plots()
					p.iterate()
		finally:
			self._safe_plots()
			self._close_files()
			qt.mend()
Exemple #7
0
    def measure_2D_AWG(self, iterations=1):
        '''
        x_vec is sequence in AWG
        '''

        if self.y_set_obj is None:
            raise ValueError('y-axes parameters not properly set')

        qkit.flow.sleep(
        )  # if stop button was pressed by now, abort without creating data files

        if iterations > 1:
            self.z_vec = range(iterations)
            self.z_coordname = 'iteration'
            self.z_set_obj = lambda z: True
            self.z_unit = ''

            self.measure_3D_AWG()

            # For 3D measurements with iterations, averages are only created at the end to get a consistent averaging base.
            hdf_file = hdf.Data(self._hdf.get_filepath())
            for j in range(self.ndev):
                amp = np.array(hdf_file["/entry/data0/amplitude_%i" % j])
                pha = np.array(hdf_file["/entry/data0/phase_%i" % j])
                amp_avg = sum(amp[i] for i in range(iterations)) / iterations
                pha_avg = sum(pha[i] for i in range(iterations)) / iterations
                hdf_amp_avg = hdf_file.add_value_matrix('amplitude_avg_%i' % i,
                                                        x=self._hdf_y,
                                                        y=self._hdf_x,
                                                        unit='a.u.')
                hdf_pha_avg = hdf_file.add_value_matrix('phase_avg_%i' % i,
                                                        x=self._hdf_y,
                                                        y=self._hdf_x,
                                                        unit='rad')

                for i in range(len(self.y_vec)):
                    hdf_amp_avg.append(amp_avg[i])
                    hdf_pha_avg.append(pha_avg[i])
            hdf_file.close_file()

        else:
            self.mode = 3  # 1: 1D, 2: 2D, 3:1D_AWG/2D_AWG, 4:3D_AWG
            self._prepare_measurement_file()
            if self.ndev > 1:
                raise ValueError(
                    'Multiplexed readout is currently not supported for 2D measurements'
                )
            if self.show_progress_bar:
                p = Progress_Bar(len(self.y_vec), name=self.dirname)
            try:
                # measurement loop
                for it in range(len(self.y_vec)):
                    qkit.flow.sleep(
                    )  # better done during measurement (waiting for trigger)
                    self.y_set_obj(self.y_vec[it])
                    self._append_data(iteration=it)
                    if self.show_progress_bar: p.iterate()
            finally:
                self._end_measurement()
Exemple #8
0
    def measure_1D(self):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False

        if not self.dirname:
            self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())

        print 'recording trace...'
        sys.stdout.flush()

        qt.mstart()
        self.vna.avg_clear()
        if self.vna.get_averages() == 1 or self.vna.get_Average() == False:   #no averaging
            self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
            qt.msleep(self.vna.get_sweeptime())      #wait single sweep
            self._p.iterate()
        else:   #with averaging
            self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
            if "avg_status" in self.vna.get_function_names():
                for a in range(self.vna.get_averages()):
                    while self.vna.avg_status() <= a:
                        qt.msleep(.2) #maybe one would like to adjust this at a later point
                    self._p.iterate()
            else: #old style
                for a in range(self.vna.get_averages()):
                    qt.msleep(self.vna.get_sweeptime())      #wait single sweep time
                    self._p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        self._data_amp.append(data_amp)
        self._data_pha.append(data_pha)
        self._data_real.append(data_real)
        self._data_imag.append(data_imag)
        if self._fit_resonator:
            self._do_fit_resonator()

        qt.mend()
        self._end_measurement()
Exemple #9
0
    def measure_3D(self, web_visible=True):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = True
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_3D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = self.y_coordname
        self._measurement_object.z_axis = 'frequency'
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname + ', ' + self.y_coordname
        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(
                len(self.x_vec) * len(self.y_vec),
                '3D VNA sweep ' + self.dirname,
                self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        """only middle point in freq array is plotted vs x and y"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []  #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()
Exemple #10
0
    def measure_2D(self, web_visible=True):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        if len(self.x_vec) == 0:
            logging.error(
                'No points to measure given. Check your x vector... aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'frequency'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(len(self.x_vec),
                                   '2D VNA sweep ' + self.dirname,
                                   self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self._nop < 10:
            if self.open_qviewkit:
                self._qvk_process = qviewkit.plot(
                    self._data_file.get_filepath(),
                    datasets=['amplitude_midpoint', 'phase_midpoint'])
        else:
            if self.open_qviewkit:
                self._qvk_process = qviewkit.plot(
                    self._data_file.get_filepath(),
                    datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        self._measure()
Exemple #11
0
 def _wait_progress_bar(self):
     ti = time()
     if self.progress_bar: 
         self._p = Progress_Bar(self.IVD.get_averages(),self.dirname,self.IVD.get_sweeptime())
     qt.msleep(.2)
     # wait for data
     while not self.IVD.ready():
         if time()-ti > self.IVD.get_sweeptime(query=False):
             if self.progress_bar: self._p.iterate()
             ti = time()
         qt.msleep(.2)
     
     if self.progress_bar:
         while self._p.progr < self._p.max_it:
             self._p.iterate()
Exemple #12
0
 def ramp_to(self, target = 0, channel = 0, steps = 20, dt = 0.1):
     """
     Ramp current to target
     Inputs:
         - target: target current value (mA)
         - channel: channel index (1..)
         - steps: number of steps
         - dt: wait time between two steps
     """
     p = Progress_Bar(steps,'Ramping current')
     for c in np.linspace(self.do_get_current(channel),target,steps):
         self.do_set_current(c, channel, verbose=False)
         p.iterate('{:.3g}mA'.format(c))
         time.sleep(dt)
     self.do_set_current(target, channel ,verbose=True)
Exemple #13
0
 def ramp_to(self, target = 0, ch = 1, steps = 100, dt = 0.05):
     """
     ramp current to target
     Inputs:
         - target: target current value
         - ch: channel index (1..)
         - steps: number of steps
         - dt: wait time between two steps
     """
     p = Progress_Bar(steps,'Ramping current')   #init progress bar
     for c in np.linspace(self.do_get_current(ch),target,steps):
         self.do_set_current(c,ch,verbose=False)
         p.iterate("%.3gmA"%c)
         time.sleep(dt)
     self.do_set_current(c,ch,verbose=True)
Exemple #14
0
 def ramp_to(self, target=0, ch=1, steps=100, dt=0.05):
     """
     ramp current to target
     Inputs:
         - target: target current value
         - ch: channel index (1..)
         - steps: number of steps
         - dt: wait time between two steps
     """
     p = Progress_Bar(steps, 'Ramping current')  #init progress bar
     for c in np.linspace(self.do_get_current(ch), target, steps):
         self.do_set_current(c, ch, verbose=False)
         p.iterate("%.3gmA" % c)
         time.sleep(dt)
     self.do_set_current(c, ch, verbose=True)
Exemple #15
0
    def measure_1D2(self):
        '''
        measure full window of vna while sweeping x_set_obj with parameters x_vec
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_1D2 = True
        self._scan_2D = False
        self.data_complex = False

        if self.dirname == None:
            self.dirname = self.x_coordname.replace()
        self._file_name = '1D2_' + self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self._p = Progress_Bar(len(self.x_vec),self.dirname)

        self._prepare_measurement_vna()
        if self.save_dat:
            self._prepare_measurement_dat_file()
        if self.save_hdf:
            self._prepare_measurement_hdf_file()
            """opens qviewkit to plot measurement, amp and pha are opened by default"""
            qviewkit.plot(self._data_hdf.get_filepath(), datasets=['amplitude', 'phase'])
            if self._fit_resonator:
                self._resonator = resonator(self._data_hdf)

        self._measure()
        self._end_measurement()
Exemple #16
0
    def measure_2D(self):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self._p = Progress_Bar(len(self.x_vec),'2D VNA sweep '+self.dirname,self.vna.get_sweeptime())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self._nop < 10:
            qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude_midpoint', 'phase_midpoint'])
        else:
            qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        self._measure()
Exemple #17
0
 def ramp_current(self, current, ramp_rate=1e-3, progress_bar=False):
     """
     ramps the bias current to a specified value with the specified ramp_rate.
     current: float, end current
     ramp_rate: float, change of voltage per second
     progress_bar: bool, weather the progress_bar should be displayed
     """
     start_current = self.do_get_measure_current()
     if np.sign(current - start_current) != np.sign(ramp_rate):
         ramp_rate *= (-1)
     current_values = np.arange(start_current, current, 0.1 * ramp_rate)
     if progress_bar:
         pb = Progress_Bar(len(current_values))
     for c in current_values:
         self.do_set_bias_current(c)
         time.sleep(0.1)
         if progress_bar:
             pb.iterate()
Exemple #18
0
    def measure_IV(self):
        self._measure_IV_1D = True
        self._measure_IV_2D = False
        self._measure_IV_3D = False
        if not self._check_measurement:
            return

        self._scan_name = 'IV'
        if self.exp_name:
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(self._sweeps)

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.get_filepath()

        self._measure()
        self._end_measurement()
Exemple #19
0
    def measure_IV_3D(self):
        self._measure_IV_1D = False
        self._measure_IV_2D = False
        self._measure_IV_3D = True
        if not self._check_measurement:
            return

        self._scan_name = 'IV_vs_' + self.x_coordname + '_' + self.y_coordname
        if self.exp_name:
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(len(self.x_vec) * len(self.y_vec))

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.filepath())

        self._measure()
        self._end_measurement()
Exemple #20
0
    def measure_1D(self):
        if self.x_set_obj is None:
            raise ValueError('x-axes parameters not properly set')

        self.mode = 1  # 1: 1D, 2: 2D, 3:1D_AWG/2D_AWG, 4:3D_AWG
        self._prepare_measurement_file()

        if self.show_progress_bar:
            p = Progress_Bar(len(self.x_vec), name=self.dirname)
        try:
            # measurement loop
            for x in self.x_vec:
                self.x_set_obj(x)
                qkit.flow.sleep()
                self._append_data()
                if self.show_progress_bar: p.iterate()
        finally:
            self._end_measurement()
Exemple #21
0
 def ramp_voltage(self, voltage, ramp_rate=1e-3, progress_bar=False):
     """
     ramps the bias voltage to a specified value with the specified ramp_rate.
     Keep in mind the defined current limit
     voltage: float, end voltage
     ramp_rate: float, change of voltage per second
     progress_bar: bool, weather the progress_bar should be displayed
     """
     start_voltage = self.do_get_measure_voltage()
     if np.sign(voltage - start_voltage) != np.sign(ramp_rate):
         ramp_rate *= (-1)
     voltage_values = np.arange(start_voltage, voltage, 0.1 * ramp_rate)
     if progress_bar:
         pb = Progress_Bar(len(voltage_values))
     for v in voltage_values:
         self.do_set_bias_voltage(v)
         time.sleep(0.1)
         if progress_bar:
             pb.iterate()
Exemple #22
0
    def measure_2D(self, web_visible=True):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'frequency'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(len(self.x_vec),
                                   '2D signal analyzer sweep ' + self.dirname,
                                   self.sig_analyzer.get_sweeptime_averages())

        self._prepare_measurement_sig_analyzer()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""

        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=self.traces_names)
        self._measure()
Exemple #23
0
    def measure_1D(self):
    
        if self.x_set_obj == None:
            print 'axes parameters not properly set...aborting'
            return

        qt.mstart()
        self.mode = 1 #1: 1D, 2: 2D, 3:1D_AWG/2D_AWG
        self._prepare_measurement_file()
        
        if self.show_progress_bar: p = Progress_Bar(len(self.x_vec),name=self.dirname)
        try:
            # measurement loop
            for x in self.x_vec:
                self.x_set_obj(x)
                qt.msleep() # better done during measurement (waiting for trigger)
                self._append_data()
                if self.show_progress_bar: p.iterate()
        finally:
            #self._safe_plots()
            self._end_measurement()
            qt.mend()
Exemple #24
0
    def measure_1D(self):

        if self.x_set_obj == None:
            print 'axes parameters not properly set...aborting'
            return

        qt.mstart()
        self.mode = 1  #1: 1D, 2: 2D, 3:1D_AWG/2D_AWG
        self._prepare_measurement_file()

        if self.show_progress_bar:
            p = Progress_Bar(len(self.x_vec), name=self.dirname)
        try:
            # measurement loop
            for x in self.x_vec:
                self.x_set_obj(x)
                qt.msleep(
                )  # better done during measurement (waiting for trigger)
                self._append_data()
                if self.show_progress_bar: p.iterate()
        finally:
            #self._safe_plots()
            self._end_measurement()
            qt.mend()
Exemple #25
0
	def measure_1D(self):
	
		if self.x_set_obj == None:
			print 'axes parameters not properly set...aborting'
			return

		self.time_data = False
		qt.mstart()
		self._prepare_measurement_dat_file(mode='1d')
		self._create_dat_plots(mode='1d')

		p = Progress_Bar(len(self.x_vec),name=self.dirname)
		try:
			# measurement loop
			for x in self.x_vec:
				self.x_set_obj(x)
				qt.msleep() # better done during measurement (waiting for trigger)
				self._append_data([x],trace=False)
				self._update_plots()
				p.iterate()
		finally:
			self._safe_plots()
			self._close_files()
			qt.mend()
Exemple #26
0
    def measure_3D(self, web_visible = True):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = True
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_3D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = self.y_coordname
        self._measurement_object.z_axis = 'frequency'
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname + ', ' + self.y_coordname
        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar: self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec),'3D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        """only middle point in freq array is plotted vs x and y"""
        if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []     #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()
Exemple #27
0
    def measure_IV_3D(self):
        self._measure_IV_1D = False
        self._measure_IV_2D = False
        self._measure_IV_3D = True
        if not self._check_measurement: 
            return

        self._scan_name = 'IV_vs_'+ self.x_coordname + '_' + self.y_coordname
        if self.exp_name: 
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec))

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.filepath())

        self._measure()
        self._end_measurement()
Exemple #28
0
    def measure_IV(self):
        self._measure_IV_1D = True
        self._measure_IV_2D = False
        self._measure_IV_3D = False
        if not self._check_measurement: 
            return

        self._scan_name = 'IV'
        if self.exp_name: 
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(self._sweeps)

        self._prepare_measurement_file() 
        self._save_settings()
        #qviewkit.plot_hdf(self._data.get_filepath()

        self._measure()
        self._end_measurement()
Exemple #29
0
    def measure_2D(self):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_1D2 = False
        self._scan_2D = True
        self.data_complex = False

        if self.dirname == None:
            self.dirname = self.x_coordname.replace() + '_' + self.y_coordname.replace()
        self._file_name = '2D_' + self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec),self.dirname)

        self._prepare_measurement_vna()
        if self.save_dat:
            self._prepare_measurement_dat_file()
        if self.save_hdf:
            self._prepare_measurement_hdf_file()
            if self._fit_resonator:
                self._resonator = resonator(self._data_hdf)

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []   #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()
        self._end_measurement()
Exemple #30
0
    def measure_timetrace(self, web_visible = True):
        '''
        measure method to record a single VNA timetrace, this only makes sense when span is set to 0 Hz!,
        tested only with KEYSIGHT E5071C ENA and its corresponding qkit driver
        LGruenhaupt 11/2016
        '''
        if self.vna.get_span() > 0: 
            print 'VNA span not set to 0 Hz... aborting'
            return
            
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = True
        
        self._measurement_object.measurement_func = 'measure_timetrace'
        self._measurement_object.x_axis = 'time'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible
        
        if not self.dirname:
            self.dirname = 'VNA_timetrace'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        
        self.x_vec = np.arange(0,self.number_of_timetraces,1)
        
        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        
        if self.progress_bar: self._p = Progress_Bar(self.number_of_timetraces,'VNA timetrace '+self.dirname,self.vna.get_sweeptime_averages())
        
        print 'recording timetrace(s)...'
        sys.stdout.flush()

        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """

            for i, x in enumerate(self.x_vec):
                
                if self.log_function != None:
                    for i,f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))
                        
                if self.averaging_start_ready: #LG 11/2016
                    self.vna.start_measurement()
                    ti = time() #changed from time.time() to time() - LGruenhaupt OCT_2016
                    tp = time() #added to enable use of progress bar
                    #self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime_averages()) moved to line 303
                    
                    ''' This is to prevent the vna.ready() function from timing out. LG NOV/16 '''
                    if self.vna.get_Average():
                        print 'this function only makes sense without averaging'
                        qt.mend()
                        self._end_measuremt()
                    else:
                        #self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                        qt.msleep(self.vna.get_sweeptime())
                        #self._p.iterate()
                        
                        while not self.vna.ready(): qt.msleep(.2) #this is just to check if the measurement has finished
                        
                        data_amp, data_pha = self.vna.get_tracedata()
                        self._data_amp.append(data_amp)
                        self._data_pha.append(data_pha)
                qt.msleep()       
                if self.progress_bar:
                    self._p.iterate()
                
                        
                else: 
                    print 'not implemented for this VNA, only works with Keysight ENA 5071C'
                    qt.mend()
                    self._end_measurement()
                    
        except Exception as e:
            print e.__doc__
            print e.message        
        finally:
            self._end_measurement()
            qt.mend()
Exemple #31
0
def update_sequence(ts,
                    wfm_func,
                    sample,
                    iq=None,
                    loop=False,
                    drive='c:',
                    path='\\waveforms',
                    reset=True,
                    marker=None,
                    markerfunc=None,
                    ch2_amp=2,
                    chpair=1,
                    awg=None,
                    show_progress_bar=True):
    '''
        set awg to sequence mode and push a number of waveforms into the sequencer
        
        inputs:
        
        ts: array of times, len(ts) = #sequenzes
        wfm_func: waveform function usually generated via generate_waveform using ts[i]; this can be a tuple of arrays (for channels 0,1, heterodyne mode) or a single array (homodyne mode)
        sample: sample object
        
        iq: Reference to iq mixer instrument. If None (default), the wfm will not be changed. Otherwise, the wfm will be converted via iq.convert()
        
        marker: marker array in the form [[ch1m1,ch1m2],[ch2m1,ch2m2]] and all entries arrays of sample length
        markerfunc: analog to wfm_func, set marker to None when used
        
        for the 6GS/s AWG, the waveform length must be divisible by 64
        for the 1.2GS/s AWG, it must be divisible by 4
        
        chpair: if you use the 4ch Tabor AWG as a single 2ch instrument, you can chose to take the second channel pair here (this can be either 1 or 2).
    '''
    qkit.flow.start()
    if awg == None:
        awg = sample.awg
    clock = sample.clock
    wfm_func2 = wfm_func
    if iq != None:
        wfm_func2 = lambda t, sample: iq.convert(wfm_func(t, sample))

    # create new sequence
    if reset:
        if "Tektronix" in awg.get_type():
            awg.set_runmode('SEQ')
            awg.set_seq_length(0)  #clear sequence, necessary?
            awg.set_seq_length(len(ts))
        elif "Tabor" in awg.get_type():
            awg.set('p%i_runmode' % chpair, 'SEQ')
            awg.define_sequence(chpair * 2 - 1, len(ts))

        #amplitude settings of analog output
        awg.set_ch1_offset(0)
        awg.set_ch2_offset(0)
        awg.set_ch1_amplitude(2)
        awg.set_ch2_amplitude(ch2_amp)

    #generate empty tuples
    wfm_samples_prev = [None, None]
    wfm_fn = [None, None]
    wfm_pn = [None, None]
    if show_progress_bar:
        p = Progress_Bar(
            len(ts) * (2 if "Tektronix" in awg.get_type() else 1),
            'Load AWG')  #init progress bar

    #update all channels and times
    for ti, t in enumerate(ts):  #run through all sequences
        qkit.flow.sleep()
        wfm_samples = wfm_func2(t, sample)  #generate waveform
        if not isinstance(wfm_samples[0],
                          (list, tuple, np.ndarray)):  #homodyne
            wfm_samples = [
                wfm_samples,
                np.zeros_like(wfm_samples, dtype=np.int8)
            ]

        for chan in [0, 1]:
            if markerfunc != None:  #use markerfunc
                try:
                    if markerfunc[chan][0] == None:
                        marker1 = np.zeros_like(wfm_samples, dtype=np.int8)[0]
                    else:
                        marker1 = markerfunc[chan][0](t, sample)

                    if markerfunc[chan][1] == None:
                        marker2 = np.zeros_like(wfm_samples, dtype=np.int8)[0]
                    else:
                        marker2 = markerfunc[chan][1](t, sample)

                except TypeError:  #only one markerfunc given
                    marker1, marker2 = np.zeros_like(wfm_samples,
                                                     dtype=np.int8)
                    if chan == 0:
                        marker1 = markerfunc(t, sample)

            elif marker == None:  #fill up with zeros
                marker1, marker2 = np.zeros_like(wfm_samples, dtype=np.int8)
            else:  #or set your own markers
                c_marker1, c_marker2 = marker[chan]
                marker1 = c_marker1[ti]
                marker2 = c_marker2[ti]

            if "Tektronix" in awg.get_type():
                wfm_fn[chan] = 'ch%d_t%05d' % (
                    chan + 1, ti)  # filename is kept until changed
                if len(wfm_samples) == 1 and chan == 1:
                    wfm_pn[chan] = '%s%s\\%s' % (
                        drive, path, np.zeros_like(
                            wfm_fn[0]))  #create empty array
                else:
                    wfm_pn[chan] = '%s%s\\%s' % (drive, path, wfm_fn[chan])
                awg.wfm_send(wfm_samples[chan], marker1, marker2, wfm_pn[chan],
                             clock)

                awg.wfm_import(wfm_fn[chan], wfm_pn[chan], 'WFM')

                # assign waveform to channel/time slot
                awg.wfm_assign(chan + 1, ti + 1, wfm_fn[chan])

                if loop:
                    awg.set_seq_loop(ti + 1, np.infty)
            elif "Tabor" in awg.get_type():
                if chan == 1:  #write out both together
                    awg.wfm_send2(wfm_samples[0], wfm_samples[1], marker1,
                                  marker2, chpair * 2 - 1, ti + 1)
                else:
                    continue
            else:
                raise ValueError("AWG type not known")
            if show_progress_bar: p.iterate()

        gc.collect()

    if reset and "Tektronix" in awg.get_type():
        # enable channels
        awg.set_ch1_status(True)
        awg.set_ch2_status(True)
        awg.set_seq_goto(len(ts), 1)
        awg.run()
        awg.wait(10, False)
    elif reset and "Tabor" in awg.get_type():
        # enable channels
        #awg.preset()
        awg.set_ch1_status(True)
        awg.set_ch2_status(True)
    qkit.flow.end()
    if sample.__dict__.has_key('mspec'):
        sample.mspec.spec_stop()
        sample.mspec.set_segments(len(ts))
    return np.all([awg.get('ch%i_status' % i) for i in [1, 2]])
Exemple #32
0
class spectrum(object):
    '''
    useage:

    m = spectrum(vna = 'vna1')
    m2 = spectrum(vna = 'vna2', mw_src = 'mw_src1')   #where 'vna2'/'mw_src1' is the qt.instruments name

    m.set_x_parameters(arange(-0.05,0.05,0.01),'flux coil current',coil.set_current, unit = 'mA')
    m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency',mw_src1.set_frequency, unit = 'Hz')

    m.gen_fit_function(...)   several times

    m.measure_XX()
    '''

    def __init__(self, vna, exp_name = ''):

        self.vna = vna
        self.exp_name = exp_name

        self.landscape = None
        self.span = 200e6   #[Hz]
        self.tdx = 0.002   #[s]
        self.tdy = 0.002   #[s]
        self.data_complex = False

        self.comment = ''
        self.dirname = None
        self.plot3D = True
        self.plotlive = True

        self.x_set_obj = None
        self.y_set_obj = None

        self.return_dat = False

        self.save_dat = True
        self.save_hdf = False
        self.progress_bar = True
        self._fit_resonator = False


    def set_x_parameters(self, x_vec, x_coordname, x_instrument, x_unit = ""):
        '''
        Sets parameters for sweep. In a 2D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to exectute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_instrument
        self.delete_fit_function()
        self.x_unit = x_unit

    def set_y_parameters(self, y_vec, y_coordname, y_instrument, y_unit = ""):
        '''
        Sets parameters for sweep. In a 2D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to exectute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_instrument
        self.delete_fit_function()
        self.y_unit = y_unit

    def gen_fit_function(self, curve_f, curve_p, units = '', p0 = [-1,0.1,7]):
        '''
        curve_f: 'parab', 'hyp', specifies the fit function to be employed
        curve_p: set of points that are the basis for the fit in the format [[x1,x2,x3,...],[y1,y2,y3,...]], frequencies in Hz
        units: set this to 'Hz' in order to avoid large values that cause the fit routine to diverge
        p0 (optional): start parameters for the fit, must be an 1D array of length 3 ([a,b,c])

        adds a trace to landscape
        '''

        if not self.landscape:
            self.landscape = []

        x_fit = curve_p[0]
        if units == 'Hz':
            y_fit = np.array(curve_p[1])*1e-9
        else:
            y_fit = np.array(curve_p[1])

        try:
            if curve_f == 'parab':
                popt, pcov = curve_fit(self.f_parab, x_fit, y_fit, p0=p0)
                if units == 'Hz':
                    self.landscape.append(1e9*self.f_parab(self.x_vec, *popt))
                else:
                    self.landscape.append(self.f_parab(self.x_vec, *popt))
            elif curve_f == 'hyp':
                popt, pcov = curve_fit(self.f_hyp, x_fit, y_fit, p0=p0)
                if units == 'Hz':
                    self.landscape.append(1e9*self.f_hyp(self.x_vec, *popt))
                else:
                    self.landscape.append(self.f_hyp(self.x_vec, *popt))
            else:
                print 'function type not known...aborting'
                raise ValueError
        except Exception as message:
            print 'fit not successful:', message
            popt = p0

    def delete_fit_function(self, n = None):
        '''
        delete single fit function n (with 0 being the first one generated) or the complete landscape for n not specified
        '''

        if n:
            self.landscape = np.delete(self.landscape, n, axis=0)
        else:
            self.landscape = None


    def plot_fit_function(self, num_points = 100):
        '''
        try:
            x_coords = np.linspace(self.x_vec[0], self.x_vec[-1], num_points)
        except Exception as message:
            print 'no x axis information specified', message
            return
        '''
        if self.landscape:
            for trace in self.landscape:
                try:
                    #plt.clear()
                    plt.plot(self.x_vec, trace)
                    plt.fill_between(self.x_vec, trace+float(self.span)/2, trace-float(self.span)/2, alpha=0.5)
                except Exception:
                    print 'invalid trace...skip'
            plt.axhspan(self.y_vec[0], self.y_vec[-1], facecolor='0.5', alpha=0.5)
            plt.show()
        else:
            print 'No trace generated.'

    def measure_1D(self):
        '''
        measure central point of awg window while sweeping one parameter x
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = True
        self._scan_1D2 = False
        self._scan_2D = False
        self.data_complex = False

        if self.dirname == None:
            self.dirname = self.x_coordname.replace()
        self._file_name = '1D_' + self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self._p = Progress_Bar(len(self.x_vec),self.dirname)

        self._prepare_measurement_vna()
        if self.save_dat:
            self._prepare_measurement_dat_file()
        if self.save_hdf:
            self._prepare_measurement_hdf_file()
            """opens qviewkit to plot measurement, amp and pha are opened by default"""
            qviewkit.plot(self._data_hdf.get_filepath(), datasets=['amplitude', 'phase'])
            if self._fit_resonator:
                self._resonator = resonator(self._data_hdf)

        self._measure()
        self._end_measurement()


    def measure_1D2(self):
        '''
        measure full window of vna while sweeping x_set_obj with parameters x_vec
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_1D2 = True
        self._scan_2D = False
        self.data_complex = False

        if self.dirname == None:
            self.dirname = self.x_coordname.replace()
        self._file_name = '1D2_' + self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self._p = Progress_Bar(len(self.x_vec),self.dirname)

        self._prepare_measurement_vna()
        if self.save_dat:
            self._prepare_measurement_dat_file()
        if self.save_hdf:
            self._prepare_measurement_hdf_file()
            """opens qviewkit to plot measurement, amp and pha are opened by default"""
            qviewkit.plot(self._data_hdf.get_filepath(), datasets=['amplitude', 'phase'])
            if self._fit_resonator:
                self._resonator = resonator(self._data_hdf)

        self._measure()
        self._end_measurement()


    def measure_2D(self):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_1D2 = False
        self._scan_2D = True
        self.data_complex = False

        if self.dirname == None:
            self.dirname = self.x_coordname.replace() + '_' + self.y_coordname.replace()
        self._file_name = '2D_' + self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec),self.dirname)

        self._prepare_measurement_vna()
        if self.save_dat:
            self._prepare_measurement_dat_file()
        if self.save_hdf:
            self._prepare_measurement_hdf_file()
            if self._fit_resonator:
                self._resonator = resonator(self._data_hdf)

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []   #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()
        self._end_measurement()

    def set_fit(self,fit_resonator=True,fit_function='',f_min=None,f_max=None):
        '''
        sets fit parameter for resonator

        fit_resonator (bool): True or False, default: True (optional)
        fit_function (string): function which will be fitted to the data (optional)
        f_min (float): lower frequency boundary for the fitting function, default: None (optional)
        f_max (float): upper frequency boundary for the fitting function, default: None (optional)
        '''
        if not fit_resonator:
            self._fit_resonator = False
            return
        self._functions = {'lorentzian':0,'skewed_lorentzian':1,'circle_fit':2,'fano':3,'all_fits':4}
        try:
            self._fit_function = self._functions[fit_function]
        except KeyError:
            logging.error('Fit function not properly set. Must be either \'lorentzian\', \'skewed_lorentzian\', \'circle_fit\', \'fano\', or \'all_fits\'.')
        else:
            self._fit_resonator = True
            self._f_min = f_min
            self._f_max = f_max

    def _do_fit_resonator(self):
        '''
        calls fit function in resonator class
        fit function is specified in self.set_fit, with boundaries f_mim and f_max
        only the last 'slice' of data is fitted, since we fit live while measuring.
        '''

        if self._fit_function == self._function['lorentzian']:
            self._resonator.fit_lorentzian(f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == self._function['skewed_lorentzian']:
            self._resonator.fit_skewed_lorentzian(f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == self._function['circle']:
            self._resonator.fit_circle(f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == self._function['fano']:
            self._resonator.fit_fano(f_min=self._f_min, f_max = self._f_max)
        #if self._fit_function == self._function['all_fits']:
            #self._resonator.fit_all_fits(f_min=self._f_min, f_max = self._f_max)

    def _prepare_measurement_vna(self):
        '''
        all the relevant settings from the vna are updated and called
        '''

        self.vna.get_all()
        #ttip.get_temperature()
        self._nop = self.vna.get_nop()
        self._sweeptime_averages = self.vna.get_sweeptime_averages()
        self._freqpoints = self.vna.get_freqpoints()

    def _prepare_measurement_dat_file(self):
        '''
        creates the output .dat-file with distict structure for each meaurement type.
        '''

        self._data_dat = qt.Data(name=self._file_name)
        if self.comment:
            self._data_dat.add_comment(self.comment)
        self._data_dat.add_coordinate(self.x_coordname + ' '+self.x_unit)
        if self._scan_1D2:
            self._data_dat.add_coordinate('Frequency (Hz)')
            self._data_dat.add_value('Amplitude (V)')
            self._data_dat.add_value('Phase (pi)')
            if self.data_complex:
                self._data_dat.add_value('Real')
                self._data_dat.add_value('Img')
        else:
            if self._scan_2D:
                self._data_dat.add_coordinate(self.y_coordname + ' ' +self.y_unit)
            for i in range(1,self._nop+1):
                self._data_dat.add_value(('Point %i Amp' %i))
            for i in range(1,self._nop+1):
                self._data_dat.add_value(('Point %i Pha' %i))

        self._data_dat.create_file()

    def _prepare_measurement_hdf_file(self):
        '''
        creates the output .h5-file with distinct dataset structures for each measurement type.
        the filename is borrowed from the .dat-file to put them into the same folder.
        at this point all measurement parameters are known and put in the output file
        '''
        if self.save_dat:
            filename = str(self._data_dat.get_filepath()).replace('.dat','.h5')
        else:
            filename = str(self._file_name) + '.h5'
        self._data_hdf = hdf.Data(name=self._file_name, path=filename)
        self._hdf_freq = self._data_hdf.add_coordinate('frequency', unit = 'Hz')
        self._hdf_freq.add(self._freqpoints)
        self._hdf_x = self._data_hdf.add_coordinate(self.x_coordname, unit = self.x_unit)
        self._hdf_x.add(self.x_vec)
        self._hdf_real = self._data_hdf.add_value_vector('real', x = self._hdf_freq, unit = '')
        self._hdf_imag = self._data_hdf.add_value_vector('imag', x = self._hdf_freq, unit = '')
        if self._scan_2D:
            self._hdf_y = self._data_hdf.add_coordinate(self.y_coordname, unit = self.y_unit)
            self._hdf_y.add(self.y_vec)
            self._hdf_amp = self._data_hdf.add_value_box('amplitudes', x = self._hdf_x, y = self._hdf_y, z = self._hdf_freq, unit = 'a.u.')
            self._hdf_pha = self._data_hdf.add_value_box('phases', x = self._hdf_x, y = self._hdf_y, z = self._hdf_freq, unit = 'rad')
        else:
            self._hdf_amp = self._data_hdf.add_value_matrix('amplitude', x = self._hdf_x, y = self._hdf_freq, unit = 'a.u.')
            self._hdf_pha = self._data_hdf.add_value_matrix('phase', x = self._hdf_x, y = self._hdf_freq, unit='rad')
        if self.comment:
            self._data_hdf.add_comment(self.comment)

    def _measure(self):
        '''
        measures and plots the data depending on the measurement type.
        the measurement loops feature the setting of the objects and saving the data in the
        .dat and/or .h5 files.
        '''
        qt.mstart()
        if not self.save_hdf or self._scan_2D:
            '''
            we use our own qviewkit for liveplotting the data. plotting a 2D scan is
            not yet implemented.
            '''
            if self.plotlive:
                self._plot_dat_file()

        try:
            """
            loop: x_obj with data from x_vec
            """
            for i, x in enumerate(self.x_vec):
                self.x_set_obj(x)
                sleep(self.tdx)
                dat=[]

                if self._scan_2D:
                    for y in self.y_vec:
                        """
                        loop: x_obj with data from x_vec (only 2D measurement)
                        """
                        if (np.min(np.abs(self.center_freqs[i]-y*np.ones(len(self.center_freqs[i])))) > self.span/2.) and self.landscape:   #if point is not of interest (not close to one of the functions)
                            data_amp = np.zeros(int(self._nop))
                            data_pha = np.zeros(int(self._nop))   #fill with zeros
                        else:
                            self.y_set_obj(y)
                            sleep(self.tdy)
                            self.vna.avg_clear()
                            sleep(self._sweeptime_averages)
                            """ measurement """
                            data_amp, data_pha = self.vna.get_tracedata()
                        if self.save_dat:
                            dat = np.append(x, y)
                            dat = np.append(dat,data_amp)
                            dat = np.append(dat,data_pha)
                            self._data_dat.add_data_point(*dat)
                            self._data_dat.new_block()
                        if self.save_hdf:
                            self._hdf_amp.append(data_amp)
                            self._hdf_pha.append(data_pha)
                            if self._fit_resonator:
                                self._do_fit_resonator()

                        if self.plotlive and not self.save_hdf:
                            qt.msleep(0.1)
                            self._plot_amp.update()
                            self._plot_pha.update()
                        if self.progress_bar:
                            self._p.iterate()

                if self._scan_1D:
                    self.vna.avg_clear()
                    sleep(self._sweeptime_averages)
                    """ measurement """
                    data_amp, data_pha = self.vna.get_tracedata()
                    if self.save_dat:
                        dat = np.append(x, data_amp)
                        dat = np.append(dat, data_pha)
                        self._data_dat.add_data_point(*dat)
                    if self.save_hdf:
                        self._hdf_amp.append(data_amp)
                        self._hdf_pha.append(data_pha)
                        if self._fit_resonator:
                            self._do_fit_resonator()
                    if self.progress_bar:
                        self._p.iterate()

                if self._scan_1D2:
                    self.vna.avg_clear()
                    sleep(self._sweeptime_averages)
                    """ measurement """
                    data_amp, data_pha = self.vna.get_tracedata()
                    if self.save_dat:
                        dat = np.append([x*np.ones(self._nop)],[self._freqpoints], axis = 0)
                        dat = np.append(dat,[data_amp],axis = 0)
                        dat = np.append(dat,[data_pha],axis = 0)
                        self._data_dat.add_data_point(*dat)
                        self._data_dat.new_block()
                    if self.save_hdf:
                        self._hdf_amp.append(data_amp)
                        self._hdf_pha.append(data_pha)
                        if self._fit_resonator:
                            self._do_fit_resonator()
                    if self.progress_bar:
                        self._p.iterate()

                if not self.save_hdf and self.plotlive:
                    qt.msleep(0.1)
                    self._plot_amp.update()
                    self._plot_pha.update()

        finally:
            if self.save_dat:
                if not self.plotlive:
                    self._plot_dat_file()
                    self._plot_amp.update()
                    self._plot_pha.update()

                self._plot_amp.save_png()
                self._plot_amp.save_gp()
                self._plot_pha.save_png()
                self._plot_pha.save_gp()

            qt.mend()

    def _end_measurement(self):
        '''
        the data files are closed and their filepaths are printed
        '''
        if self.save_dat:
            print self._data_dat.get_filepath()
            self._data_dat.close_file()
        if self.save_hdf:
            print self._data_hdf.get_filepath()
            qviewkit.save_plots(self._data_hdf.get_filepath())
            self._data_hdf.close_file()

    def _plot_dat_file(self):
        '''
        plots measured data in gnuplot:
        1D: amp/pha vs x_vec (1D plot for middle freqpoint)
        1D2: freq vs x_vec (color plot with amp/pha trace color coded)
        2D: x_vec vs y_vec (color plot with amp/pha of middle freqpoint color coded)
        '''
        if self._scan_1D:
            self._plot_amp = qt.Plot2D(self._data_dat, name='Amplitude', coorddim=0, valdim=int(self._nop/2)+1)
            self._plot_pha = qt.Plot2D(self._data_dat, name='Phase', coorddim=0, valdim=self._nop+int(self._nop/2)+1)
        if self._scan_1D2:
            self._plot_amp = qt.Plot3D(self._data_dat, name='Amplitude 1D2', coorddims=(0,1), valdim=2, style=qt.Plot3D.STYLE_IMAGE)
            self._plot_amp.set_palette('bluewhitered')
            self._plot_pha = qt.Plot3D(self._data_dat, name='Phase 1D2', coorddims=(0,1), valdim=3, style=qt.Plot3D.STYLE_IMAGE)
            self._plot_pha.set_palette('bluewhitered')
        if self._scan_2D:
            if self.plot3D:
                self._plot_amp = qt.Plot3D(self._data_dat, name='Amplitude', coorddims=(0,1), valdim=int(self._nop/2)+2, style=qt.Plot3D.STYLE_IMAGE)
                self._plot_amp.set_palette('bluewhitered')
                self._plot_pha = qt.Plot3D(self._data_dat, name='Phase', coorddims=(0,1), valdim=int(self._nop/2)+2+self._nop, style=qt.Plot3D.STYLE_IMAGE)
                self._plot_pha.set_palette('bluewhitered')
            else:
                self._plot_amp = qt.Plot2D(self._data_dat, name='Amplitude', coorddim=1, valdim=int(self._nop/2)+2)
                self._plot_pha = qt.Plot2D(self._data_dat, name='Phase', coorddim=1, valdim=int(self._nop/2)+2+self._nop)

    def record_trace(self):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA

        returns frequency points, data_amp and data_pha when self.return_dat is set
        '''
        qt.mstart()
        self._prepare_measurement_vna()
        self.vna.hold(0)   #switch VNA to continuous mode

        print 'recording trace...'
        sys.stdout.flush()

        #use 1D2 functions
        self._scan_1D = False
        self._scan_1D2 = True
        self._scan_2D = False
        self.data_complex = True

        #creating data object
        self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_dat_file()

        p = Progress_Bar(self.vna.get_averages(),self.dirname)
        self.vna.avg_clear()
        if self.vna.get_averages() == 1 or self.vna.get_Average == False:   #no averaging
            qt.msleep(self.vna.get_sweeptime())   #wait single sweep
        else:
            p = Progress_Bar(self.vna.get_averages(),self.dirname)
            for a in range(self.vna.get_averages()):
                qt.msleep(self.vna.get_sweeptime())   #wait single sweep time
                p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        if self.save_dat:
            for i in np.arange(self._nop):
                self._data_dat.add_data_point(self._freqpoints[i], data_amp[i], data_pha[i], data_real[i], data_imag[i])
        if self.save_hdf:
            self._hdf_amp.append(data_amp)
            self._hdf_pha.append(data_pha)
            self._hdf_real.append(data_real)
            self._hdf_imag.append(data_imag)
            if self._fit_resonator:
                self._do_fit_resonator()

        plot_amp = qt.Plot2D(self._data.dat, name='amplitude', clear=True, needtempfile=True, autoupdate=True, coorddim=0, valdim=1)
        plot_pha = qt.Plot2D(self._data.dat, name='phase', clear=True, needtempfile=True, autoupdate=True, coorddim=0, valdim=2)
        plot_complex = qt.Plot2D(self._data.dat, name='Complex Plane', clear=True, needtempfile=True, autoupdate=True, coorddim=3, valdim=4)

        plot_amp.save_png()
        plot_amp.save_gp()
        plot_pha.save_png()
        plot_pha.save_gp()
        plot_complex.save_png()
        plot_complex.save_png()

        self._data.dat.close_file()
        qt.mend()
        #print 'Done.'
        if self.return_dat: return self._freqpoints, data_amp, data_pha

    def set_span(self, span):
        self.span = span

    def get_span(self):
        return self.span

    def set_tdx(self, tdx):
        self.tdx = tdx

    def set_tdy(self, tdy):
        self.tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def f_parab(self,x,a,b,c):
        return a*(x-b)**2+c

    def f_hyp(self,x,a,b,c):
        return a*np.sqrt((x/b)**2+c)
Exemple #33
0
class transport(object):
    '''
    useage:
    
    m = transport(daq = 'DAQ')
    
    m.set_voltage_bias('True')
    m.set_measurement_setup_parameters(conversion_IV = 1e7, V_amp=1, I_div=1, V_divider=1000)
    m.set_measurement_parameters(start=-100e-6, stop=100e-7, sample_count=1000, sample_rate=200, sweeps = 3)
    m.set_x_parameters(arange(0.,1.5,0.05),'magnetic coil current', yoko.set_current, 'A')
    #m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency', mw_src.set_frequency, 'Hz')
    #sweep-parameter only active for x.measure_IV()!!
    m.measure_IV_2D()
    '''
    def __init__(self, daq, exp_name=''):

        self.daq = daq
        self.exp_name = exp_name

        self._chan_out = self.daq._ins._get_output_channels()[0]
        self._chan_in = self.daq._ins._get_input_channels()[0]

        self._tdx = 0.002
        self._tdy = 0.002

        self.comment = ''

        self._voltage_bias = False
        self._current_bias = True

        self._voltage_offset = 0.
        self._current_offset = 0.

    def set_x_parameters(self, x_vec, x_coordname, x_instrument, x_unit):
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_instrument
        self.x_unit = x_unit
        self._set_x_parameters = True

    def set_y_parameters(self, y_vec, y_coordname, y_instrument, y_unit):
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_instrument
        self.y_unit = y_unit
        self._set_y_parameters = True

    def set_measurement_setup_parameters(self, conversion_IV, V_amp, I_div,
                                         V_divider):
        self._conversion_IV = conversion_IV
        self._V_amp = V_amp
        self._I_div = I_div
        self._V_divider = V_divider
        self._set_measurement_setup_parameters = True

    def set_measurement_parameters(self,
                                   start,
                                   stop,
                                   sample_count,
                                   sample_rate,
                                   sweeps=1):
        self._start = start
        self._stop = stop
        self._sample_count = sample_count
        self._sample_rate = sample_rate
        self._sweeps = sweeps
        self._vec_fw = np.linspace(start, stop, sample_count)
        self._vec_bw = np.linspace(stop, start, sample_count)
        self._set_measurement_parameters = True

    def _check_measurement(self):
        if self._voltage_bias == self._current_bias:
            logging.error(
                'Please specify current- or voltage-bias, both are %s...aborting'
                % (str(self._voltage_bias)))
            return False
        if not self._set_measurement_setup_parameters:
            logging.error('Please set_measurement_setup_parameters...aborting')
            return False
        if not self._set_measurement_parameters:
            logging.error('Please set_measurement_parameters...aborting')
            return False
        if self._measure_IV_2D or self._measure_IV_3D and not self._set_x_parameters:
            logging.error('Please set_x_parameters...aborting')
            return False
        if self._measure_IV_3D and not self._set_y_parameters:
            logging.error('Please set_y_parameters...aborting')
            return False
        return True

    def _save_settings(self):
        settings = "## Settings for measurement " + self._scan_name + ' ##\n'
        settings += "A per V = %f\nV_amp = %f\nI_div = %f\nV_div = %f\nsamples = %f\nrate = %f\nsweeps = %f\n" % (
            float(self._conversion_factor), float(self._V_amp),
            float(self._I_div), float(self._V_div), float(self._sample_count),
            float(self._sample_rate), float(self._sweeps))
        settings += 'Voltage bias = %s, Current bias = %s\n' % (str(
            self._voltage_bias), str(self._current_bias))
        settings += "Min = %f \nMax = %f \n" % (self._start, self._stop)
        if not self._measure_IV:
            settings += "%s, %f-%f %s, step = %f\n" % (
                self.x_instrument, self.x_vec[0],
                self.x_vec[len(self.x_vec) - 1],
                (self.x_vec[len(self.x_vec) - 1] - self.x_vec[0]) /
                (len(self.x_vec) - 1))
        if self._measure_IV_3D:
            settings += "%s, %f-%f %s, step = %f\n" % (
                self.y_instrument, self.y_vec[0],
                self.y_vec[len(self.y_vec) - 1],
                (self.y_vec[len(self.y_vec) - 1] - self.y_vec[0]) /
                (len(self.y_vec) - 1))
        settings += "Current offset %f A\n" % (self._current_offset)
        settings += "Voltage offset %f V\n" % (self._voltage_offset)
        self._data.add_comment(settings)

    def measure_IV(self):
        self._measure_IV_1D = True
        self._measure_IV_2D = False
        self._measure_IV_3D = False
        if not self._check_measurement:
            return

        self._scan_name = 'IV'
        if self.exp_name:
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(self._sweeps)

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.get_filepath()

        self._measure()
        self._end_measurement()

    def measure_IV_2D(self):
        self._measure_IV_1D = False
        self._measure_IV_2D = True
        self._measure_IV_3D = False
        if not self._check_measurement:
            return

        self._scan_name = 'IV_vs_' + self.x_coordname
        if self.exp_name:
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(len(self.x_vec))

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.get_filepath())

        self._measure()
        self._end_measurement()

    def measure_IV_3D(self):
        self._measure_IV_1D = False
        self._measure_IV_2D = False
        self._measure_IV_3D = True
        if not self._check_measurement:
            return

        self._scan_name = 'IV_vs_' + self.x_coordname + '_' + self.y_coordname
        if self.exp_name:
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(len(self.x_vec) * len(self.y_vec))

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.filepath())

        self._measure()
        self._end_measurement()

    def _prepare_measurement_file(self):
        self._data = hdf.Data(name=self._scan_name)

        if self._voltage_bias:
            bias_name = 'Voltage'
            bias_unit = 'V'
            measurement_name = 'Current'
            measurement_unit = 'A'
        if self._current_bias:
            bias_name = 'Current'
            bias_unit = 'A'
            measurement_name = 'Voltage'
            measurement_unit = 'V'

        self._data_bias = self._data.add_coordinate(bias_name, unit=bias_unit)
        bias_vec = np.append(self._vec_fw, self._vec_bw)
        self._data_bias.add(bias_vec)

        if self._measure_IV_1D:
            if self._sweeps == 1:
                self._data_measure = self._data.add_value_vector(
                    measurement_name, x=self._hdf_bias, unit=measurement_unit)
            else:
                self._data_sweep = self._data.add_coordinate('sweep')
                self._data_sweep.add([sweep for sweep in self._sweeps])
                self._data_measure = self._data.add_value_matrix(
                    measurement_name,
                    x=self._data_sweep,
                    y=self._hdf_bias,
                    unit=measurement_unit)
        if self._measure_IV_2D:
            self._data_x = self._dat.add_coordinate(self.x_coordname,
                                                    unit=self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_measure = self._data.add_value_matrix(
                measurement_name,
                x=self._x,
                y=self._hdf_bias,
                unit=measurement_unit)

        if self._measure_IV_3D:
            self._data_x = self._data.add_coordinate(self.x_coordname,
                                                     unit=self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_y = self._data.add_coordinate(self.y_coordname,
                                                     unit=self.y_unit)
            self._data_y.add(self.y_vec)
            self._data_measure = self._data.add_value_box(
                measurement_name,
                x=self._data_x,
                y=self._data_y,
                z=self._hdf_bias,
                unit=measurement_unit)

        if self.comment:
            self._data.add_comment(self.comment)

    def _measure(self):
        qt.mstart()
        plt.gca().set_xlabel("V [uV]")
        plt.gca().set_ylabel("I [nA]")
        try:
            if self._measure_IV_1D:
                for self._sweep in np.arange(self._sweeps):
                    if self._current_bias:
                        self._take_IV(
                            out_conversion_factor=self._conversion_IV,
                            in_amplification=self._V_amp,
                            out_divider=self._V_divider)
                    if self._voltage_bias:
                        self._take_IV(out_conversion_factor=1,
                                      in_amplification=self._conversion_IV,
                                      out_divider=self._V_divider)
                    self._p_iterate()

            if self._measure_IV_2D or self._measure_IV_3D:
                for self._x in self.x_vec:
                    self.x_set_obj(self._x)
                    sleep(self._tdx)

                    if self._measure_IV_2D:
                        if self._current_bias:
                            self._take_IV(
                                out_conversion_factor=self._conversion_IV,
                                in_amplification=self._V_amp,
                                out_divider=self._V_divider)
                        if self._voltage_bias:
                            self._take_IV(out_conversion_factor=1,
                                          in_amplification=self._conversion_IV,
                                          out_divider=self._V_divider)
                        self._p.iterate()

                    if self._measure_IV_3D:
                        for self._y in self.y_vec:
                            self.y_set_obj(self._y)
                            sleep(self._tdy)
                            if self._current_bias:
                                self._take_IV(
                                    out_conversion_factor=self._conversion_IV,
                                    in_amplification=self._V_amp,
                                    out_divider=self._V_divider)
                            if self._voltage_bias:
                                self._take_IV(
                                    out_conversion_factor=1,
                                    in_amplification=self._conversion_IV,
                                    out_divider=self._V_divider)
                            self._p.iterate()

        finally:
            self.daq.set_ao1(0)
            qt.mend()

    def _end_measurement(self):
        print self._data.get_filepath()
        self._data.close_file()

    def _take_IV(self, out_conversion_factor, in_amplification, out_divider=1):
        """ IV measurement with current or voltage (vec_fw, vec_bw)!"""
        data_IV = self.daq.sync_output_input(self._chan_out,
                                             self._chan_in,
                                             self._vec_fw * out_divider /
                                             out_conversion_factor,
                                             rate=self._sample_rate)
        if self._current_bias:
            self._pl1 = plt.plot((data_IV / in_amplification) * 1e6,
                                 self._vec_fw * 1e6, "o")
        else:
            self._pl1 = plt.plot(self._vec_fw * 1e6,
                                 (data_IV / in_amplification) * 1e9, "-")
        qt.msleep(0.1)

        data_measure = []
        data_measure = np.append(data_measure, data_IV / in_amplification)

        data_IV = self.daq.sync_output_input(self._chan_out,
                                             self._chan_in,
                                             self._vec_bw * out_divider /
                                             out_conversion_factor,
                                             rate=self._sample_rate)
        if self._current_bias:
            self._pl1 = plt.plot((data_IV / in_amplification) * 1e6,
                                 self._vec_fw * 1e6, "o")
        else:
            self._pl1 = plt.plot(self._vec_fw * 1e6,
                                 (data_IV / in_amplification) * 1e9, "-")
        qt.msleep(0.1)

        data_measure = np.append(data_measure, data_IV / in_amplification)
        self._data_measure.append(data_measure)

    def set_tdx(self, tdx):
        self._tdx = tdx

    def set_tdy(self, tdy):
        self._tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def set_voltage_bias(self, voltage_bias):
        self._voltage_bias = voltage_bias
        self._current_bias = not voltage_bias

    def get_voltage_bias(self):
        return self._voltage_bias

    def set_current_bias(self, current_bias):
        self._current_bias = current_bias
        self._voltage_bias = not current_bias

    def get_current_bias(self):
        return self._current_bias

    def set_voltage_offset(self, voltage_offset):
        self._voltage_offset = voltage_offset

    def set_current_offset(self, voltage_offset):
        self._current_offset = voltage_offset

    def get_voltage_offset(self):
        return self._voltgae_offset

    def get_current_offset(self):
        return self._current_offset
Exemple #34
0
    def record_trace(self):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA

        returns frequency points, data_amp and data_pha when self.return_dat is set
        '''
        qt.mstart()
        self._prepare_measurement_vna()
        self.vna.hold(0)   #switch VNA to continuous mode

        print 'recording trace...'
        sys.stdout.flush()

        #use 1D2 functions
        self._scan_1D = False
        self._scan_1D2 = True
        self._scan_2D = False
        self.data_complex = True

        #creating data object
        self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_dat_file()

        p = Progress_Bar(self.vna.get_averages(),self.dirname)
        self.vna.avg_clear()
        if self.vna.get_averages() == 1 or self.vna.get_Average == False:   #no averaging
            qt.msleep(self.vna.get_sweeptime())   #wait single sweep
        else:
            p = Progress_Bar(self.vna.get_averages(),self.dirname)
            for a in range(self.vna.get_averages()):
                qt.msleep(self.vna.get_sweeptime())   #wait single sweep time
                p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        if self.save_dat:
            for i in np.arange(self._nop):
                self._data_dat.add_data_point(self._freqpoints[i], data_amp[i], data_pha[i], data_real[i], data_imag[i])
        if self.save_hdf:
            self._hdf_amp.append(data_amp)
            self._hdf_pha.append(data_pha)
            self._hdf_real.append(data_real)
            self._hdf_imag.append(data_imag)
            if self._fit_resonator:
                self._do_fit_resonator()

        plot_amp = qt.Plot2D(self._data.dat, name='amplitude', clear=True, needtempfile=True, autoupdate=True, coorddim=0, valdim=1)
        plot_pha = qt.Plot2D(self._data.dat, name='phase', clear=True, needtempfile=True, autoupdate=True, coorddim=0, valdim=2)
        plot_complex = qt.Plot2D(self._data.dat, name='Complex Plane', clear=True, needtempfile=True, autoupdate=True, coorddim=3, valdim=4)

        plot_amp.save_png()
        plot_amp.save_gp()
        plot_pha.save_png()
        plot_pha.save_gp()
        plot_complex.save_png()
        plot_complex.save_png()

        self._data.dat.close_file()
        qt.mend()
        #print 'Done.'
        if self.return_dat: return self._freqpoints, data_amp, data_pha
Exemple #35
0
class spectrum(object):
    '''
    usage:

    m = spectrum(vna = vna1)

    m.set_x_parameters(arange(-0.05,0.05,0.01),'flux coil current',coil.set_current, unit = 'mA')
    m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency',mw_src1.set_frequency, unit = 'Hz')

    m.gen_fit_function(...)      several times

    m.measure_XX()
    '''

    def __init__(self, vna, exp_name = '', sample = None):

        self.vna = vna
        self.averaging_start_ready = "start_measurement" in self.vna.get_function_names() and "ready" in self.vna.get_function_names()
        if not self.averaging_start_ready: logging.warning(__name__ + ': With your VNA instrument driver (' + self.vna.get_type() + '), I can not see when a measurement is complete. So I only wait for a specific time and hope the VNA has finished. Please consider implemeting the necessary functions into your driver.')
        self.exp_name = exp_name
        self._sample = sample

        self.landscape = None
        self.span = 200e6    #[Hz]
        self.tdx = 0.002   #[s]
        self.tdy = 0.002   #[s]

        self.comment = ''
        self.dirname = None

        self.x_set_obj = None
        self.y_set_obj = None

        self.progress_bar = True
        self._fit_resonator = False
        self._plot_comment=""

        self.set_log_function()
        
        self.open_qviewkit = True
        self.qviewkit_singleInstance = False
        
        self._measurement_object = Measurement()
        self._measurement_object.measurement_type = 'spectroscopy'
        self._measurement_object.sample = self._sample
        
        self._qvk_process = False
        
        self.number_of_timetraces = 1   #relevant in time domain mode
        
        

    def set_log_function(self, func=None, name = None, unit = None, log_dtype = None):
        '''
        A function (object) can be passed to the measurement loop which is excecuted before every x iteration 
        but after executing the x_object setter in 2D measurements and before every line (but after setting 
        the x value) in 3D measurements.
        The return value of the function of type float or similar is stored in a value vector in the h5 file.

        Call without any arguments to delete all log functions. The timestamp is automatically saved.

        func: function object in list form
        name: name of logging parameter appearing in h5 file, default: 'log_param'
        unit: unit of logging parameter, default: ''
        log_dtype: h5 data type, default: 'f' (float32)
        '''

        if name == None:
            try:
                name = ['log_param']*len(func)
            except Exception:
                name = None
        if unit == None:
            try:
                unit = ['']*len(func)
            except Exception:
                unit = None
        if log_dtype == None:
            try:
                log_dtype = ['f']*len(func)
            except Exception:
                log_dtype = None

        self.log_function = []
        self.log_name = []
        self.log_unit = []
        self.log_dtype = []

        if func != None:
            for i,f in enumerate(func):
                self.log_function.append(f)
                self.log_name.append(name[i])
                self.log_unit.append(unit[i])
                self.log_dtype.append(log_dtype[i])

    def set_x_parameters(self, x_vec, x_coordname, x_set_obj, x_unit = ""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_set_obj
        self.delete_fit_function()
        self.x_unit = x_unit

    def set_y_parameters(self, y_vec, y_coordname, y_set_obj, y_unit = ""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        y_vec (array): contains the sweeping values
        y_coordname (string)
        y_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        y_unit (string): optional
        '''
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_set_obj
        self.delete_fit_function()
        self.y_unit = y_unit

    def gen_fit_function(self, curve_f, curve_p, units = '', p0 = [-1,0.1,7]):
        '''
        curve_f: 'parab', 'hyp', specifies the fit function to be employed
        curve_p: set of points that are the basis for the fit in the format [[x1,x2,x3,...],[y1,y2,y3,...]], frequencies in Hz
        units: set this to 'Hz' in order to avoid large values that cause the fit routine to diverge
        p0 (optional): start parameters for the fit, must be an 1D array of length 3 ([a,b,c,d]), 
           where for the parabula p0[3] will be ignored 
        The parabolic function takes the form  y = a*(x-b)**2 + c , where (a,b,c) = p0
        The hyperbolic function takes the form y = sqrt[ a*(x-b)**2 + c ], where (a,b,c) = p0
        
        adds a trace to landscape
        '''

        if not self.landscape:
            self.landscape = []

        x_fit = curve_p[0]
        if units == 'Hz':
            y_fit = np.array(curve_p[1])*1e-9
        else:
            y_fit = np.array(curve_p[1])

        try:
            if curve_f == 'parab':
                "remove the last item"
                #p0.pop()
                popt, pcov = curve_fit(self.f_parab, x_fit, y_fit, p0=p0)
                if units == 'Hz':
                    self.landscape.append(1e9*self.f_parab(self.x_vec, *popt))
                else:
                    self.landscape.append(self.f_parab(self.x_vec, *popt))
            elif curve_f == 'hyp':
                popt, pcov = curve_fit(self.f_hyp, x_fit, y_fit, p0=p0)
                print popt
                if units == 'Hz':
                    self.landscape.append(1e9*self.f_hyp(self.x_vec, *popt))
                else:
                    self.landscape.append(self.f_hyp(self.x_vec, *popt))
            else:
                print 'function type not known...aborting'
                raise ValueError
        except Exception as message:
            print 'fit not successful:', message
            popt = p0

    def _prepare_measurement_vna(self):
        '''
        all the relevant settings from the vna are updated and called
        '''

        self.vna.get_all()
        #ttip.get_temperature()
        self._nop = self.vna.get_nop()
        self._sweeptime_averages = self.vna.get_sweeptime_averages()
        self._freqpoints = self.vna.get_freqpoints()

        if self.averaging_start_ready: self.vna.pre_measurement()

    def _prepare_measurement_file(self):
        '''
        creates the output .h5-file with distinct dataset structures for each measurement type.
        at this point all measurement parameters are known and put in the output file
        '''

        self._data_file = hdf.Data(name=self._file_name)
        self._measurement_object.uuid = self._data_file._uuid
        self._measurement_object.hdf_relpath = self._data_file._relpath
        self._measurement_object.instruments = qt.instruments.get_instruments()

        self._measurement_object.save()
        self._mo = self._data_file.add_textlist('measurement')
        self._mo.append(self._measurement_object.get_JSON())

        # write logfile and instrument settings
        self._write_settings_dataset()
        self._log = waf.open_log_file(self._data_file.get_filepath())

        if not self._scan_time:
            self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
            self._data_freq.add(self._freqpoints)

        if self._scan_1D:
            self._data_real = self._data_file.add_value_vector('real', x = self._data_freq, unit = '', save_timestamp = True)
            self._data_imag = self._data_file.add_value_vector('imag', x = self._data_freq, unit = '', save_timestamp = True)
            self._data_amp = self._data_file.add_value_vector('amplitude', x = self._data_freq, unit = 'arb. unit', save_timestamp = True)
            self._data_pha = self._data_file.add_value_vector('phase', x = self._data_freq, unit = 'rad', save_timestamp = True)

        if self._scan_2D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_freq, unit = 'arb. unit', save_timestamp = True)
            self._data_pha = self._data_file.add_value_matrix('phase', x = self._data_x, y = self._data_freq, unit='rad', save_timestamp = True)

            if self.log_function != None:   #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(self._data_file.add_value_vector(self.log_name[i], x = self._data_x, unit = self.log_unit[i], dtype=self.log_dtype[i]))

            if self._nop < 10:
                """creates view: plot middle point vs x-parameter, for qubit measurements"""
                self._data_amp_mid = self._data_file.add_value_vector('amplitude_midpoint', unit = 'arb. unit', x = self._data_x, save_timestamp = True)
                self._data_pha_mid = self._data_file.add_value_vector('phase_midpoint', unit = 'rad', x = self._data_x, save_timestamp = True)
                #self._view = self._data_file.add_view("amplitude vs. " + self.x_coordname, x = self._data_x, y = self._data_amp[self._nop/2])

        if self._scan_3D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_y = self._data_file.add_coordinate(self.y_coordname, unit = self.y_unit)
            self._data_y.add(self.y_vec)
            
            if self._nop == 0:   #saving in a 2D matrix instead of a 3D box HR: does not work yet !!! test things before you put them online.
                self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_y,  unit = 'arb. unit',   save_timestamp = False)
                self._data_pha = self._data_file.add_value_matrix('phase',     x = self._data_x, y = self._data_y,  unit = 'rad', save_timestamp = False)
            else:
                self._data_amp = self._data_file.add_value_box('amplitude', x = self._data_x, y = self._data_y, z = self._data_freq, unit = 'arb. unit', save_timestamp = False)
                self._data_pha = self._data_file.add_value_box('phase', x = self._data_x, y = self._data_y, z = self._data_freq, unit = 'rad', save_timestamp = False)
                
            if self.log_function != None:   #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(self._data_file.add_value_vector(self.log_name[i], x = self._data_x, unit = self.log_unit[i], dtype=self.log_dtype[i]))

        if self._scan_time:
            self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
            self._data_freq.add([self.vna.get_centerfreq()])
            
            self._data_time = self._data_file.add_coordinate('time', unit = 's')
            self._data_time.add(np.arange(0,self._nop,1)*self.vna.get_sweeptime()/(self._nop-1))
            
            self._data_x = self._data_file.add_coordinate('trace_number', unit = '')
            self._data_x.add(np.arange(0, self.number_of_timetraces, 1))
            
            self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_time, unit = 'lin. mag.', save_timestamp = False)
            self._data_pha = self._data_file.add_value_matrix('phase', x = self._data_x, y = self._data_time, unit = 'rad.', save_timestamp = False)
                    
        if self.comment:
            self._data_file.add_comment(self.comment)
            
        if self.qviewkit_singleInstance and self.open_qviewkit and self._qvk_process:
            self._qvk_process.terminate() #terminate an old qviewkit instance

    def _write_settings_dataset(self):
        self._settings = self._data_file.add_textlist('settings')
        settings = waf.get_instrument_settings(self._data_file.get_filepath())
        self._settings.append(settings)

    def measure_1D(self, rescan = True, web_visible = True):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started. 
                If False, it will directly take the data from the VNA without waiting.
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath()) 
        print 'recording trace...'
        sys.stdout.flush()

        qt.mstart()
        if rescan:
            if self.averaging_start_ready:
                self.vna.start_measurement()
                ti = time()
                if self.progress_bar: self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
                qt.msleep(.2)
                while not self.vna.ready():
                    if time()-ti > self.vna.get_sweeptime(query=False):
                        if self.progress_bar: self._p.iterate()
                        ti = time()
                    qt.msleep(.2)
                if self.progress_bar:
                    while self._p.progr < self._p.max_it:
                        self._p.iterate()
            else:
                self.vna.avg_clear()
                if self.vna.get_averages() == 1 or self.vna.get_Average() == False:   #no averaging
                    if self.progress_bar:self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                    qt.msleep(self.vna.get_sweeptime())      #wait single sweep
                    if self.progress_bar: self._p.iterate()
                else:   #with averaging
                    if self.progress_bar: self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
                    if "avg_status" in self.vna.get_function_names():
                        for a in range(self.vna.get_averages()):
                            while self.vna.avg_status() <= a:
                                qt.msleep(.2) #maybe one would like to adjust this at a later point
                            if self.progress_bar: self._p.iterate()
                    else: #old style
                        for a in range(self.vna.get_averages()):
                            qt.msleep(self.vna.get_sweeptime())      #wait single sweep time
                            if self.progress_bar: self._p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        self._data_amp.append(data_amp)
        self._data_pha.append(data_pha)
        self._data_real.append(data_real)
        self._data_imag.append(data_imag)
        if self._fit_resonator:
            self._do_fit_resonator()

        qt.mend()
        self._end_measurement()

    def measure_2D(self, web_visible = True):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'frequency'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar: self._p = Progress_Bar(len(self.x_vec),'2D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self._nop < 10:
            if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude_midpoint', 'phase_midpoint'])
        else:
            if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        self._measure()


    def measure_3D(self, web_visible = True):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = True
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_3D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = self.y_coordname
        self._measurement_object.z_axis = 'frequency'
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname + ', ' + self.y_coordname
        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar: self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec),'3D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        """only middle point in freq array is plotted vs x and y"""
        if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []     #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()
        
        
    def measure_timetrace(self, web_visible = True):
        '''
        measure method to record a single VNA timetrace, this only makes sense when span is set to 0 Hz!,
        tested only with KEYSIGHT E5071C ENA and its corresponding qkit driver
        LGruenhaupt 11/2016
        '''
        if self.vna.get_span() > 0: 
            print 'VNA span not set to 0 Hz... aborting'
            return
            
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = True
        
        self._measurement_object.measurement_func = 'measure_timetrace'
        self._measurement_object.x_axis = 'time'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible
        
        if not self.dirname:
            self.dirname = 'VNA_timetrace'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        
        self.x_vec = np.arange(0,self.number_of_timetraces,1)
        
        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        
        if self.progress_bar: self._p = Progress_Bar(self.number_of_timetraces,'VNA timetrace '+self.dirname,self.vna.get_sweeptime_averages())
        
        print 'recording timetrace(s)...'
        sys.stdout.flush()

        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """

            for i, x in enumerate(self.x_vec):
                
                if self.log_function != None:
                    for i,f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))
                        
                if self.averaging_start_ready: #LG 11/2016
                    self.vna.start_measurement()
                    ti = time() #changed from time.time() to time() - LGruenhaupt OCT_2016
                    tp = time() #added to enable use of progress bar
                    #self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime_averages()) moved to line 303
                    
                    ''' This is to prevent the vna.ready() function from timing out. LG NOV/16 '''
                    if self.vna.get_Average():
                        print 'this function only makes sense without averaging'
                        qt.mend()
                        self._end_measuremt()
                    else:
                        #self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                        qt.msleep(self.vna.get_sweeptime())
                        #self._p.iterate()
                        
                        while not self.vna.ready(): qt.msleep(.2) #this is just to check if the measurement has finished
                        
                        data_amp, data_pha = self.vna.get_tracedata()
                        self._data_amp.append(data_amp)
                        self._data_pha.append(data_pha)
                qt.msleep()       
                if self.progress_bar:
                    self._p.iterate()
                
                        
                else: 
                    print 'not implemented for this VNA, only works with Keysight ENA 5071C'
                    qt.mend()
                    self._end_measurement()
                    
        except Exception as e:
            print e.__doc__
            print e.message        
        finally:
            self._end_measurement()
            qt.mend()

    def _measure(self):
        '''
        measures and plots the data depending on the measurement type.
        the measurement loops feature the setting of the objects and saving the data in the .h5 file.
        '''
        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """
            for ix, x in enumerate(self.x_vec):
                self.x_set_obj(x)
                sleep(self.tdx)
                
                if self.log_function != None:
                    for i,f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))

                if self._scan_3D:
                    for y in self.y_vec:
                        """
                        loop: y_obj with parameters from y_vec (only 3D measurement)
                        """
                        if (np.min(np.abs(self.center_freqs[ix]-y*np.ones(len(self.center_freqs[ix])))) > self.span/2.) and self.landscape:    #if point is not of interest (not close to one of the functions)
                            data_amp = np.zeros(int(self._nop))
                            data_pha = np.zeros(int(self._nop))      #fill with zeros
                        else:
                            self.y_set_obj(y)
                            sleep(self.tdy)
                            if self.averaging_start_ready:
                                self.vna.start_measurement()
                                qt.msleep(.2) #just to make sure, the ready command does not *still* show ready
                                while not self.vna.ready():
                                    qt.msleep(.2)
                            else:
                                self.vna.avg_clear()
                                qt.msleep(self._sweeptime_averages)
                                
                            #if "avg_status" in self.vna.get_function_names():
                            #       while self.vna.avg_status() < self.vna.get_averages():
                            #            qt.msleep(.2) #maybe one would like to adjust this at a later point
                            
                            """ measurement """
                            data_amp, data_pha = self.vna.get_tracedata()

                        if self._nop == 0: # this does not work yet.
                           print data_amp[0], data_amp, self._nop
                           self._data_amp.append(data_amp[0])
                           self._data_pha.append(data_pha[0])
                        else:
                           self._data_amp.append(data_amp)
                           self._data_pha.append(data_pha)
                        if self._fit_resonator:
                            self._do_fit_resonator()
                        if self.progress_bar:
                            self._p.iterate()
                        qt.msleep()
                    """
                    filling of value-box is done here.
                    after every y-loop the data is stored the next 2d structure
                    """
                    self._data_amp.next_matrix()
                    self._data_pha.next_matrix()

                if self._scan_2D:
                    if self.averaging_start_ready:
                        self.vna.start_measurement()
                        qt.msleep(.2) #just to make sure, the ready command does not *still* show ready
                        while not self.vna.ready():
                            qt.msleep(.2)
                    else:
                        self.vna.avg_clear()
                        qt.msleep(self._sweeptime_averages)
                    """ measurement """
                    data_amp, data_pha = self.vna.get_tracedata()
                    self._data_amp.append(data_amp)
                    self._data_pha.append(data_pha)
                    if self._nop < 10:
                        #print data_amp[self._nop/2]
                        self._data_amp_mid.append(float(data_amp[self._nop/2]))
                        self._data_pha_mid.append(float(data_pha[self._nop/2]))
                        
                    if self._fit_resonator:
                        self._do_fit_resonator()
                    if self.progress_bar:
                        self._p.iterate()
                    qt.msleep()
        except Exception as e:
            print e.__doc__
            print e.message        
        finally:
            self._end_measurement()
            qt.mend()

    def _end_measurement(self):
        '''
        the data file is closed and filepath is printed
        '''
        print self._data_file.get_filepath()
        #qviewkit.save_plots(self._data_file.get_filepath(),comment=self._plot_comment) #old version where we have to wait for the plots
        t = threading.Thread(target=qviewkit.save_plots,args=[self._data_file.get_filepath(),self._plot_comment])
        t.start()
        self._data_file.close_file()
        waf.close_log_file(self._log)
        self.dirname = None
        if self.averaging_start_ready: self.vna.post_measurement()
        

    def set_resonator_fit(self,fit_resonator=True,fit_function='',f_min=None,f_max=None):
        '''
        sets fit parameter for resonator

        fit_resonator (bool): True or False, default: True (optional)
        fit_function (string): function which will be fitted to the data (optional)
        f_min (float): lower frequency boundary for the fitting function, default: None (optional)
        f_max (float): upper frequency boundary for the fitting function, default: None (optional)
        fit types: 'lorentzian','skewed_lorentzian','circle_fit_reflection', 'circle_fit_notch','fano'
        '''
        if not fit_resonator:
            self._fit_resonator = False
            return
        self._functions = {'lorentzian':0,'skewed_lorentzian':1,'circle_fit_reflection':2,'circle_fit_notch':3,'fano':5,'all_fits':5}
        try:
            self._fit_function = self._functions[fit_function]
        except KeyError:
            logging.error('Fit function not properly set. Must be either \'lorentzian\', \'skewed_lorentzian\', \'circle_fit_reflection\', \'circle_fit_notch\', \'fano\', or \'all_fits\'.')
        else:
            self._fit_resonator = True
            self._f_min = f_min
            self._f_max = f_max

    def _do_fit_resonator(self):
        '''
        calls fit function in resonator class
        fit function is specified in self.set_fit, with boundaries f_mim and f_max
        only the last 'slice' of data is fitted, since we fit live while measuring.
        '''

        if self._fit_function == 0: #lorentzian
            self._resonator.fit_lorentzian(f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == 1: #skewed_lorentzian
            self._resonator.fit_skewed_lorentzian(f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == 2: #circle_reflection
            self._resonator.fit_circle(reflection = True, f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == 3: #circle_notch
            self._resonator.fit_circle(notch = True, f_min=self._f_min, f_max = self._f_max)
        if self._fit_function == 4: #fano
            self._resonator.fit_fano(f_min=self._f_min, f_max = self._f_max)
        #if self._fit_function == 5: #all fits
            #self._resonator.fit_all_fits(f_min=self._f_min, f_max = self._f_max)

    def delete_fit_function(self, n = None):
        '''
        delete single fit function n (with 0 being the first one generated) or the complete landscape for n not specified
        '''

        if n:
            self.landscape = np.delete(self.landscape, n, axis=0)
        else:
            self.landscape = None

    def plot_fit_function(self, num_points = 100):
        '''
        try:
            x_coords = np.linspace(self.x_vec[0], self.x_vec[-1], num_points)
        except Exception as message:
            print 'no x axis information specified', message
            return
        '''
        if self.landscape:
            for trace in self.landscape:
                try:
                    #plt.clear()
                    plt.plot(self.x_vec, trace)
                    plt.fill_between(self.x_vec, trace+float(self.span)/2, trace-float(self.span)/2, alpha=0.5)
                except Exception:
                    print 'invalid trace...skip'
            plt.axhspan(self.y_vec[0], self.y_vec[-1], facecolor='0.5', alpha=0.5)
            plt.show()
        else:
            print 'No trace generated.'

    def set_span(self, span):
        self.span = span

    def get_span(self):
        return self.span

    def set_tdx(self, tdx):
        self.tdx = tdx

    def set_tdy(self, tdy):
        self.tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def f_parab(self,x,a,b,c):
        return a*(x-b)**2+c

    def f_hyp(self,x,a,b,c):
        "hyperbolic function with the form y = sqrt[ a*(x-b)**2 + c ]"
        return np.sqrt(a*(x-b)**2+c)

    def set_plot_comment(self, comment):
        '''
        Small comment to add at the end of plot pics for more information i.e. good for wiki entries.
        '''
        self._plot_comment=comment
Exemple #36
0
    def measure_timetrace(self, web_visible=True):
        '''
        measure method to record a single VNA timetrace, this only makes sense when span is set to 0 Hz!,
        tested only with KEYSIGHT E5071C ENA and its corresponding qkit driver
        LGruenhaupt 11/2016
        '''
        if self.vna.get_span() > 0:
            print 'VNA span not set to 0 Hz... aborting'
            return

        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = True

        self._measurement_object.measurement_func = 'measure_timetrace'
        self._measurement_object.x_axis = 'time'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'VNA_timetrace'
        self._file_name = self.dirname.replace(' ', '').replace(',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self.x_vec = np.arange(0, self.number_of_timetraces, 1)

        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        if self.progress_bar:
            self._p = Progress_Bar(self.number_of_timetraces,
                                   'VNA timetrace ' + self.dirname,
                                   self.vna.get_sweeptime_averages())

        print 'recording timetrace(s)...'
        sys.stdout.flush()

        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """

            for i, x in enumerate(self.x_vec):

                if self.log_function != None:
                    for i, f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))

                if self.averaging_start_ready:  #LG 11/2016
                    self.vna.start_measurement()
                    ti = time(
                    )  #changed from time.time() to time() - LGruenhaupt OCT_2016
                    tp = time()  #added to enable use of progress bar
                    #self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime_averages()) moved to line 303
                    ''' This is to prevent the vna.ready() function from timing out. LG NOV/16 '''
                    if self.vna.get_Average():
                        print 'this function only makes sense without averaging'
                        qt.mend()
                        self._end_measuremt()
                    else:
                        #self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                        qt.msleep(self.vna.get_sweeptime())
                        #self._p.iterate()

                        while not self.vna.ready():
                            qt.msleep(
                                .2
                            )  #this is just to check if the measurement has finished

                        data_amp, data_pha = self.vna.get_tracedata()
                        self._data_amp.append(data_amp)
                        self._data_pha.append(data_pha)
                qt.msleep()
                if self.progress_bar:
                    self._p.iterate()

                else:
                    print 'not implemented for this VNA, only works with Keysight ENA 5071C'
                    qt.mend()
                    self._end_measurement()

        except Exception as e:
            print e.__doc__
            print e.message
        finally:
            self._end_measurement()
            qt.mend()
Exemple #37
0
    def measure_1D(self, rescan=True, web_visible=True):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started. 
                If False, it will directly take the data from the VNA without waiting.
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        print 'recording trace...'
        sys.stdout.flush()

        qt.mstart()
        if rescan:
            if self.averaging_start_ready:
                self.vna.start_measurement()
                ti = time()
                if self.progress_bar:
                    self._p = Progress_Bar(self.vna.get_averages(),
                                           self.dirname,
                                           self.vna.get_sweeptime())
                qt.msleep(.2)
                while not self.vna.ready():
                    if time() - ti > self.vna.get_sweeptime(query=False):
                        if self.progress_bar: self._p.iterate()
                        ti = time()
                    qt.msleep(.2)
                if self.progress_bar:
                    while self._p.progr < self._p.max_it:
                        self._p.iterate()
            else:
                self.vna.avg_clear()
                if self.vna.get_averages() == 1 or self.vna.get_Average(
                ) == False:  #no averaging
                    if self.progress_bar:
                        self._p = Progress_Bar(1, self.dirname,
                                               self.vna.get_sweeptime())
                    qt.msleep(self.vna.get_sweeptime())  #wait single sweep
                    if self.progress_bar: self._p.iterate()
                else:  #with averaging
                    if self.progress_bar:
                        self._p = Progress_Bar(self.vna.get_averages(),
                                               self.dirname,
                                               self.vna.get_sweeptime())
                    if "avg_status" in self.vna.get_function_names():
                        for a in range(self.vna.get_averages()):
                            while self.vna.avg_status() <= a:
                                qt.msleep(
                                    .2
                                )  #maybe one would like to adjust this at a later point
                            if self.progress_bar: self._p.iterate()
                    else:  #old style
                        for a in range(self.vna.get_averages()):
                            qt.msleep(self.vna.get_sweeptime()
                                      )  #wait single sweep time
                            if self.progress_bar: self._p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        self._data_amp.append(data_amp)
        self._data_pha.append(data_pha)
        self._data_real.append(data_real)
        self._data_imag.append(data_imag)
        if self._fit_resonator:
            self._do_fit_resonator()

        qt.mend()
        self._end_measurement()
Exemple #38
0
def load_tabor(channel_sequences,
               ro_index,
               sample,
               reset=True,
               show_progress_bar=True):
    """
    This function takes the data, coming from virtual awg, and loads them into the awg
    :param channel_sequences: This must be a list of list, i.e., a list of channels each containing the sequences
    :param ro_index: coming from virtual awg, for each sequence there is a ro_index letting the awg know, when to
                     send the trigger.
    :param sample: you should know this
    :param reset: simply sets the awg_channel active, probably not needed
    :param show_progress_bar: enables the progress bar
    :return:
    """
    awg = sample.awg
    awg.clear_waveforms()
    number_of_channels = 0
    complex_channel = []
    for chan in channel_sequences:
        if True in (s.dtype == np.complex128 for s in chan):
            number_of_channels += 2
            complex_channel.append(True)
        else:
            number_of_channels += 1
            complex_channel.append(False)
    if number_of_channels > awg._numchannels:
        raise ValueError('more sequences than channels')
    # reordering channels if necessary
    if number_of_channels > 2:
        if complex_channel[:2] == [False, True]:
            logging.warning(
                'Channels reordered! Please do not split complex channels on two different channelpairs.'
                'Complex channel is on chpair 1')
            channel_sequences[:2] = [
                channel_sequences[1], channel_sequences[0]
            ]
            complex_channel[:2] = [True, False]
    #qkit.flow.start()

    if reset:
        _reset(awg, number_of_channels, ro_index)
    # Loading the waveforms into the AWG, differentiating between all cases
    if show_progress_bar:
        p = Progress_Bar(len(ro_index), 'Load AWG')

    if number_of_channels == 1:
        for j, seq in enumerate(channel_sequences[0]):
            _adjust_wfs_for_tabor(seq, [0], ro_index, 1, j, sample)
            if show_progress_bar:
                p.iterate()

    elif number_of_channels == 2:
        if complex_channel[0]:
            for j, seq in enumerate(channel_sequences[0]):
                _adjust_wfs_for_tabor(seq.real, seq.imag, ro_index, 1, j,
                                      sample)
                if show_progress_bar:
                    p.iterate()
        else:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1])):
                _adjust_wfs_for_tabor(seq[0], seq[1], ro_index, 1, j, sample)
                if show_progress_bar:
                    p.iterate()

    elif number_of_channels == 3:
        if complex_channel[0]:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1])):
                _adjust_wfs_for_tabor(seq[0].real, seq[0].imag, ro_index, 1, j,
                                      sample)
                _adjust_wfs_for_tabor(seq[1], [0], ro_index, 2, j, sample)
                if show_progress_bar:
                    p.iterate()
        else:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1],
                        channel_sequences[2])):
                _adjust_wfs_for_tabor(seq[0], seq[1], ro_index, 1, j, sample)
                _adjust_wfs_for_tabor(seq[2], [0], ro_index, 2, j, sample)
                if show_progress_bar:
                    p.iterate()

    else:  # 4 channels
        if complex_channel == [True, True]:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1])):
                _adjust_wfs_for_tabor(seq[0].real, seq[0].imag, ro_index, 1, j,
                                      sample)
                _adjust_wfs_for_tabor(seq[1].real, seq[1].imag, ro_index, 2, j,
                                      sample)
                if show_progress_bar:
                    p.iterate()
        elif complex_channel == [True, False, False]:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1],
                        channel_sequences[2])):
                _adjust_wfs_for_tabor(seq[0].real, seq[0].imag, ro_index, 1, j,
                                      sample)
                _adjust_wfs_for_tabor(seq[1], seq[2], ro_index, 2, j, sample)
                if show_progress_bar:
                    p.iterate()
        elif complex_channel == [False, False, True]:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1],
                        channel_sequences[2])):
                _adjust_wfs_for_tabor(seq[0], seq[1], ro_index, 1, j, sample)
                _adjust_wfs_for_tabor(seq[2].real, seq[2].imag, ro_index, 2, j,
                                      sample)
                if show_progress_bar:
                    p.iterate()
        else:
            for j, seq in enumerate(
                    zip(channel_sequences[0], channel_sequences[1],
                        channel_sequences[2], channel_sequences[3])):
                _adjust_wfs_for_tabor(seq[0], seq[1], ro_index, 1, j, sample)
                _adjust_wfs_for_tabor(seq[2], seq[3], ro_index, 2, j, sample)
                if show_progress_bar:
                    p.iterate()

    gc.collect()

    if number_of_channels <= 2:
        num_channels = [1, 2]
    else:
        num_channels = [1, 2, 3, 4]
    return np.all([awg.get('ch%i_status' % i) for i in num_channels])
Exemple #39
0
class SputterMonitor(object):
    """
    Sputter monitoring class, derived from spectroscopy.py
    monitors and stores sputter parameters live during deposition
    facilitates dynamic flow adjustment

    Example:
        m = SPUTTER_Monitor(quartz, ohmmeter, film_name, sample)
        m.set_filmparameters() ... see in corresponding docstring
        m.monitor_depo()

    Args:
        quartz (Instrument): The quartz oscillator instrument measuring thickness and rate.
        ohmmeter (Instrument): The resistance measurement instrument.
        mfc (Instrument): The mass flow controller instrument.
        film_name (str): A name can be given, that is added to the directory and filename.
        sample (Sample): A sample object can be given that is stored in the h5 file.

    Attributes:
        Should be listed here... Until then, use tabbing.
    """
    def __init__(self,
                 quartz=None,
                 ohmmeter=None,
                 mfc=None,
                 film_name='',
                 sample=None):
        self.quartz = quartz
        self.ohmmeter = ohmmeter
        self.mfc = mfc

        self.film_name = film_name
        self._sample = sample

        self.comment = ''
        self.dirname = None

        self.x_set_obj = None
        self.y_set_obj = None

        self.progress_bar = False

        self._show_ideal = False

        self._fit_resistance = False
        self._fit_every = 1
        self._fit_points = 5
        self._p0 = None

        self._reference_uid = None

        self._plot_comment = ""

        self.open_qviewkit = True
        self.qviewkit_singleInstance = False

        self._measurement_object = Measurement()
        self._measurement_object.measurement_type = 'sputter_deposition'
        self._measurement_object.sample = self._sample

        self._qvk_process = True

        self._duration = 60.  # Duration of monitoring
        self._resolution = 2.  # How often values should be taken

        self._target_resistance = 1000.
        self._target_thickness = 20.
        self._target_marker = False

        self._depmon_queue = Queue(
        )  # for communication with the depmon thread

    def set_duration(self, duration=60.):
        """
        Set the duration for the monitoring. Better too long than too short.

        Args:
            duration (float): Monitoring duration in seconds.
        """
        self._duration = duration

    def get_duration(self):
        """
        Get the duration for the monitoring.

        Returns:
            duration (float): Monitoring duration in seconds.
        """
        return self._duration

    def set_resolution(self, resolution=2.0):
        """
        Set the resolution for the monitoring.
        Every x second, the parameters will be read and stored.

        Args:
            resolution (float): Monitoring resolution in seconds.
        """
        self._resolution = resolution

    def get_resolution(self):
        """
        Get the resolution for the monitoring.
        Every x second, the parameters will be read and stored.

        Returns:
            resolution (float): Monitoring resolution in seconds.
        """
        return self._resolution

    def set_filmparameters(self,
                           resistance=1000.,
                           thickness=20.,
                           target_marker=False):
        """
        Set the target parameters of the film to be deposited.
        They are used to calculate the ideal trend of the measured parameters and their deviation from the ideal.

        Args:
            resistance (float): The target sheet resistance in Ohm.
            thickness (float): The target thickness in nm.
            target_marker (bool): Display a cross marking the target resistance and thickness.
        """
        self._target_resistance = resistance
        self._target_thickness = thickness
        self._target_marker = target_marker

    def get_filmparameters(self):
        """
        Get the set film parameters.

        Returns:
            Tuple containing:
                [0]: target_resistance (float): The target sheet resistance in Ohm.
                [1]: target_thickness (float): The target thickness in nm.
        """
        return self._target_resistance, self._target_thickness

    def ideal_resistance(self, thickness):
        """
        Calculates the ideal resistance at a given thickness depending on the set film parameters.

        Args:
            thickness (float): Film thickness in nm for which the ideal resistance should be calculated.

        Returns:
            The ideal resistance as a float.
        """
        try:
            return 1. / (thickness * (1. / self._target_resistance) /
                         self._target_thickness)
        except:
            return np.nan

    def ideal_trend(self):
        """
        Calculates a list of ideal resistances that is used as comparison in a view together with the real values.
        """
        t = np.linspace(1, self._target_thickness, 300)
        return [t, self.ideal_resistance(t)]

    def set_fit(self, fit=False, fit_every=1, fit_points=5, p0=None):
        """
        Settings for the fit used to estimate final resistance at target thickness and thickness at target resistance.

        Args:
            fit (bool): Turn on the fit.
            fit_every (int): Fit after every x measurement.
            fit_points (int): Fit to the last x points.
            p0 (list): Provide initial values for the curvefit.
        """
        self._fit_resistance = fit
        self._fit_every = fit_every
        self._fit_points = fit_points
        self._p0 = p0

    def set_reference_uid(self, uid=None):
        """
        Set a UID to be shown as a reference trace in the "resistance_thickness" view.

        Args:
            uid (str): The UID of the h5 file from which the resistance and thickness data is to be displayed.
        """
        try:
            ref = hdf.Data(qkit.fid[uid])
            self._ref_resistance = ref.data.resistance[:]
            self._ref_thickness = ref.data.thickness[:]
            self._reference_uid = uid
            ref.close()
            return self._reference_uid
        except:
            self._reference_uid = None
            return "Invalid UID"

    def set_resistance_4W(self, four_wire=False):
        """
        Sets 2 (default) or 4 wire measurement mode, if the device supports it.

        Args:
            four_wire = False
        """
        self.ohmmeter.set_measure_4W(four_wire)

    def get_rate(self, test_thickness):
        """
        Tests deposition rate.

        Args:
            test_thickness (in nm)
        """
        self.quartz.set_timer_zero()
        self.quartz.set_thickness_zero()
        time.sleep(3)
        while self.quartz.get_thickness() < test_thickness * 1e-2:
            time.sleep(1)
        mins, secs = self.quartz.get_time().split(':')
        t = 60 * float(mins) + float(secs)
        rate = test_thickness / t
        return rate, t

    def _theory(self, thickness, thickness_start, conductivity,
                cond_per_layer):
        """
        Calculate a prediction for the resistance at a certain film thickness,
        given the current thickness, current conductivity and added conductivity per layer.

        Args:
            thickness (float): Film thickness for which the resistance shall be predicted
            thickness_start (float): Film thickness at the start of the prediction.
            conductivity (float): Film conductivity at the start of the prediction.
            cond_per_layer (float): Added conductivity per layer for the remaining film growth.

        Returns:
            The projected film resistance (float).
        """
        t_added = thickness - thickness_start
        try:
            return 1. / (conductivity + t_added * cond_per_layer)
        except:
            return np.nan

    def _linear(self, x, a, b):
        """
        Helper function providing a linear fitting function.
        """
        return a * x + b

    def _fit_layer(self, t_points, R_points):
        """
        Fit the changing film resistance to extract the gained conductivity per layer.
        This is then used to project the final film resistance with the provided target film parameters.

        Args:
            t_points (numpy array): Thickness data from which the conductivity per layer is to be extracted.
            R_points (numpy array): Resistance data from which the conductivity per layer is to be extracted.

        Returns:
            Tuple containing:
                [0]: t_final (float): The predicted thickness at which the target resistance will be reached.
                [1]: R_final (float): The predicted resistance that will be reached at the target thickness.
                [2]: popt[0] (float): Conductivity per layer as obtained by linear fit.
        """
        # ToDo: Store all fits, Store time of fit to sync it to other datasets, revise theory.
        for i in R_points:
            if i == 0:
                return [np.nan, np.nan, np.nan]

        try:
            c_target = 1. / self._target_resistance
            c_points = 1. / R_points
            popt, _ = curve_fit(self._linear, t_points, c_points, p0=self._p0)
            R_final = self._theory(self._target_thickness, t_points[0],
                                   c_points[0], popt[0])
            t_final = ((c_target - c_points[-1]) / popt[0]) + t_points[-1]
            return [t_final, R_final, popt[0]]

        except:
            return [np.nan, np.nan, np.nan]

    def _reciprocal(self, thickness, cond_per_layer):
        """
        Function used by the curvefit routine.

        Args:
            thickness: Film thickness in nm.
            cond_per_layer: Film conductance per layer.

        Returns:
            The resistance for the given parameters as a float.
        """
        try:
            return 1. / (thickness * cond_per_layer)
        except:
            return np.nan

    def _fit_trend(self, t_points, R_points):
        """
        Do the fit used to estimate final resistance at target thickness and thickness at target resistance.

        Args:
            t_points: The last x points of film thickness in nm.
            R_points: The last x points of film resistivity in Ohm.

        Returns:
            List of [R_final, t_final] with
            R_final (float): Estimated final resistance at target thickness.
            t_final (float): Estimated thickness at target resistance.
        """
        for i in t_points:
            if i == 0:
                return [np.nan, np.nan]

        try:
            self._popt, _ = curve_fit(self._reciprocal,
                                      t_points,
                                      R_points,
                                      p0=self._p0)

            t_final = 1. / (self._target_resistance * self._popt[0])
            R_final = 1. / (self._target_thickness * self._popt[0])

            return [t_final, R_final]

        except:
            return [np.nan, np.nan]

    def _prepare_measurement_quartz(self):
        """
        All the relevant settings from the quartz are updated and called.
        """
        # self.quartz.get_all()
        # self.quartz.get_frequency() # Store it somewhere
        pass

    def _prepare_measurement_ohmmeter(self):
        """
        All the relevant settings from the ohmmeter are updated and called.
        """
        # self.ohmmeter.get_all()
        pass

    def _prepare_measurement_mfc(self):
        """
        All the relevant settings from the ohmmeter are updated and called.
        """
        # self.mfc.get_all()
        self.Ar_channel = self.mfc.predef_channels['Ar']
        self.ArO_channel = self.mfc.predef_channels['ArO']

        pass

    def _prepare_monitoring_file(self):
        """
        Creates the output .h5-file with distinct the required datasets and views.
        At this point all measurement parameters are known and put in the output file.
        """
        self._data_file = hdf.Data(name=self._file_name, mode='a')
        self._measurement_object.uuid = self._data_file._uuid
        self._measurement_object.hdf_relpath = self._data_file._relpath
        self._measurement_object.instruments = qkit.instruments.get_instrument_names(
        )

        self._measurement_object.save()
        self._mo = self._data_file.add_textlist('measurement')
        self._mo.append(self._measurement_object.get_JSON())

        # write logfile and instrument settings
        self._write_settings_dataset()
        self._log = waf.open_log_file(self._data_file.get_filepath())
        '''
        Time record
        '''
        self._data_time = self._data_file.add_value_vector('time',
                                                           x=None,
                                                           unit='s')
        '''
        Quartz datasets
        '''
        self._data_rate = self._data_file.add_value_vector(
            'rate', x=self._data_time, unit='nm/s', save_timestamp=False)
        self._data_thickness = self._data_file.add_value_vector(
            'thickness', x=self._data_time, unit='nm', save_timestamp=False)
        '''
        Ohmmeter datasets
        '''
        self._data_resistance = self._data_file.add_value_vector(
            'resistance', x=self._data_time, unit='Ohm', save_timestamp=False)
        self._data_conductance = self._data_file.add_value_vector(
            'conductance', x=self._data_time, unit='S', save_timestamp=False)
        self._data_deviation_abs = self._data_file.add_value_vector(
            'deviation_absolute',
            x=self._data_time,
            unit='Ohm',
            save_timestamp=False)
        self._data_deviation_rel = self._data_file.add_value_vector(
            'deviation_relative',
            x=self._data_time,
            unit='relative',
            save_timestamp=False)
        '''
        MFC datasets
        '''
        # FIXME: units?
        if self.mfc:
            self._data_pressure = self._data_file.add_value_vector(
                'pressure',
                x=self._data_time,
                unit='ubar',
                save_timestamp=False)
            self._data_Ar_flow = self._data_file.add_value_vector(
                'Ar_flow',
                x=self._data_time,
                unit='sccm',
                save_timestamp=False)
            self._data_ArO_flow = self._data_file.add_value_vector(
                'ArO_flow',
                x=self._data_time,
                unit='sccm',
                save_timestamp=False)
        '''
        Calculate ideal trend and create record
        '''
        self._thickness_coord = self._data_file.add_coordinate(
            'thickness_coord', unit='nm')
        self._thickness_coord.add(self.ideal_trend()[0])
        if self._show_ideal:
            self._data_ideal = self._data_file.add_value_vector(
                'ideal_resistance',
                x=self._thickness_coord,
                unit='Ohm',
                save_timestamp=False)
            self._data_ideal.append(self.ideal_trend()[1])
        '''
        Create target marker
        '''
        if self._target_marker:
            self._target_thickness_line = self._data_file.add_value_vector(
                'target_thickness', x=None, unit='nm', save_timestamp=False)
            self._target_thickness_line.append([
                0.8 * self._target_thickness, self._target_thickness,
                self._target_thickness, self._target_thickness,
                self._target_thickness, 1.2 * self._target_thickness
            ])
            self._target_resistance_line = self._data_file.add_value_vector(
                'target_resistance', x=None, unit='Ohm', save_timestamp=False)
            self._target_resistance_line.append([
                self._target_resistance, self._target_resistance,
                1.2 * self._target_resistance, 0.8 * self._target_resistance,
                self._target_resistance, self._target_resistance
            ])
            self._target_conductance_line = self._data_file.add_value_vector(
                'target_conductance', x=None, unit='S', save_timestamp=False)
            self._target_conductance_line.append([
                1. / self._target_resistance, 1. / self._target_resistance,
                1. / 1.2 / self._target_resistance,
                1. / 0.8 / self._target_resistance,
                1. / self._target_resistance, 1. / self._target_resistance
            ])
        '''
        Estimation datasets
        '''
        if self._fit_resistance:
            self._thickness_estimation = self._data_file.add_value_vector(
                'thickness_estimation',
                x=None,
                unit='nm',
                save_timestamp=False)
            self._resistance_estimation = self._data_file.add_value_vector(
                'resistance_estimation',
                x=None,
                unit='Ohm',
                save_timestamp=False)
            self._last_resistance_fit = self._data_file.add_value_vector(
                'last_resistance_fit',
                x=None,
                unit='Ohm',
                save_timestamp=False)
        '''
        Reference dataset
        '''
        if not self._reference_uid == None:
            self._thickness_reference = self._data_file.add_value_vector(
                'thickness_reference', x=None, unit='nm', save_timestamp=False)
            self._thickness_reference.append(self._ref_thickness)
            self._resistance_reference = self._data_file.add_value_vector(
                'reference_' + self._reference_uid,
                x=None,
                unit='Ohm',
                save_timestamp=False)
            self._resistance_reference.append(self._ref_resistance)
        '''
        Create Views
        '''
        self._resist_view = self._data_file.add_view('resistance_thickness',
                                                     x=self._data_thickness,
                                                     y=self._data_resistance)
        if self._show_ideal:
            self._resist_view.add(x=self._thickness_coord, y=self._data_ideal)
        if self._target_marker:
            self._resist_view.add(x=self._target_thickness_line,
                                  y=self._target_resistance_line)
        if not self._reference_uid == None:
            self._resist_view.add(x=self._thickness_reference,
                                  y=self._resistance_reference)
        if self._fit_resistance:
            self._resist_view.add(x=self._thickness_coord,
                                  y=self._last_resistance_fit)

        self._conductance_view = self._data_file.add_view(
            'conductance_thickness',
            x=self._data_thickness,
            y=self._data_conductance)
        if self._target_marker:
            self._conductance_view.add(x=self._target_thickness_line,
                                       y=self._target_conductance_line)

        self._deviation_abs_view = self._data_file.add_view(
            'deviation_absolute',
            x=self._data_thickness,
            y=self._data_deviation_abs)

        self._deviation_rel_view = self._data_file.add_view(
            'deviation_relative',
            x=self._data_thickness,
            y=self._data_deviation_rel)
        '''
        Create comment
        '''
        if self.comment:
            self._data_file.add_comment(self.comment)
        '''
        Open GUI
        '''
        if self.qviewkit_singleInstance and self.open_qviewkit and self._qvk_process:
            self._qvk_process.terminate()  # terminate an old qviewkit instance

    def _write_settings_dataset(self):
        """
        Writes a dataset containing the settings of the measurement instruments.
        """
        self._settings = self._data_file.add_textlist('settings')
        settings = waf.get_instrument_settings(self._data_file.get_filepath())
        self._settings.append(settings)

    def _init_depmon(self):
        """
        Initializes the measurement, the required files and instruments.
        Should only be called by the main functions monitor_depo or start_depmon.
        """
        self._measurement_object.measurement_func = 'sputter_monitoring'
        self._measurement_object.x_axis = 'time'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = True

        if not self.dirname:
            self.dirname = 'SPUTTER_monitoring'
        self._file_name = self.dirname.replace(' ', '').replace(',', '_')
        if self.film_name:
            self._file_name += '_' + self.film_name

        self.x_vec = np.arange(0, self._duration, self._resolution)

        self._prepare_measurement_quartz()
        self._prepare_measurement_ohmmeter()
        if self.mfc:
            self._prepare_measurement_mfc()

        self._prepare_monitoring_file()

    def _acquire(self, mon_data):
        """
        Acquires and stores current information from the instruments.
        Should only be called by main functions monitor_depo or start_depmon.
        """
        self._data_time.append(time.time() - mon_data.t0)

        # mon_data.resistance.append(self.ohmmeter.get_resistance())
        mon_data.resistance = np.append(mon_data.resistance,
                                        self.ohmmeter.get_resistance())
        if self.quartz:
            rate = self.quartz.get_rate(nm=True)
            # mon_data.thickness.append(self.quartz.get_thickness(nm=True))
            mon_data.thickness = np.append(mon_data.thickness,
                                           self.quartz.get_thickness(nm=True))
        if self.mfc:
            pressure = self.mfc.get_pressure()
            Ar_flow = self.mfc.get_flow(self.Ar_channel)
            ArO_flow = self.mfc.get_flow(self.ArO_channel)

        if mon_data.resistance[-1] > 1.e9:
            mon_data.resistance[-1] = np.nan
        self._data_resistance.append(mon_data.resistance[-1])
        if not mon_data.resistance[-1] == 0:
            self._data_conductance.append(1. / mon_data.resistance[-1])
        else:
            self._data_conductance.append(np.nan)
        if self.quartz:
            self._data_rate.append(rate)
            self._data_thickness.append(mon_data.thickness[-1])
        if self.mfc:
            self._data_pressure.append(pressure)
            self._data_Ar_flow.append(Ar_flow)
            self._data_ArO_flow.append(ArO_flow)
        if self.quartz:
            deviation_abs = mon_data.resistance[-1] - self.ideal_resistance(
                mon_data.thickness[-1])
            deviation_rel = deviation_abs / self._target_resistance

            self._data_deviation_abs.append(deviation_abs)
            self._data_deviation_rel.append(deviation_rel)

        if ((self._fit_resistance) and (mon_data.it % self._fit_every == 0)
                and (len(mon_data.resistance) >= self._fit_points)):
            """
            # OLD ROUTINE
            estimation = self._fit_trend(mon_data.thickness[-self._fit_points:None],
                                         mon_data.resistance[-self._fit_points:None])
            self._thickness_estimation.append(estimation[0])
            self._resistance_estimation.append(estimation[1])
            self._last_resistance_fit.append(self._reciprocal(self.ideal_trend()[0],self._popt[0]), reset=True)
            """
            estimation = self._fit_layer(
                mon_data.thickness[-self._fit_points:None],
                mon_data.resistance[-self._fit_points:None])
            self._thickness_estimation.append(estimation[0])
            self._resistance_estimation.append(estimation[1])
            self._last_resistance_fit.append(self._theory(
                self.ideal_trend()[0], mon_data.thickness[-1],
                1. / mon_data.resistance[-1], estimation[2]),
                                             reset=True)

    def monitor_depo(self):
        """
        Main sputter deposition monitoring function.

        Consider using the threaded version by calling start_depmon().

        Records the film resistance, thickness and deposition rate live during the sputter process.
        Stores everything into a h5 file.
        Provides measures to estimate the resulting resistance of the final film and thereby
        facilitates live adjustments to the sputter parameters.

        Note:
            set_duration and set_resolution should be called before to set the monitoring length and time resolution.
            set_filmparameters should be called before to provide the actual target values.
        """

        self._init_depmon()

        if self.progress_bar:
            self._p = Progress_Bar(
                self._duration / self._resolution,
                'EVAP_timetrace ' + self.dirname,
                self._resolution)  # FIXME: Doesn't make much sense...

        print('Monitoring deposition...')
        sys.stdout.flush()

        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(
                self._data_file.get_filepath(),
                datasets=['views/resistance_thickness'])

        try:
            """
            Initialize the data lists.
            """
            class MonData(object):
                resistance = np.array([])
                thickness = np.array([])

            mon_data = MonData()
            """
            Main loop:
            """
            mon_data.t0 = time.time(
            )  # note: Windows has limitations on time precision (about 16ms)
            for mon_data.it, _ in enumerate(self.x_vec):
                self._acquire(mon_data)

                if self.progress_bar:
                    self._p.iterate()

                # calculate the time when the next iteration should take place
                ti = mon_data.t0 + (float(mon_data.it) + 1) * self._resolution
                # wait until the total dt(iteration) has elapsed
                while time.time() < ti:
                    time.sleep(0.05)

        except KeyboardInterrupt:
            print('Monitoring interrupted by user.')

        except Exception as e:
            print(e)
            print(e.__doc__)
            print(e.message)

        finally:
            self._end_measurement()

    def _monitor_depo_bg(self):
        """
        Main sputter deposition monitoring function, threaded version

        Should only be called by main function start_depmon.

        Records the film resistance, thickness and deposition rate live during the sputter process.
        Stores everything into a h5 file.
        Provides measures to estimate the resulting resistance of the final film and thereby
        facilitates live adjustments to the sputter parameters.

        Note:
            set_duration and set_resolution should be called before to set the monitoring length and time resolution.
            set_filmparameters should be called before to provide the actual target values.
        """
        class StopPauseExeption(Exception):
            pass

        class StartPauseExeption(Exception):
            pass

        """
        A few boilerplate functions for the thread management:
        continue, stop, status, etc...
        """

        def stop():
            raise StopIteration

        def do_nothing():
            pass

        def status():
            self._depmon_queue.put(loop_status)

        def cont():
            raise StopPauseExeption

        def pause():
            raise StartPauseExeption

        loop_status = 0
        tasks = {}
        tasks[0] = stop
        tasks[1] = do_nothing
        tasks[2] = status
        tasks[3] = pause
        tasks[4] = cont
        """
        Initialize the data lists.
        """

        class MonData(object):
            resistance = np.array([])
            thickness = np.array([])

        mon_data = MonData()
        """
        Main loop:
        """
        mon_data.it = 0
        mon_data.t0 = time.time(
        )  # note: Windows has limitations on time precision (about 16ms)?
        while True:
            self._acquire(mon_data)

            # Handle external commands
            try:
                tasks.get(self._depmon_queue.get(False), do_nothing)()
                self._depmon_queue.task_done()
            except Empty:
                pass
            except StartPauseExeption:
                print('monitoring paused')
                while True:
                    try:
                        time.sleep(0.1)
                        tasks.get(self._depmon_queue.get(False), do_nothing)()
                        self._depmon_queue.task_done()
                    except StopPauseExeption:
                        print('monitoring restarted')
                        break
                    except Empty:
                        pass
            except StopPauseExeption:
                pass
            except StopIteration:
                break

            # calculate the time when the next iteration should take place
            mon_data.it += 1
            ti = mon_data.t0 + (float(mon_data.it)) * self._resolution
            loop_status = ti  # for now we simply return the runtime
            # wait until the total dt(iteration) has elapsed
            while time.time() < ti:
                time.sleep(0.05)

        self._end_measurement()

    def start_depmon(self):
        """
        Starts the main sputter deposition monitoring function background process (depmon).

        Records the film resistance, thickness and deposition rate live during the sputter process.
        Stores everything into a h5 file.
        Provides measures to estimate the resulting resistance of the final film and thereby
        facilitates live adjustments to the sputter parameters.

        Note:
            set_duration and set_resolution should be called before to set the monitoring length and time resolution.
            set_filmparameters should be called before to provide the actual target values.

        Hint:
            Check with 'list_depmon_threads()'
            Stop with 'stop_depmon()'
        """
        print('Monitoring deposition...')
        sys.stdout.flush()

        self._init_depmon()

        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(
                self._data_file.get_filepath(),
                datasets=['views/resistance_thickness'],
                refresh=1.)

        self._depmon = Thread(target=self._monitor_depo_bg, name="depmon-1")
        self._depmon.daemon = True
        self._depmon.start()

    def stop_depmon(self):
        """
        Stop the deposition monitoring thread.
        Can be executed several times if more than one monitoring thread is running.

        Hint:
            Check with 'list_depmon_threads()'
        """
        self._depmon_queue.put(0)

    def status_depmon(self):
        """
        Give a heartbeat of the deposition monitoring thread (in the moment just the runtime).
        """
        self._depmon_queue.put(2)
        print(self._depmon_queue.get())
        self._depmon_queue.task_done()

    def pause_depmon(self):
        print('Pause Monitoring deposition...')
        self._depmon_queue.put(3)

    def continue_depmon(self):
        print('Continue Monitoring deposition...')
        self._depmon_queue.put(4)

    def list_depmon_threads(self):
        """
        List all bg deposition monitoring threads.
        """
        for thread in threading.enumerate():
            if thread.getName()[:3] == "dep":
                print(thread)

    def _end_measurement(self):
        """
        The data file is closed and file path is printed.
        """
        print(self._data_file.get_filepath())
        # qviewkit.save_plots(self._data_file.get_filepath(),comment=self._plot_comment)
        # #old version where we have to wait for the plots
        t = threading.Thread(
            target=qviewkit.save_plots,
            args=[self._data_file.get_filepath(), self._plot_comment])
        t.start()
        self._data_file.close_file()
        waf.close_log_file(self._log)
        self.dirname = None
Exemple #40
0
class spectrum(object):
    '''
    usage:

    m = spectrum(vna = vna1)

    m.set_x_parameters(arange(-0.05,0.05,0.01),'flux coil current',coil.set_current, unit = 'mA')
    m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency',mw_src1.set_frequency, unit = 'Hz')

    m.gen_fit_function(...)      several times

    m.measure_XX()
    '''
    def __init__(self, vna, exp_name='', sample=None):

        self.vna = vna
        self.averaging_start_ready = "start_measurement" in self.vna.get_function_names(
        ) and "ready" in self.vna.get_function_names()
        if not self.averaging_start_ready:
            logging.warning(
                __name__ + ': With your VNA instrument driver (' +
                self.vna.get_type() +
                '), I can not see when a measurement is complete. So I only wait for a specific time and hope the VNA has finished. Please consider implemeting the necessary functions into your driver.'
            )
        self.exp_name = exp_name
        self._sample = sample

        self.landscape = None
        self.span = 200e6  #[Hz]
        self.tdx = 0.002  #[s]
        self.tdy = 0.002  #[s]

        self.comment = ''
        self.dirname = None

        self.x_set_obj = None
        self.y_set_obj = None

        self.progress_bar = True
        self._fit_resonator = False
        self._plot_comment = ""

        self.set_log_function()

        self.open_qviewkit = True
        self.qviewkit_singleInstance = False

        self._measurement_object = Measurement()
        self._measurement_object.measurement_type = 'spectroscopy'
        self._measurement_object.sample = self._sample

        self._qvk_process = False

        self.number_of_timetraces = 1  #relevant in time domain mode

    def set_log_function(self,
                         func=None,
                         name=None,
                         unit=None,
                         log_dtype=None):
        '''
        A function (object) can be passed to the measurement loop which is excecuted before every x iteration 
        but after executing the x_object setter in 2D measurements and before every line (but after setting 
        the x value) in 3D measurements.
        The return value of the function of type float or similar is stored in a value vector in the h5 file.

        Call without any arguments to delete all log functions. The timestamp is automatically saved.

        func: function object in list form
        name: name of logging parameter appearing in h5 file, default: 'log_param'
        unit: unit of logging parameter, default: ''
        log_dtype: h5 data type, default: 'f' (float32)
        '''

        if name == None:
            try:
                name = ['log_param'] * len(func)
            except Exception:
                name = None
        if unit == None:
            try:
                unit = [''] * len(func)
            except Exception:
                unit = None
        if log_dtype == None:
            try:
                log_dtype = ['f'] * len(func)
            except Exception:
                log_dtype = None

        self.log_function = []
        self.log_name = []
        self.log_unit = []
        self.log_dtype = []

        if func != None:
            for i, f in enumerate(func):
                self.log_function.append(f)
                self.log_name.append(name[i])
                self.log_unit.append(unit[i])
                self.log_dtype.append(log_dtype[i])

    def set_x_parameters(self, x_vec, x_coordname, x_set_obj, x_unit=""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_set_obj
        self.delete_fit_function()
        self.x_unit = x_unit

    def set_y_parameters(self, y_vec, y_coordname, y_set_obj, y_unit=""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        y_vec (array): contains the sweeping values
        y_coordname (string)
        y_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        y_unit (string): optional
        '''
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_set_obj
        self.delete_fit_function()
        self.y_unit = y_unit

    def gen_fit_function(self, curve_f, curve_p, units='', p0=[-1, 0.1, 7]):
        '''
        curve_f: 'parab', 'hyp', specifies the fit function to be employed
        curve_p: set of points that are the basis for the fit in the format [[x1,x2,x3,...],[y1,y2,y3,...]], frequencies in Hz
        units: set this to 'Hz' in order to avoid large values that cause the fit routine to diverge
        p0 (optional): start parameters for the fit, must be an 1D array of length 3 ([a,b,c,d]), 
           where for the parabula p0[3] will be ignored 
        The parabolic function takes the form  y = a*(x-b)**2 + c , where (a,b,c) = p0
        The hyperbolic function takes the form y = sqrt[ a*(x-b)**2 + c ], where (a,b,c) = p0
        
        adds a trace to landscape
        '''

        if not self.landscape:
            self.landscape = []

        x_fit = curve_p[0]
        if units == 'Hz':
            y_fit = np.array(curve_p[1]) * 1e-9
        else:
            y_fit = np.array(curve_p[1])

        try:
            multiplier = 1
            if units == 'Hz':
                multiplier = 1e9

            fit_fct = None
            if curve_f == 'parab':
                fit_fct = self.f_parab
            elif curve_f == 'hyp':
                fit_fct = self.f_hyp
            elif curve_f == 'lin':
                fit_fct = self.f_lin
                p0 = p0[:2]
            else:
                print 'function type not known...aborting'
                raise ValueError

            popt, pcov = curve_fit(fit_fct, x_fit, y_fit, p0=p0)
            self.landscape.append(multiplier * fit_fct(self.x_vec, *popt))

        except Exception as message:
            print 'fit not successful:', message
            popt = p0

    def _prepare_measurement_vna(self):
        '''
        all the relevant settings from the vna are updated and called
        '''

        self.vna.get_all()
        #ttip.get_temperature()
        self._nop = self.vna.get_nop()
        self._sweeptime_averages = self.vna.get_sweeptime_averages()
        self._freqpoints = self.vna.get_freqpoints()

        if self.averaging_start_ready: self.vna.pre_measurement()

    def _prepare_measurement_file(self):
        '''
        creates the output .h5-file with distinct dataset structures for each measurement type.
        at this point all measurement parameters are known and put in the output file
        '''

        self._data_file = hdf.Data(name=self._file_name)
        self._measurement_object.uuid = self._data_file._uuid
        self._measurement_object.hdf_relpath = self._data_file._relpath
        self._measurement_object.instruments = qt.instruments.get_instruments()

        self._measurement_object.save()
        self._mo = self._data_file.add_textlist('measurement')
        self._mo.append(self._measurement_object.get_JSON())

        # write logfile and instrument settings
        self._write_settings_dataset()
        self._log = waf.open_log_file(self._data_file.get_filepath())

        if not self._scan_time:
            self._data_freq = self._data_file.add_coordinate('frequency',
                                                             unit='Hz')
            self._data_freq.add(self._freqpoints)

        if self._scan_1D:
            self._data_real = self._data_file.add_value_vector(
                'real', x=self._data_freq, unit='', save_timestamp=True)
            self._data_imag = self._data_file.add_value_vector(
                'imag', x=self._data_freq, unit='', save_timestamp=True)
            self._data_amp = self._data_file.add_value_vector(
                'amplitude',
                x=self._data_freq,
                unit='arb. unit',
                save_timestamp=True)
            self._data_pha = self._data_file.add_value_vector(
                'phase', x=self._data_freq, unit='rad', save_timestamp=True)

        if self._scan_2D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname,
                                                          unit=self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_amp = self._data_file.add_value_matrix(
                'amplitude',
                x=self._data_x,
                y=self._data_freq,
                unit='arb. unit',
                save_timestamp=True)
            self._data_pha = self._data_file.add_value_matrix(
                'phase',
                x=self._data_x,
                y=self._data_freq,
                unit='rad',
                save_timestamp=True)

            if self.log_function != None:  #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(
                        self._data_file.add_value_vector(
                            self.log_name[i],
                            x=self._data_x,
                            unit=self.log_unit[i],
                            dtype=self.log_dtype[i]))

            if self._nop < 10:
                """creates view: plot middle point vs x-parameter, for qubit measurements"""
                self._data_amp_mid = self._data_file.add_value_vector(
                    'amplitude_midpoint',
                    unit='arb. unit',
                    x=self._data_x,
                    save_timestamp=True)
                self._data_pha_mid = self._data_file.add_value_vector(
                    'phase_midpoint',
                    unit='rad',
                    x=self._data_x,
                    save_timestamp=True)
                #self._view = self._data_file.add_view("amplitude vs. " + self.x_coordname, x = self._data_x, y = self._data_amp[self._nop/2])

        if self._scan_3D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname,
                                                          unit=self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_y = self._data_file.add_coordinate(self.y_coordname,
                                                          unit=self.y_unit)
            self._data_y.add(self.y_vec)

            if self._nop == 0:  #saving in a 2D matrix instead of a 3D box HR: does not work yet !!! test things before you put them online.
                self._data_amp = self._data_file.add_value_matrix(
                    'amplitude',
                    x=self._data_x,
                    y=self._data_y,
                    unit='arb. unit',
                    save_timestamp=False)
                self._data_pha = self._data_file.add_value_matrix(
                    'phase',
                    x=self._data_x,
                    y=self._data_y,
                    unit='rad',
                    save_timestamp=False)
            else:
                self._data_amp = self._data_file.add_value_box(
                    'amplitude',
                    x=self._data_x,
                    y=self._data_y,
                    z=self._data_freq,
                    unit='arb. unit',
                    save_timestamp=False)
                self._data_pha = self._data_file.add_value_box(
                    'phase',
                    x=self._data_x,
                    y=self._data_y,
                    z=self._data_freq,
                    unit='rad',
                    save_timestamp=False)

            if self.log_function != None:  #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(
                        self._data_file.add_value_vector(
                            self.log_name[i],
                            x=self._data_x,
                            unit=self.log_unit[i],
                            dtype=self.log_dtype[i]))

        if self._scan_time:
            self._data_freq = self._data_file.add_coordinate('frequency',
                                                             unit='Hz')
            self._data_freq.add([self.vna.get_centerfreq()])

            self._data_time = self._data_file.add_coordinate('time', unit='s')
            self._data_time.add(
                np.arange(0, self._nop, 1) * self.vna.get_sweeptime() /
                (self._nop - 1))

            self._data_x = self._data_file.add_coordinate('trace_number',
                                                          unit='')
            self._data_x.add(np.arange(0, self.number_of_timetraces, 1))

            self._data_amp = self._data_file.add_value_matrix(
                'amplitude',
                x=self._data_x,
                y=self._data_time,
                unit='lin. mag.',
                save_timestamp=False)
            self._data_pha = self._data_file.add_value_matrix(
                'phase',
                x=self._data_x,
                y=self._data_time,
                unit='rad.',
                save_timestamp=False)

        if self.comment:
            self._data_file.add_comment(self.comment)

        if self.qviewkit_singleInstance and self.open_qviewkit and self._qvk_process:
            self._qvk_process.terminate()  #terminate an old qviewkit instance

    def _write_settings_dataset(self):
        self._settings = self._data_file.add_textlist('settings')
        settings = waf.get_instrument_settings(self._data_file.get_filepath())
        self._settings.append(settings)

    def measure_1D(self, rescan=True, web_visible=True):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started. 
                If False, it will directly take the data from the VNA without waiting.
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        print 'recording trace...'
        sys.stdout.flush()

        qt.mstart()
        if rescan:
            if self.averaging_start_ready:
                self.vna.start_measurement()
                ti = time()
                if self.progress_bar:
                    self._p = Progress_Bar(self.vna.get_averages(),
                                           self.dirname,
                                           self.vna.get_sweeptime())
                qt.msleep(.2)
                while not self.vna.ready():
                    if time() - ti > self.vna.get_sweeptime(query=False):
                        if self.progress_bar: self._p.iterate()
                        ti = time()
                    qt.msleep(.2)
                if self.progress_bar:
                    while self._p.progr < self._p.max_it:
                        self._p.iterate()
            else:
                self.vna.avg_clear()
                if self.vna.get_averages() == 1 or self.vna.get_Average(
                ) == False:  #no averaging
                    if self.progress_bar:
                        self._p = Progress_Bar(1, self.dirname,
                                               self.vna.get_sweeptime())
                    qt.msleep(self.vna.get_sweeptime())  #wait single sweep
                    if self.progress_bar: self._p.iterate()
                else:  #with averaging
                    if self.progress_bar:
                        self._p = Progress_Bar(self.vna.get_averages(),
                                               self.dirname,
                                               self.vna.get_sweeptime())
                    if "avg_status" in self.vna.get_function_names():
                        for a in range(self.vna.get_averages()):
                            while self.vna.avg_status() <= a:
                                qt.msleep(
                                    .2
                                )  #maybe one would like to adjust this at a later point
                            if self.progress_bar: self._p.iterate()
                    else:  #old style
                        for a in range(self.vna.get_averages()):
                            qt.msleep(self.vna.get_sweeptime()
                                      )  #wait single sweep time
                            if self.progress_bar: self._p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        self._data_amp.append(data_amp)
        self._data_pha.append(data_pha)
        self._data_real.append(data_real)
        self._data_imag.append(data_imag)
        if self._fit_resonator:
            self._do_fit_resonator()

        qt.mend()
        self._end_measurement()

    def measure_2D(self, web_visible=True):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'frequency'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(len(self.x_vec),
                                   '2D VNA sweep ' + self.dirname,
                                   self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self._nop < 10:
            if self.open_qviewkit:
                self._qvk_process = qviewkit.plot(
                    self._data_file.get_filepath(),
                    datasets=['amplitude_midpoint', 'phase_midpoint'])
        else:
            if self.open_qviewkit:
                self._qvk_process = qviewkit.plot(
                    self._data_file.get_filepath(),
                    datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        self._measure()

    def measure_3D(self, web_visible=True):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = True
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_3D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = self.y_coordname
        self._measurement_object.z_axis = 'frequency'
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname + ', ' + self.y_coordname
        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(
                len(self.x_vec) * len(self.y_vec),
                '3D VNA sweep ' + self.dirname,
                self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        """only middle point in freq array is plotted vs x and y"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []  #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()

    def measure_timetrace(self, web_visible=True):
        '''
        measure method to record a single VNA timetrace, this only makes sense when span is set to 0 Hz!,
        tested only with KEYSIGHT E5071C ENA and its corresponding qkit driver
        LGruenhaupt 11/2016
        '''
        if self.vna.get_span() > 0:
            print 'VNA span not set to 0 Hz... aborting'
            return

        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = True

        self._measurement_object.measurement_func = 'measure_timetrace'
        self._measurement_object.x_axis = 'time'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'VNA_timetrace'
        self._file_name = self.dirname.replace(' ', '').replace(',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        self.x_vec = np.arange(0, self.number_of_timetraces, 1)

        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        if self.progress_bar:
            self._p = Progress_Bar(self.number_of_timetraces,
                                   'VNA timetrace ' + self.dirname,
                                   self.vna.get_sweeptime_averages())

        print 'recording timetrace(s)...'
        sys.stdout.flush()

        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """

            for i, x in enumerate(self.x_vec):

                if self.log_function != None:
                    for i, f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))

                if self.averaging_start_ready:  #LG 11/2016
                    self.vna.start_measurement()
                    ti = time(
                    )  #changed from time.time() to time() - LGruenhaupt OCT_2016
                    tp = time()  #added to enable use of progress bar
                    #self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime_averages()) moved to line 303
                    ''' This is to prevent the vna.ready() function from timing out. LG NOV/16 '''
                    if self.vna.get_Average():
                        print 'this function only makes sense without averaging'
                        qt.mend()
                        self._end_measuremt()
                    else:
                        #self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                        qt.msleep(self.vna.get_sweeptime())
                        #self._p.iterate()

                        while not self.vna.ready():
                            qt.msleep(
                                .2
                            )  #this is just to check if the measurement has finished

                        data_amp, data_pha = self.vna.get_tracedata()
                        self._data_amp.append(data_amp)
                        self._data_pha.append(data_pha)
                qt.msleep()
                if self.progress_bar:
                    self._p.iterate()

                else:
                    print 'not implemented for this VNA, only works with Keysight ENA 5071C'
                    qt.mend()
                    self._end_measurement()

        except Exception as e:
            print e.__doc__
            print e.message
        finally:
            self._end_measurement()
            qt.mend()

    def _measure(self):
        '''
        measures and plots the data depending on the measurement type.
        the measurement loops feature the setting of the objects and saving the data in the .h5 file.
        '''
        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """
            for ix, x in enumerate(self.x_vec):
                self.x_set_obj(x)
                sleep(self.tdx)

                if self.log_function != None:
                    for i, f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))

                if self._scan_3D:
                    for y in self.y_vec:
                        """
                        loop: y_obj with parameters from y_vec (only 3D measurement)
                        """
                        if (
                                np.min(
                                    np.abs(self.center_freqs[ix] - y *
                                           np.ones(len(self.center_freqs[ix])))
                                ) > self.span / 2.
                        ) and self.landscape:  #if point is not of interest (not close to one of the functions)
                            data_amp = np.zeros(int(self._nop))
                            data_pha = np.zeros(int(
                                self._nop))  #fill with zeros
                        else:
                            self.y_set_obj(y)
                            sleep(self.tdy)
                            if self.averaging_start_ready:
                                self.vna.start_measurement()
                                qt.msleep(
                                    .2
                                )  #just to make sure, the ready command does not *still* show ready
                                while not self.vna.ready():
                                    qt.msleep(.2)
                            else:
                                self.vna.avg_clear()
                                qt.msleep(self._sweeptime_averages)

                            #if "avg_status" in self.vna.get_function_names():
                            #       while self.vna.avg_status() < self.vna.get_averages():
                            #            qt.msleep(.2) #maybe one would like to adjust this at a later point
                            """ measurement """
                            data_amp, data_pha = self.vna.get_tracedata()

                        if self._nop == 0:  # this does not work yet.
                            print data_amp[0], data_amp, self._nop
                            self._data_amp.append(data_amp[0])
                            self._data_pha.append(data_pha[0])
                        else:
                            self._data_amp.append(data_amp)
                            self._data_pha.append(data_pha)
                        if self._fit_resonator:
                            self._do_fit_resonator()
                        if self.progress_bar:
                            self._p.iterate()
                        qt.msleep()
                    """
                    filling of value-box is done here.
                    after every y-loop the data is stored the next 2d structure
                    """
                    self._data_amp.next_matrix()
                    self._data_pha.next_matrix()

                if self._scan_2D:
                    if self.averaging_start_ready:
                        self.vna.start_measurement()
                        qt.msleep(
                            .2
                        )  #just to make sure, the ready command does not *still* show ready
                        while not self.vna.ready():
                            qt.msleep(.2)
                    else:
                        self.vna.avg_clear()
                        qt.msleep(self._sweeptime_averages)
                    """ measurement """
                    data_amp, data_pha = self.vna.get_tracedata()
                    self._data_amp.append(data_amp)
                    self._data_pha.append(data_pha)
                    if self._nop < 10:
                        #print data_amp[self._nop/2]
                        self._data_amp_mid.append(
                            float(data_amp[self._nop / 2]))
                        self._data_pha_mid.append(
                            float(data_pha[self._nop / 2]))

                    if self._fit_resonator:
                        self._do_fit_resonator()
                    if self.progress_bar:
                        self._p.iterate()
                    qt.msleep()
        except Exception as e:
            print e.__doc__
            print e.message
        finally:
            self._end_measurement()
            qt.mend()

    def _end_measurement(self):
        '''
        the data file is closed and filepath is printed
        '''
        print self._data_file.get_filepath()
        #qviewkit.save_plots(self._data_file.get_filepath(),comment=self._plot_comment) #old version where we have to wait for the plots
        t = threading.Thread(
            target=qviewkit.save_plots,
            args=[self._data_file.get_filepath(), self._plot_comment])
        t.start()
        self._data_file.close_file()
        waf.close_log_file(self._log)
        self.dirname = None
        if self.averaging_start_ready: self.vna.post_measurement()

    def set_resonator_fit(self,
                          fit_resonator=True,
                          fit_function='',
                          f_min=None,
                          f_max=None):
        '''
        sets fit parameter for resonator

        fit_resonator (bool): True or False, default: True (optional)
        fit_function (string): function which will be fitted to the data (optional)
        f_min (float): lower frequency boundary for the fitting function, default: None (optional)
        f_max (float): upper frequency boundary for the fitting function, default: None (optional)
        fit types: 'lorentzian','skewed_lorentzian','circle_fit_reflection', 'circle_fit_notch','fano'
        '''
        if not fit_resonator:
            self._fit_resonator = False
            return
        self._functions = {
            'lorentzian': 0,
            'skewed_lorentzian': 1,
            'circle_fit_reflection': 2,
            'circle_fit_notch': 3,
            'fano': 5,
            'all_fits': 5
        }
        try:
            self._fit_function = self._functions[fit_function]
        except KeyError:
            logging.error(
                'Fit function not properly set. Must be either \'lorentzian\', \'skewed_lorentzian\', \'circle_fit_reflection\', \'circle_fit_notch\', \'fano\', or \'all_fits\'.'
            )
        else:
            self._fit_resonator = True
            self._f_min = f_min
            self._f_max = f_max

    def _do_fit_resonator(self):
        '''
        calls fit function in resonator class
        fit function is specified in self.set_fit, with boundaries f_mim and f_max
        only the last 'slice' of data is fitted, since we fit live while measuring.
        '''

        if self._fit_function == 0:  #lorentzian
            self._resonator.fit_lorentzian(f_min=self._f_min,
                                           f_max=self._f_max)
        if self._fit_function == 1:  #skewed_lorentzian
            self._resonator.fit_skewed_lorentzian(f_min=self._f_min,
                                                  f_max=self._f_max)
        if self._fit_function == 2:  #circle_reflection
            self._resonator.fit_circle(reflection=True,
                                       f_min=self._f_min,
                                       f_max=self._f_max)
        if self._fit_function == 3:  #circle_notch
            self._resonator.fit_circle(notch=True,
                                       f_min=self._f_min,
                                       f_max=self._f_max)
        if self._fit_function == 4:  #fano
            self._resonator.fit_fano(f_min=self._f_min, f_max=self._f_max)
        #if self._fit_function == 5: #all fits
        #self._resonator.fit_all_fits(f_min=self._f_min, f_max = self._f_max)

    def delete_fit_function(self, n=None):
        '''
        delete single fit function n (with 0 being the first one generated) or the complete landscape for n not specified
        '''

        if n:
            self.landscape = np.delete(self.landscape, n, axis=0)
        else:
            self.landscape = None

    def plot_fit_function(self, num_points=100):
        '''
        try:
            x_coords = np.linspace(self.x_vec[0], self.x_vec[-1], num_points)
        except Exception as message:
            print 'no x axis information specified', message
            return
        '''
        if self.landscape:
            for trace in self.landscape:
                try:
                    #plt.clear()
                    plt.plot(self.x_vec, trace)
                    plt.fill_between(self.x_vec,
                                     trace + float(self.span) / 2,
                                     trace - float(self.span) / 2,
                                     alpha=0.5)
                except Exception:
                    print 'invalid trace...skip'
            plt.axhspan(self.y_vec[0],
                        self.y_vec[-1],
                        facecolor='0.5',
                        alpha=0.5)
            plt.show()
        else:
            print 'No trace generated.'

    def set_span(self, span):
        self.span = span

    def get_span(self):
        return self.span

    def set_tdx(self, tdx):
        self.tdx = tdx

    def set_tdy(self, tdy):
        self.tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def f_parab(self, x, a, b, c):
        return a * (x - b)**2 + c

    def f_hyp(self, x, a, b, c):
        "hyperbolic function with the form y = sqrt[ a*(x-b)**2 + c ]"
        return np.sqrt(a * (x - b)**2 + c)

    def f_lin(self, x, a, b):
        return a * x + b

    def set_plot_comment(self, comment):
        '''
        Small comment to add at the end of plot pics for more information i.e. good for wiki entries.
        '''
        self._plot_comment = comment
Exemple #41
0
class transport(object):

    '''
    useage:
    
    m = transport(daq = 'DAQ')
    
    m.set_voltage_bias('True')
    m.set_measurement_setup_parameters(conversion_IV = 1e7, V_amp=1, I_div=1, V_divider=1000)
    m.set_measurement_parameters(start=-100e-6, stop=100e-7, sample_count=1000, sample_rate=200, sweeps = 3)
    m.set_x_parameters(arange(0.,1.5,0.05),'magnetic coil current', yoko.set_current, 'A')
    #m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency', mw_src.set_frequency, 'Hz')
    #sweep-parameter only active for x.measure_IV()!!
    m.measure_IV_2D()
    '''

    def __init__(self, daq, exp_name = ''):

        self.daq = daq
        self.exp_name = exp_name

        self._chan_out = self.daq._ins._get_output_channels()[0]
        self._chan_in = self.daq._ins._get_input_channels()[0]

        self._tdx = 0.002
        self._tdy = 0.002

        self.comment = ''

        self._voltage_bias = False
        self._current_bias = True

        self._voltage_offset = 0.
        self._current_offset = 0.

    def set_x_parameters(self, x_vec, x_coordname, x_instrument, x_unit):
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_instrument
        self.x_unit = x_unit
        self._set_x_parameters = True

    def set_y_parameters(self, y_vec, y_coordname, y_instrument, y_unit):
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_instrument
        self.y_unit = y_unit
        self._set_y_parameters = True

    def set_measurement_setup_parameters(self, conversion_IV, V_amp, I_div, V_divider):
        self._conversion_IV = conversion_IV
        self._V_amp = V_amp
        self._I_div = I_div
        self._V_divider = V_divider
        self._set_measurement_setup_parameters = True

    def set_measurement_parameters(self, start, stop, sample_count, sample_rate, sweeps=1):
        self._start = start
        self._stop = stop
        self._sample_count = sample_count
        self._sample_rate = sample_rate
        self._sweeps = sweeps
        self._vec_fw = np.linspace(start, stop, sample_count)
        self._vec_bw = np.linspace(stop, start, sample_count)
        self._set_measurement_parameters = True

    def _check_measurement(self):
        if self._voltage_bias == self._current_bias:
            logging.error('Please specify current- or voltage-bias, both are %s...aborting' % (str(self._voltage_bias)))
            return False
        if not self._set_measurement_setup_parameters:
            logging.error('Please set_measurement_setup_parameters...aborting')
            return False          
        if not self._set_measurement_parameters:
            logging.error('Please set_measurement_parameters...aborting')
            return False     
        if self._measure_IV_2D or self._measure_IV_3D and not self._set_x_parameters:
            logging.error('Please set_x_parameters...aborting')
            return False
        if self._measure_IV_3D and not self._set_y_parameters:
            logging.error('Please set_y_parameters...aborting')
            return False
        return True

    def _save_settings(self):
            settings = "## Settings for measurement "+self._scan_name+' ##\n'
            settings += "A per V = %f\nV_amp = %f\nI_div = %f\nV_div = %f\nsamples = %f\nrate = %f\nsweeps = %f\n" % (float(self._conversion_factor), float(self._V_amp), float(self._I_div), float(self._V_div), float(self._sample_count), float(self._sample_rate), float(self._sweeps))
            settings += 'Voltage bias = %s, Current bias = %s\n' %(str(self._voltage_bias), str(self._current_bias))
            settings += "Min = %f \nMax = %f \n" % (self._start, self._stop)
            if not self._measure_IV:
                settings += "%s, %f-%f %s, step = %f\n" % (self.x_instrument, self.x_vec[0], self.x_vec[len(self.x_vec)-1], (self.x_vec[len(self.x_vec)-1]-self.x_vec[0])/(len(self.x_vec)-1))
            if self._measure_IV_3D:
                settings += "%s, %f-%f %s, step = %f\n" % (self.y_instrument, self.y_vec[0], self.y_vec[len(self.y_vec)-1], (self.y_vec[len(self.y_vec)-1]-self.y_vec[0])/(len(self.y_vec)-1))
            settings += "Current offset %f A\n" %(self._current_offset)
            settings += "Voltage offset %f V\n" %(self._voltage_offset)
            self._data.add_comment(settings)

    def measure_IV(self):
        self._measure_IV_1D = True
        self._measure_IV_2D = False
        self._measure_IV_3D = False
        if not self._check_measurement: 
            return

        self._scan_name = 'IV'
        if self.exp_name: 
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(self._sweeps)

        self._prepare_measurement_file() 
        self._save_settings()
        #qviewkit.plot_hdf(self._data.get_filepath()

        self._measure()
        self._end_measurement()


    def measure_IV_2D(self):
        self._measure_IV_1D = False
        self._measure_IV_2D = True
        self._measure_IV_3D = False
        if not self._check_measurement: 
            return

        self._scan_name = 'IV_vs_'+ self.x_coordname
        if self.exp_name: 
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(len(self.x_vec))

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.get_filepath())

        self._measure()
        self._end_measurement()


    def measure_IV_3D(self):
        self._measure_IV_1D = False
        self._measure_IV_2D = False
        self._measure_IV_3D = True
        if not self._check_measurement: 
            return

        self._scan_name = 'IV_vs_'+ self.x_coordname + '_' + self.y_coordname
        if self.exp_name: 
            self._scan_name += '_' + self.exp_name
        self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec))

        self._prepare_measurement_file()
        self._save_settings()
        #qviewkit.plot_hdf(self._data.filepath())

        self._measure()
        self._end_measurement()

    def _prepare_measurement_file(self):
        self._data = hdf.Data(name=self._scan_name)

        if self._voltage_bias:
            bias_name = 'Voltage'
            bias_unit = 'V'
            measurement_name = 'Current'
            measurement_unit = 'A'
        if self._current_bias:
            bias_name = 'Current'
            bias_unit = 'A'
            measurement_name = 'Voltage'
            measurement_unit = 'V'

        self._data_bias = self._data.add_coordinate(bias_name, unit = bias_unit)
        bias_vec = np.append(self._vec_fw, self._vec_bw)
        self._data_bias.add(bias_vec)

        if self._measure_IV_1D:
            if self._sweeps == 1:
                self._data_measure = self._data.add_value_vector(measurement_name, x = self._hdf_bias, unit = measurement_unit)
            else:
                self._data_sweep = self._data.add_coordinate('sweep')
                self._data_sweep.add([sweep for sweep in self._sweeps])
                self._data_measure = self._data.add_value_matrix(measurement_name, x = self._data_sweep, y = self._hdf_bias, unit = measurement_unit)
        if self._measure_IV_2D:
            self._data_x = self._dat.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_measure = self._data.add_value_matrix(measurement_name, x = self._x, y = self._hdf_bias, unit = measurement_unit)

        if self._measure_IV_3D:
            self._data_x = self._data.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec) 
            self._data_y = self._data.add_coordinate(self.y_coordname, unit = self.y_unit)
            self._data_y.add(self.y_vec) 
            self._data_measure = self._data.add_value_box(measurement_name, x = self._data_x, y = self._data_y, z = self._hdf_bias, unit = measurement_unit)

        if self.comment:
            self._data.add_comment(self.comment)

    def _measure(self):
        qt.mstart()
        plt.gca().set_xlabel("V [uV]")
        plt.gca().set_ylabel("I [nA]")
        try:
            if self._measure_IV_1D:
                for self._sweep in np.arange(self._sweeps):
                    if self._current_bias:
                        self._take_IV(out_conversion_factor = self._conversion_IV, in_amplification = self._V_amp, out_divider = self._V_divider)
                    if self._voltage_bias:
                        self._take_IV(out_conversion_factor = 1, in_amplification = self._conversion_IV, out_divider = self._V_divider)
                    self._p_iterate()

            if self._measure_IV_2D or self._measure_IV_3D:
                for self._x in self.x_vec:
                    self.x_set_obj(self._x)
                    sleep(self._tdx)

                    if self._measure_IV_2D:
                        if self._current_bias:
                            self._take_IV(out_conversion_factor = self._conversion_IV, in_amplification = self._V_amp, out_divider = self._V_divider)
                        if self._voltage_bias:
                            self._take_IV(out_conversion_factor = 1, in_amplification = self._conversion_IV, out_divider = self._V_divider)
                        self._p.iterate()

                    if self._measure_IV_3D:
                        for self._y in self.y_vec:
                            self.y_set_obj(self._y)
                            sleep(self._tdy)
                            if self._current_bias:
                                self._take_IV(out_conversion_factor = self._conversion_IV, in_amplification = self._V_amp, out_divider = self._V_divider)
                            if self._voltage_bias:
                                self._take_IV(out_conversion_factor = 1, in_amplification = self._conversion_IV, out_divider = self._V_divider)
                            self._p.iterate()

        finally:
            self.daq.set_ao1(0)
            qt.mend()

    def _end_measurement(self):
        print self._data.get_filepath()
        self._data.close_file()

    def _take_IV(self, out_conversion_factor,in_amplification,out_divider=1):
        """ IV measurement with current or voltage (vec_fw, vec_bw)!"""
        data_IV = self.daq.sync_output_input(self._chan_out, self._chan_in, self._vec_fw * out_divider / out_conversion_factor, rate=self._sample_rate)
        if self._current_bias:
            self._pl1 = plt.plot((data_IV/in_amplification)*1e6,self._vec_fw*1e6,"o")
        else:
            self._pl1 = plt.plot(self._vec_fw*1e6, (data_IV/in_amplification)*1e9,"-")
        qt.msleep(0.1)

        data_measure = []
        data_measure = np.append(data_measure, data_IV/in_amplification)

        data_IV = self.daq.sync_output_input(self._chan_out, self._chan_in, self._vec_bw * out_divider / out_conversion_factor, rate=self._sample_rate)
        if self._current_bias:
            self._pl1 = plt.plot((data_IV/in_amplification)*1e6,self._vec_fw*1e6,"o")
        else:
            self._pl1 = plt.plot(self._vec_fw*1e6, (data_IV/in_amplification)*1e9,"-")
        qt.msleep(0.1)

        data_measure = np.append(data_measure, data_IV/in_amplification)
        self._data_measure.append(data_measure)

    def set_tdx(self, tdx):
        self._tdx = tdx

    def set_tdy(self, tdy):
        self._tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def set_voltage_bias(self, voltage_bias):
        self._voltage_bias = voltage_bias
        self._current_bias = not voltage_bias

    def get_voltage_bias(self):
        return self._voltage_bias

    def set_current_bias(self, current_bias):
        self._current_bias = current_bias
        self._voltage_bias = not current_bias

    def get_current_bias(self):
        return self._current_bias

    def set_voltage_offset(self, voltage_offset):
        self._voltage_offset = voltage_offset

    def set_current_offset(self, voltage_offset):
        self._current_offset = voltage_offset

    def get_voltage_offset(self):
        return self._voltgae_offset

    def get_current_offset(self):
        return self._current_offset
Exemple #42
0
class transport(object):
    '''
    usage:

    m = spectrum(vna = vna1)

    m.set_x_parameters(arange(-0.05,0.05,0.01),'flux coil current',coil.set_current, unit = 'mA')
    m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency',mw_src1.set_frequency, unit = 'Hz')

    m.gen_fit_function(...)      several times

    m.measure_XX()
    '''

    def __init__(self, IV_Device, exp_name = '', sample = None):

        self.IVD = IV_Device
        
        
        self.exp_name = exp_name
        self._sample = sample



        self.comment = ''
        self.dirname = None

        self.x_set_obj = None
        self.y_set_obj = None

        self.progress_bar = True

        self._plot_comment=""

        self.set_log_function()
        
        self.open_qviewkit = True
        self.qviewkit_singleInstance = False
        
        self._measurement_object = Measurement()
        self._measurement_object.measurement_type = 'transport'
        self._measurement_object.sample = self._sample
        
        self._qvk_process = False
        
        self.number_of_timetraces = 1   #relevant in time domain mode
        
        self._web_visible = True
        
        self.sweep = self.sweeps()
        
        self._Fraunhofer = True
        
        
    def add_sweep_4quadrants(self, start, stop, step, offset=0):
        self.sweep.add_sweep(start+offset, stop+offset, step)
        self.sweep.add_sweep(stop+offset, start+offset, -step)
        self.sweep.add_sweep(start+offset, -stop+offset, -step)
        self.sweep.add_sweep(-stop+offset, start+offset, step)
        

    def set_log_function(self, func=None, name = None, unit = None, log_dtype = None):
        '''
        A function (object) can be passed to the measurement loop which is excecuted before every x iteration 
        but after executing the x_object setter in 2D measurements and before every line (but after setting 
        the x value) in 3D measurements.
        The return value of the function of type float or similar is stored in a value vector in the h5 file.

        Call without any arguments to delete all log functions. The timestamp is automatically saved.

        func: function object in list form
        name: name of logging parameter appearing in h5 file, default: 'log_param'
        unit: unit of logging parameter, default: ''
        log_dtype: h5 data type, default: 'f' (float32)
        '''

        if name == None:
            try:
                name = ['log_param']*len(func)
            except Exception:
                name = None
        if unit == None:
            try:
                unit = ['']*len(func)
            except Exception:
                unit = None
        if log_dtype == None:
            try:
                log_dtype = ['f']*len(func)
            except Exception:
                log_dtype = None

        self.log_function = []
        self.log_name = []
        self.log_unit = []
        self.log_dtype = []

        if func != None:
            for i,f in enumerate(func):
                self.log_function.append(f)
                self.log_name.append(name[i])
                self.log_unit.append(unit[i])
                self.log_dtype.append(log_dtype[i])

    def set_x_parameters(self, x_vec, x_coordname, x_set_obj, x_unit = ""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_set_obj
        #self.delete_fit_function()
        self.x_unit = x_unit

    def set_y_parameters(self, y_vec, y_coordname, y_set_obj, y_unit = ""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        y_vec (array): contains the sweeping values
        y_coordname (string)
        y_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        y_unit (string): optional
        '''
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_set_obj
        self.delete_fit_function()
        self.y_unit = y_unit

    def set_web_visible(self, web_visible = True):
        '''
        Sets the web_visible parameter for the measurement class
        Input:
        web_visible = True (Default) | False
        '''
        self._web_visible = web_visible
        
    def set_sweep_type(self, sweep_type = 1):
        '''
        # FIXME: HR this should go into the IVD driver 
        Sets the  sweep type, in the moment only simple sweep types are defined: 
        Input:
        sweep_type:
            0: single sweep START -> END 
            1: double sweep START -> END -> START (default)
            2: triple sweep START -> END -> START -> -END
            3: quad sweep   START -> END -> START -> -END -> START
            ...
        
        '''
        # define the number of datasets for each sweep type
        self.IV_sweep_types = { 0:1 , 1:2, 2:3, 3:4 }
        self.IV_sweep_type = sweep_type

    def get_sweep_type(self):
        return self.IV_sweep_type
    def get_num_ds_from_sweep_type(self,sweep_type):
        # should be self.IVD.IV_sweep_types[sweep_type]
        return self.IV_sweep_types[sweep_type]
        
        
        
    def _prepare_measurement_IVD(self):
        '''
        all the relevant settings from the vna are updated and called
        '''

        self.IVD.get_all()
        #ttip.get_temperature() 
        # bias mode is either  current=0 or voltage=1
        self._bias_mode = self.IVD.get_bias_mode()
        
        #self._nop = self.IVD.get_nop()
        #self._sweeptime_averages = self.IVD.get_sweeptime_averages()
        #self._freqpoints = self.IVD.get_freqpoints()

        #if self.averaging_start_ready: self.vna.pre_measurement()

    def _prepare_measurement_file(self):
        '''
        creates the output .h5-file with distinct dataset structures for each measurement type.
        at this point all measurement parameters are known and put in the output file
        '''
        print ('filename '+self._file_name)
        self._data_file = hdf.Data(name=self._file_name)
        self._measurement_object.uuid = self._data_file._uuid
        self._measurement_object.hdf_relpath = self._data_file._relpath
        self._measurement_object.instruments = qt.instruments.get_instruments()

        #self._measurement_object.save()
        self._mo = self._data_file.add_textlist('measurement')
        self._mo.append(self._measurement_object.get_JSON())

        # write logfile and instrument settings
        #self._write_settings_dataset()
        #self._log = waf.open_log_file(self._data_file.get_filepath())

        #if not self._scan_time:
        #    self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
        #    self._data_freq.add(self._freqpoints)

        self._data_I  = []
        self._data_V  = []
        #self._data_dVdI  = []
        if self._scan_1D:
            if self._bias_mode:# current bias
                #self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
                for st in range(self.sweep.get_nos()):
                    self._data_V.append(self._data_file.add_value_vector('V_'+str(st), unit = 'V', save_timestamp = False))
                    self._data_I.append(self._data_file.add_value_vector('I_'+str(st), x = self._data_V[st], unit = 'A', save_timestamp = False))
                    #self._data_dVdI.append(self._data_file.add_value_vector('_data_dVdI_'+str(st), x = self._data_V[st], unit = 'V/A', save_timestamp = False))
                    
                IV   = self._data_file.add_view('IV', x = self._data_V[0], y = self._data_I[0])
                #dVdI = self._data_file.add_view('dVdI', x = self._data_I[0] , y = self._data_dVdI[0])
                for i in range(1, self.sweep.get_nos()):
                    IV.add(x=self._data_V[i],y=self._data_I[i])
                    #dVdI.add(x=self._data_I[i],y=self._data_dVdI[i])
                    

        if self._scan_2D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            
            for st in range(self.sweep.get_nos()):
                self._data_I.append(self._data_file.add_value_vector('I_'+str(st), unit = 'A', save_timestamp = False))
                self._data_V.append(self._data_file.add_value_matrix('V_'+str(st), x = self._data_x, y = self._data_I[st], unit = 'V', save_timestamp = False))
                #self._data_dVdI.append(self._data_file.add_value_matrix('dVdI_'+str(st), x = self._data_x, y = self._data_I[st], unit = 'V/A', save_timestamp = False))
            
            if self._Fraunhofer:
                self._data_Ic = []
                for st in range(self.sweep.get_nos()):
                    self._data_Ic.append(self._data_file.add_value_vector('Ic_'+str(st), x = self._data_x, unit = 'A', save_timestamp = False))
                
                Fraunhofer = self._data_file.add_view('Fraunhofer', x=self._data_x, y=self._data_Ic[0])
                for i in range(1, self.sweep.get_nos()):
                    Fraunhofer.add(x=self._data_x, y=self._data_Ic[i])
                
                
            #if self.log_function != None:   #use logging
            #    self._log_value = []
            #    for i in range(len(self.log_function)):
            #        self._log_value.append(self._data_file.add_value_vector(self.log_name[i], x = self._data_x, unit = self.log_unit[i], dtype=self.log_dtype[i]))

        if self._scan_3D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_y = self._data_file.add_coordinate(self.y_coordname, unit = self.y_unit)
            self._data_y.add(self.y_vec)
            
            if self._nop == 0:   #saving in a 2D matrix instead of a 3D box HR: does not work yet !!! test things before you put them online.
                self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_y,  unit = 'arb. unit',   save_timestamp = False)
                self._data_pha = self._data_file.add_value_matrix('phase',     x = self._data_x, y = self._data_y,  unit = 'rad', save_timestamp = False)
            else:
                self._data_amp = self._data_file.add_value_box('amplitude', x = self._data_x, y = self._data_y, z = self._data_freq, unit = 'arb. unit', save_timestamp = False)
                self._data_pha = self._data_file.add_value_box('phase', x = self._data_x, y = self._data_y, z = self._data_freq, unit = 'rad', save_timestamp = False)
                
            if self.log_function != None:   #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(self._data_file.add_value_vector(self.log_name[i], x = self._data_x, unit = self.log_unit[i], dtype=self.log_dtype[i]))
                    
        if self.comment:
            self._data_file.add_comment(self.comment)
            
        if self.qviewkit_singleInstance and self.open_qviewkit and self._qvk_process:
            self._qvk_process.terminate() #terminate an old qviewkit instance

    def _write_settings_dataset(self):
        self._settings = self._data_file.add_textlist('settings')
        settings = waf.get_instrument_settings(self._data_file.get_filepath())
        self._settings.append(settings)

    def _wait_progress_bar(self):
        ti = time()
        if self.progress_bar: 
            self._p = Progress_Bar(self.IVD.get_averages(),self.dirname,self.IVD.get_sweeptime())
        qt.msleep(.2)
        # wait for data
        while not self.IVD.ready():
            if time()-ti > self.IVD.get_sweeptime(query=False):
                if self.progress_bar: self._p.iterate()
                ti = time()
            qt.msleep(.2)
        
        if self.progress_bar:
            while self._p.progr < self._p.max_it:
                self._p.iterate()
                
    def measure_1D(self, sweep_type=1):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started. 
                If False, it will directly take the data from the VNA without waiting.
        '''
        
        self._sweep_type = sweep_type
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = self._web_visible
        if not self.dirname:
            self.dirname = 'IVD_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
            
        # prepare storage
        self._prepare_measurement_IVD()
        self._prepare_measurement_file()


        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['I_0', 'V_0'])
        print('recording trace...')
        sys.stdout.flush()

        qt.mstart()
        
        self.sweep.create_iterator()
        self.IVD.set_status(True)
        for st in range(self.sweep.get_nos()):
            #print st
            self.IVD.set_sweep_parameters(self.sweep.get_sweep())
            data_bias, data_sense = self.IVD.take_IV()
            self._data_I[st].append(data_bias)
            self._data_V[st].append(data_sense)
            #self._data_dVdI[st].append(np.gradient(self._data_V[st])/np.gradient(self._data_I[st]))
        self.IVD.set_status(False)


        qt.mend()
        self._end_measurement()




    def measure_2D(self):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        
        
        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'current'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = self._web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        #if self.progress_bar: self._p = Progress_Bar(len(self.x_vec),'2D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())

        self._prepare_measurement_IVD()
        self._prepare_measurement_file()

        '''opens qviewkit to plot measurement, amp and pha are opened by default'''
        
        if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['I_0', 'V_0'])
        
        self._measure()
#
#
#    def measure_3D(self):
#        '''
#        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.
#
#        optional: measure method to perform the measurement according to landscape, if set
#        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
#        note: make sure to have properly set x,y vectors before generating traces
#        '''
#        if not self.x_set_obj or not self.y_set_obj:
#            logging.error('axes parameters not properly set...aborting')
#            return
#        self._scan_1D = False
#        self._scan_2D = False
#        self._scan_3D = True
#        self._scan_time = False
#        
#        self._measurement_object.measurement_func = 'measure_3D'
#        self._measurement_object.x_axis = self.x_coordname
#        self._measurement_object.y_axis = self.y_coordname
#        self._measurement_object.z_axis = 'frequency'
#        self._measurement_object.web_visible = self._web_visible
#
#        if not self.dirname:
#            self.dirname = self.x_coordname + ', ' + self.y_coordname
#        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(',','_')
#        if self.exp_name:
#            self._file_name += '_' + self.exp_name
#
#        if self.progress_bar: self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec),'3D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())
#
#        self._prepare_measurement_vna()
#        self._prepare_measurement_file()
#        '''opens qviewkit to plot measurement, amp and pha are opened by default'''
#        '''only middle point in freq array is plotted vs x and y'''
#        if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
#        if self._fit_resonator:
#            self._resonator = resonator(self._data_file.get_filepath())
#
#        if self.landscape:
#            self.center_freqs = np.array(self.landscape).T
#        else:
#            self.center_freqs = []     #load default sequence
#            for i in range(len(self.x_vec)):
#                self.center_freqs.append([0])
#
#        self._measure()
  
        

    def _measure(self):
        '''
        measures and plots the data depending on the measurement type.
        the measurement loops feature the setting of the objects and saving the data in the .h5 file.
        '''
        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """
            self.IVD.set_status(True)
            for ix, x in enumerate(self.x_vec):
                self.x_set_obj(x)
                sleep(1)
                
                #if self.log_function != None:
                #    for i,f in enumerate(self.log_function):
                #        self._log_value[i].append(float(f()))

                

                if self._scan_2D:
                    """ measurement """
                    self.sweep.create_iterator()
                    for st in range(self.sweep.get_nos()):
                        self.IVD.set_sweep_parameters(self.sweep.get_sweep())
                        data_bias, data_sense = self.IVD.take_IV(channel=1)
                        self._data_I[st].add(data_bias)
                        self._data_V[st].append(data_sense)
                        #self._data_dVdI[st].append(np.array(np.gradient(self._data_V[st]))[-1]/np.gradient(self._data_I[st]))
                        
                        if self._Fraunhofer:
                            self._IVC = IV_curve()
                            self._data_Ic[st].append(self._IVC.get_Ic(V=data_sense, I=data_bias, direction=self.IVD._direction))
                    
                    
                    #if self.progress_bar:
                    #    self._p.iterate()
                    qt.msleep()
            self.IVD.set_status(False)
        except Exception as e:
            print e.__doc__
            print e.message        
        finally:
            self._end_measurement()
            self.IVD.set_status(False, 1)
            #self.IVD.ramp_current(0, 100e-6, channel=2)
            self.IVD.set_status(False, 2)
            qt.mend()

    def _end_measurement(self):
        '''
        the data file is closed and filepath is printed
        '''
        print self._data_file.get_filepath()
        #qviewkit.save_plots(self._data_file.get_filepath(),comment=self._plot_comment) #old version where we have to wait for the plots
        t = threading.Thread(target=qviewkit.save_plots,args=[self._data_file.get_filepath(),self._plot_comment])
        t.start()
        self._data_file.close_file()
        #waf.close_log_file(self._log)
        self.dirname = None
        


    def set_span(self, span):
        self.span = span

    def get_span(self):
        return self.span

    def set_tdx(self, tdx):
        self.tdx = tdx

    def set_tdy(self, tdy):
        self.tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def f_parab(self,x,a,b,c):
        return a*(x-b)**2+c

    def f_hyp(self,x,a,b,c):
        "hyperbolic function with the form y = sqrt[ a*(x-b)**2 + c ]"
        return np.sqrt(a*(x-b)**2+c)

    def set_plot_comment(self, comment):
        '''
        Small comment to add at the end of plot pics for more information i.e. good for wiki entries.
        '''
        self._plot_comment=comment
    
    
    class sweeps(object):
        def __init__(self, name='default'):
            self._starts = []
            self._stops  = []
            self._steps  = []
            self.create_iterator()
        
        def create_iterator(self):
            self._start_iter = iter(self._starts)
            self._stop_iter = iter(self._stops)
            self._step_iter = iter(self._steps)
            
            
        def add_sweep(self, start, stop, step):
            self._starts.append(start)
            self._stops.append(stop)
            self._steps.append(step)
            
            
        def reset_sweeps(self):
            self._starts = []
            self._stops  = []
            self._stops  = []
            
        
        def get_sweep(self):
            return (self._start_iter.next(),
                    self._stop_iter.next(),
                    self._step_iter.next())
                    
        def get_nos(self):
            return len(self._starts)
            
            
        def print_sweeps(self):
            print(self._starts, self._stops, self._steps)
            
            
Exemple #43
0
class spectrum(object):
    """
    usage: similar to the old spectroscopy file.However class generates hdf vectors/matrices depending on the number
    of traces of your signal_analyzer.

    m = spectrum(sig_analyzer = specki)

    m.set_x_parameters(arange(-0.05,0.05,0.01),'flux coil current',coil.set_current, unit = 'mA')
    m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency',mw_src1.set_frequency, unit = 'Hz')

    m.gen_fit_function(...)      several times

    m.measure_XX()
    functions that must be additionally implemented in your signal analyzer's driver
    get_y_unit(trace) - returns y-unit of your trace
    get_active_traces() - returns number of traces
    get_trace_name(trace) - returns name of your trace
    """
    def __init__(self, sig_analyzer, exp_name='', sample=None):

        self.sig_analyzer = sig_analyzer
        self.averaging_start_ready = "start_measurement" in self.sig_analyzer.get_function_names() \
                                     and "ready" in self.sig_analyzer.get_function_names()
        if not self.averaging_start_ready:
            logging.warning(
                __name__ + ': With your signal analyzer driver (' +
                self.sig_analyzer.get_type() + '),'
                ' I can not see when a measurement is complete. '
                'So I only wait for a specific time and hope the VNA has finished. '
                'Please consider implemeting the necessary functions into your driver.'
            )
        self.exp_name = exp_name
        self._sample = sample

        self.landscape = None
        self.span = 200e6  # [Hz]
        self.tdx = 0.002  # [s]
        self.tdy = 0.002  # [s]

        self.comment = ''
        self.dirname = None

        self.x_set_obj = None
        self.y_set_obj = None

        self.progress_bar = True
        self._plot_comment = ""

        self.set_log_function()

        self.open_qviewkit = True
        self.qviewkit_singleInstance = False

        self._measurement_object = Measurement()
        self._measurement_object.measurement_type = 'spectroscopy'
        self._measurement_object.sample = self._sample

        self._qvk_process = False

    def set_log_function(self,
                         func=None,
                         name=None,
                         unit=None,
                         log_dtype=None):
        '''
        A function (object) can be passed to the measurement loop which is excecuted before every x iteration
        but after executing the x_object setter in 2D measurements and before every line (but after setting
        the x value) in 3D measurements.
        The return value of the function of type float or similar is stored in a value vector in the h5 file.

        Call without any arguments to delete all log functions. The timestamp is automatically saved.

        func: function object in list form
        name: name of logging parameter appearing in h5 file, default: 'log_param'
        unit: unit of logging parameter, default: ''
        log_dtype: h5 data type, default: 'f' (float32)
        '''

        if name == None:
            try:
                name = ['log_param'] * len(func)
            except Exception:
                name = None
        if unit == None:
            try:
                unit = [''] * len(func)
            except Exception:
                unit = None
        if log_dtype == None:
            try:
                log_dtype = ['f'] * len(func)
            except Exception:
                log_dtype = None

        self.log_function = []
        self.log_name = []
        self.log_unit = []
        self.log_dtype = []

        if func != None:
            for i, f in enumerate(func):
                self.log_function.append(f)
                self.log_name.append(name[i])
                self.log_unit.append(unit[i])
                self.log_dtype.append(log_dtype[i])

    def set_x_parameters(self, x_vec, x_coordname, x_set_obj, x_unit=""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_set_obj
        self.delete_fit_function()
        self.x_unit = x_unit

    def set_y_parameters(self, y_vec, y_coordname, y_set_obj, y_unit=""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        y_vec (array): contains the sweeping values
        y_coordname (string)
        y_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        y_unit (string): optional
        '''
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_set_obj
        self.delete_fit_function()
        self.y_unit = y_unit

    def gen_fit_function(self, curve_f, curve_p, units='', p0=[-1, 0.1, 7]):
        '''
        curve_f: 'parab', 'hyp', specifies the fit function to be employed
        curve_p: set of points that are the basis for the fit in the format [[x1,x2,x3,...],[y1,y2,y3,...]], frequencies in Hz
        units: set this to 'Hz' in order to avoid large values that cause the fit routine to diverge
        p0 (optional): start parameters for the fit, must be an 1D array of length 3 ([a,b,c,d]),
           where for the parabula p0[3] will be ignored
        The parabolic function takes the form  y = a*(x-b)**2 + c , where (a,b,c) = p0
        The hyperbolic function takes the form y = sqrt[ a*(x-b)**2 + c ], where (a,b,c) = p0

        adds a trace to landscape
        '''
        if not qkit.module_available("scipy"):
            raise ImportError('scipy not available.')

        if not self.landscape:
            self.landscape = []

        x_fit = curve_p[0]
        if units == 'Hz':
            y_fit = np.array(curve_p[1]) * 1e-9
        else:
            y_fit = np.array(curve_p[1])

        try:
            multiplier = 1
            if units == 'Hz':
                multiplier = 1e9

            fit_fct = None
            if curve_f == 'parab':
                fit_fct = self.f_parab
            elif curve_f == 'hyp':
                fit_fct = self.f_hyp
            elif curve_f == 'lin':
                fit_fct = self.f_lin
                p0 = p0[:2]
            else:
                print('function type not known...aborting')
                raise ValueError

            popt, pcov = curve_fit(fit_fct, x_fit, y_fit, p0=p0)
            self.landscape.append(multiplier * fit_fct(self.x_vec, *popt))

        except Exception as message:
            print('fit not successful:', message)
            popt = p0

    def _prepare_measurement_sig_analyzer(self):
        '''
        all the relevant settings from the vna are updated and called
        '''

        self.sig_analyzer.get_all()
        # ttip.get_temperature()
        self._nop = self.sig_analyzer.get_nop()
        self._sweeptime_averages = self.sig_analyzer.get_sweeptime_averages()
        self._freqpoints = self.sig_analyzer.get_freqpoints()
        self.num_traces = self.sig_analyzer.get_active_traces()
        self.traces_names = []
        self.units = []
        for i in range(self.num_traces):
            self.traces_names.append(self.sig_analyzer.get_trace_name(
                i + 1))  # must be implemented in driver
            self.units.append(
                self.sig_analyzer.get_y_unit(i +
                                             1))  # must also be impelmented

        if self.averaging_start_ready:
            self.sig_analyzer.pre_measurement()

    def _prepare_measurement_file(self):
        '''
        creates the output .h5-file with distinct dataset structures for each measurement type.
        at this point all measurement parameters are known and put in the output file
        '''

        self._data_file = hdf.Data(name=self._file_name, mode='a')
        self._measurement_object.uuid = self._data_file._uuid
        self._measurement_object.hdf_relpath = self._data_file._relpath
        self._measurement_object.instruments = qkit.instruments.get_instrument_names(
        )

        self._measurement_object.save()
        self._mo = self._data_file.add_textlist('measurement')
        self._mo.append(self._measurement_object.get_JSON())

        # write logfile and instrument settings
        self._write_settings_dataset()
        self._log = waf.open_log_file(self._data_file.get_filepath())
        self._data_freq = self._data_file.add_coordinate('frequency',
                                                         unit='Hz')
        self._data_freq.add(self._freqpoints)
        self._data = []  # empty list as we have a variable number of channels

        if self._scan_1D:
            for i in range(self.num_traces):
                self._data.append(
                    self._data_file.add_value_vector(self.traces_names[i],
                                                     x=self._data_freq,
                                                     unit=self.units[i],
                                                     save_timestamp=True))
        if self._scan_2D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname,
                                                          unit=self.x_unit)
            self._data_x.add(self.x_vec)
            for i in range(self.num_traces):
                self._data.append(
                    self._data_file.add_value_matrix(self.traces_names[i],
                                                     x=self._data_x,
                                                     y=self._data_freq,
                                                     unit=self.units[i],
                                                     save_timestamp=True))
            if self.log_function != None:  # use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(
                        self._data_file.add_value_vector(
                            self.log_name[i],
                            x=self._data_x,
                            unit=self.log_unit[i],
                            dtype=self.log_dtype[i]))

        if self._scan_3D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname,
                                                          unit=self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_y = self._data_file.add_coordinate(self.y_coordname,
                                                          unit=self.y_unit)
            self._data_y.add(self.y_vec)
            for i in range(self.num_traces):
                self._data.append(
                    self._data_file.add_value_box(self.traces_names[i],
                                                  x=self._data_x,
                                                  y=self.data_y,
                                                  z=self._data_freq,
                                                  unit=self.units[i],
                                                  save_timestamp=True))
            if self.log_function != None:  # use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(
                        self._data_file.add_value_vector(
                            self.log_name[i],
                            x=self._data_x,
                            unit=self.log_unit[i],
                            dtype=self.log_dtype[i]))

        if self.comment:
            self._data_file.add_comment(self.comment)

        if self.qviewkit_singleInstance and self.open_qviewkit and self._qvk_process:
            self._qvk_process.terminate()  # terminate an old qviewkit instance

    def _write_settings_dataset(self):
        self._settings = self._data_file.add_textlist('settings')
        settings = waf.get_instrument_settings(self._data_file.get_filepath())
        self._settings.append(settings)

    def measure_1D(self, rescan=True, web_visible=True):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started.
                If False, it will directly take the data from the VNA without waiting.
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'signal_analyzer_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_sig_analyzer()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=self.traces_names)
        print('recording trace...')
        sys.stdout.flush()

        qkit.flow.start()
        if rescan:
            if self.averaging_start_ready:
                self.sig_analyzer.start_measurement()
                ti = time()
                if self.progress_bar:
                    self._p = Progress_Bar(self.sig_analyzer.get_averages(),
                                           self.dirname,
                                           self.sig_analyzer.get_sweeptime())
                qkit.flow.sleep(.2)
                while not self.sig_analyzer.ready():
                    if time() - ti > self.sig_analyzer.get_sweeptime(
                            query=False):
                        if self.progress_bar: self._p.iterate()
                        ti = time()
                    qkit.flow.sleep(.2)
                if self.progress_bar:
                    while self._p.progr < self._p.max_it:
                        self._p.iterate()
            else:  # not tested!!!!!!
                self.sig_analyzer.avg_clear()
                if self.sig_analyzer.get_averages(
                ) == 1 or self.sig_analyzer.get_Average(
                ) == False:  # no averaging
                    if self.progress_bar:
                        self._p = Progress_Bar(
                            1, self.dirname, self.sig_analyzer.get_sweeptime())
                    qkit.flow.sleep(
                        self.sig_analyzer.get_sweeptime())  # wait single sweep
                    if self.progress_bar: self._p.iterate()
                else:  # with averaging
                    if self.progress_bar:
                        self._p = Progress_Bar(
                            self.sig_analyzer.get_averages(), self.dirname,
                            self.sig_analyzer.get_sweeptime())
                    if "avg_status" in self.sig_analyzer.get_function_names():
                        for a in range(self.sig_analyzer.get_averages()):
                            while self.sig_analyzer.avg_status() <= a:
                                qkit.flow.sleep(
                                    .2
                                )  # maybe one would like to adjust this at a later point
                            if self.progress_bar: self._p.iterate()
                    else:  # old style
                        for a in range(self.sig_analyzer.get_averages()):
                            qkit.flow.sleep(self.sig_analyzer.get_sweeptime()
                                            )  # wait single sweep time
                            if self.progress_bar: self._p.iterate()

        for i in range(self.num_traces):
            self._data[i].append(self.sig_analyzer.get_tracedata(i + 1))

        qkit.flow.end()
        self._end_measurement()

    def measure_2D(self, web_visible=True):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'frequency'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(len(self.x_vec),
                                   '2D signal analyzer sweep ' + self.dirname,
                                   self.sig_analyzer.get_sweeptime_averages())

        self._prepare_measurement_sig_analyzer()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""

        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=self.traces_names)
        self._measure()

    def measure_3D(self, web_visible=True):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec.
        sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = True
        self._scan_time = False

        self._measurement_object.measurement_func = 'measure_3D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = self.y_coordname
        self._measurement_object.z_axis = 'frequency'
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname + ', ' + self.y_coordname
        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(
            ',', '_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar:
            self._p = Progress_Bar(
                len(self.x_vec) * len(self.y_vec),
                '3D signal analyzer sweep ' + self.dirname,
                self.sig_analyzer.get_sweeptime_averages())
        self._prepare_measurement_sig_analyzer()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        """only middle point in freq array is plotted vs x and y"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(),
                                              datasets=self.traces_names)

        ### ???
        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []  # load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()

    def _measure(self):
        '''
        measures and plots the data depending on the measurement type.
        the measurement loops feature the setting of the objects and saving the data in the .h5 file.
        '''
        qkit.flow.start()
        try:
            """
            loop: x_obj with parameters from x_vec
            """
            for ix, x in enumerate(self.x_vec):
                self.x_set_obj(x)
                sleep(self.tdx)

                if self.log_function != None:
                    for i, f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))

                #### not tested
                if self._scan_3D:
                    for y in self.y_vec:
                        """
                        loop: y_obj with parameters from y_vec (only 3D measurement)
                        """
                        if (
                                np.min(
                                    np.abs(self.center_freqs[ix] - y *
                                           np.ones(len(self.center_freqs[ix])))
                                ) > self.span / 2.
                        ) and self.landscape:  # if point is not of interest (not close to one of the functions)
                            data = []
                            for i in range(self.num_traces):
                                data.append(np.zeros(int(self._nop)))
                        else:
                            self.y_set_obj(y)
                            sleep(self.tdy)
                            if self.averaging_start_ready:
                                self.sig_analyzer.start_measurement()
                                qkit.flow.sleep(
                                    .2
                                )  # just to make sure, the ready command does not *still* show ready
                                while not self.sig_analyzer.ready():
                                    qkit.flow.sleep(.2)
                            else:
                                self.sig_analyzer.avg_clear()
                                qkit.flow.sleep(self._sweeptime_averages)

                            # if "avg_status" in self.sig_analyzer.get_function_names():
                            #       while self.sig_analyzer.avg_status() < self.sig_analyzer.get_averages():
                            #            qkit.flow.sleep(.2) #maybe one would like to adjust this at a later point
                            """ measurement """
                            for i in range(self.num_traces):
                                data[i] = self.sig_analyzer.get_tracedata(i +
                                                                          1)
                                self._data[i].append(data[i])

                        if self.progress_bar:
                            self._p.iterate()
                        qkit.flow.sleep()
                    """
                    filling of value-box is done here.
                    after every y-loop the data is stored the next 2d structure
                    """
                    for i in range(self.num_traces):
                        self._data[i].next_matrix()

                if self._scan_2D:
                    if self.averaging_start_ready:
                        self.sig_analyzer.start_measurement()
                        qkit.flow.sleep(
                            .2
                        )  # just to make sure, the ready command does not *still* show ready
                        while not self.sig_analyzer.ready():
                            qkit.flow.sleep(.2)
                    else:
                        self.sig_analyzer.avg_clear()
                        qkit.flow.sleep(self._sweeptime_averages)
                    """ measurement """
                    for i in range(self.num_traces):
                        self._data[i].append(
                            self.sig_analyzer.get_tracedata(i + 1))

                    if self.progress_bar:
                        self._p.iterate()
                    qkit.flow.sleep()
        finally:
            self._end_measurement()
            qkit.flow.end()

    def _end_measurement(self):
        '''
        the data file is closed and filepath is printed
        '''
        print(self._data_file.get_filepath())
        # qviewkit.save_plots(self._data_file.get_filepath(),comment=self._plot_comment) #old version where we have to wait for the plots
        t = threading.Thread(
            target=qviewkit.save_plots,
            args=[self._data_file.get_filepath(), self._plot_comment])
        t.start()
        self._data_file.close_file()
        waf.close_log_file(self._log)
        self.dirname = None
        if self.averaging_start_ready: self.sig_analyzer.post_measurement()

    def delete_fit_function(self, n=None):
        '''
        delete single fit function n (with 0 being the first one generated) or the complete landscape for n not specified
        '''

        if n:
            self.landscape = np.delete(self.landscape, n, axis=0)
        else:
            self.landscape = None

    def plot_fit_function(self, num_points=100):
        '''
        try:
            x_coords = np.linspace(self.x_vec[0], self.x_vec[-1], num_points)
        except Exception as message:
            print 'no x axis information specified', message
            return
        '''
        if not qkit.module_available("matplotlib"):
            raise ImportError("matplotlib not found.")
        if self.landscape:
            for trace in self.landscape:
                try:
                    # plt.clear()
                    plt.plot(self.x_vec, trace)
                    plt.fill_between(self.x_vec,
                                     trace + float(self.span) / 2,
                                     trace - float(self.span) / 2,
                                     alpha=0.5)
                except Exception:
                    print('invalid trace...skip')
            plt.axhspan(self.y_vec[0],
                        self.y_vec[-1],
                        facecolor='0.5',
                        alpha=0.5)
            plt.show()
        else:
            print('No trace generated.')

    def set_span(self, span):
        self.span = span

    def get_span(self):
        return self.span

    def set_tdx(self, tdx):
        self.tdx = tdx

    def set_tdy(self, tdy):
        self.tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def f_parab(self, x, a, b, c):
        return a * (x - b)**2 + c

    def f_hyp(self, x, a, b, c):
        "hyperbolic function with the form y = sqrt[ a*(x-b)**2 + c ]"
        return np.sqrt(a * (x - b)**2 + c)

    def f_lin(self, x, a, b):
        return a * x + b

    def set_plot_comment(self, comment):
        '''
        Small comment to add at the end of plot pics for more information i.e. good for wiki entries.
        '''
        self._plot_comment = comment
Exemple #44
0
def update_sequence(ts, wfm_func, sample, iq = None, loop = False, drive = 'c:', path = '\\waveforms', reset = True, marker=None, markerfunc=None, ch2_amp = 2,chpair=1,awg= None):
    '''
        set awg to sequence mode and push a number of waveforms into the sequencer
        
        inputs:
        
        ts: array of times, len(ts) = #sequenzes
        wfm_func: waveform function usually generated via generate_waveform using ts[i]; this can be a touple of arrays (for channels 0,1, heterodyne mode) or a single array (homodyne mode)
        sample: sample object
        
        iq: Reference to iq mixer instrument. If None (default), the wfm will not be changed. Otherwise, the wfm will be converted via iq.convert()
        
        marker: marker array in the form [[ch1m1,ch1m2],[ch2m1,ch2m2]] and all entries arrays of sample length
        markerfunc: analog to wfm_func, set marker to None when used
        
        for the 6GS/s AWG, the waveform length must be divisible by 64
        for the 1.2GS/s AWG, it must be divisible by 4
        
        chpair: if you use the 4ch Tabor AWG as a single 5ch instrument, you can chose to take the second channel pair here (this can be either 1 or 2).
    '''
    qt.mstart()
    if awg==None:
        awg = sample.get_awg()
    clock = sample.get_clock()
    wfm_func2 = wfm_func
    if iq != None:
        wfm_func2 = lambda t, sample: iq.convert(wfm_func(t,sample))
    
    # create new sequence
    if reset:
        if "Tektronix" in awg.get_type():
            awg.set_runmode('SEQ')
            awg.set_seq_length(0)   #clear sequence, necessary?
            awg.set_seq_length(len(ts))
        elif "Tabor" in awg.get_type():
            awg.set('p%i_runmode'%chpair,'SEQ')
            awg.define_sequence(chpair*2-1,len(ts))
        
        
        
        #amplitude settings of analog output
        awg.set_ch1_offset(0)
        awg.set_ch2_offset(0)
        awg.set_ch1_amplitude(2)
        awg.set_ch2_amplitude(ch2_amp)

    #generate empty tuples
    wfm_samples_prev = [None,None]
    wfm_fn = [None,None]
    wfm_pn = [None,None]
    p = Progress_Bar(len(ts)*(2 if "Tektronix" in awg.get_type() else 1),'Load AWG')   #init progress bar
    
    #update all channels and times
    for ti, t in enumerate(ts):   #run through all sequences
        qt.msleep()
        wfm_samples = wfm_func2(t,sample)   #generate waveform
        if not isinstance(wfm_samples[0],(list, tuple, np.ndarray)):   #homodyne
            wfm_samples = [wfm_samples,np.zeros_like(wfm_samples, dtype=np.int8)]
        
        for chan in [0,1]:
            if markerfunc != None:   #use markerfunc
                try:
                    if markerfunc[chan][0] == None:
                        marker1 = np.zeros_like(wfm_samples, dtype=np.int8)[0]
                    else:
                        marker1 = markerfunc[chan][0](t,sample)
                    
                    if markerfunc[chan][1] == None:
                        marker2 = np.zeros_like(wfm_samples, dtype=np.int8)[0]
                    else:
                        marker2 = markerfunc[chan][1](t,sample)
                
                except TypeError:   #only one markerfunc given
                    marker1, marker2 = np.zeros_like(wfm_samples, dtype=np.int8)
                    if chan == 0:
                        marker1 = markerfunc(t,sample)
                    
            elif marker == None:   #fill up with zeros
                marker1, marker2 = np.zeros_like(wfm_samples, dtype=np.int8)
            else: #or set your own markers
                c_marker1, c_marker2 = marker[chan]
                marker1 = c_marker1[ti]
                marker2 = c_marker2[ti]
            
            if "Tektronix" in awg.get_type():
                wfm_fn[chan] = 'ch%d_t%05d'%(chan+1, ti) # filename is kept until changed
                if len(wfm_samples) == 1 and chan == 1:
                    wfm_pn[chan] = '%s%s\\%s'%(drive, path, np.zeros_like(wfm_fn[0]))   #create empty array
                else:
                    wfm_pn[chan] = '%s%s\\%s'%(drive, path, wfm_fn[chan])
                awg.wfm_send(wfm_samples[chan], marker1, marker2, wfm_pn[chan], clock)
                
                awg.wfm_import(wfm_fn[chan], wfm_pn[chan], 'WFM')
                
                # assign waveform to channel/time slot
                awg.wfm_assign(chan+1, ti+1, wfm_fn[chan])
                
                if loop:
                    awg.set_seq_loop(ti+1, np.infty)
            elif "Tabor" in awg.get_type():
                if chan == 0:
                    awg.wfm_send2(wfm_samples[0],wfm_samples[1],marker1,marker2,chpair*2-1+chan+1,ti+1)
                else: continue
            else:
                raise ValueError("AWG type not known")
            p.iterate()

        gc.collect()

    if reset and "Tektronix" in awg.get_type():
        # enable channels
        awg.set_ch1_status(True)
        awg.set_ch2_status(True)
        awg.set_seq_goto(len(ts), 1)
        awg.run()
        awg.wait(10,False)
    elif reset and "Tabor" in awg.get_type():
        # enable channels
        #awg.preset()
        awg.set_ch1_status(True)
        awg.set_ch2_status(True)
    qt.mend()
    return np.all([awg.get('ch%i_status'%i) for i in [1,2]])
Exemple #45
0
    def measure_1D(self, rescan = True, web_visible = True):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started. 
                If False, it will directly take the data from the VNA without waiting.
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'VNA_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath()) 
        print 'recording trace...'
        sys.stdout.flush()

        qt.mstart()
        if rescan:
            if self.averaging_start_ready:
                self.vna.start_measurement()
                ti = time()
                if self.progress_bar: self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
                qt.msleep(.2)
                while not self.vna.ready():
                    if time()-ti > self.vna.get_sweeptime(query=False):
                        if self.progress_bar: self._p.iterate()
                        ti = time()
                    qt.msleep(.2)
                if self.progress_bar:
                    while self._p.progr < self._p.max_it:
                        self._p.iterate()
            else:
                self.vna.avg_clear()
                if self.vna.get_averages() == 1 or self.vna.get_Average() == False:   #no averaging
                    if self.progress_bar:self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                    qt.msleep(self.vna.get_sweeptime())      #wait single sweep
                    if self.progress_bar: self._p.iterate()
                else:   #with averaging
                    if self.progress_bar: self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
                    if "avg_status" in self.vna.get_function_names():
                        for a in range(self.vna.get_averages()):
                            while self.vna.avg_status() <= a:
                                qt.msleep(.2) #maybe one would like to adjust this at a later point
                            if self.progress_bar: self._p.iterate()
                    else: #old style
                        for a in range(self.vna.get_averages()):
                            qt.msleep(self.vna.get_sweeptime())      #wait single sweep time
                            if self.progress_bar: self._p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        self._data_amp.append(data_amp)
        self._data_pha.append(data_pha)
        self._data_real.append(data_real)
        self._data_imag.append(data_imag)
        if self._fit_resonator:
            self._do_fit_resonator()

        qt.mend()
        self._end_measurement()
Exemple #46
0
    def monitor_depo(self):
        """
        Main sputter deposition monitoring function.

        Consider using the threaded version by calling start_depmon().

        Records the film resistance, thickness and deposition rate live during the sputter process.
        Stores everything into a h5 file.
        Provides measures to estimate the resulting resistance of the final film and thereby
        facilitates live adjustments to the sputter parameters.

        Note:
            set_duration and set_resolution should be called before to set the monitoring length and time resolution.
            set_filmparameters should be called before to provide the actual target values.
        """

        self._init_depmon()

        if self.progress_bar:
            self._p = Progress_Bar(
                self._duration / self._resolution,
                'EVAP_timetrace ' + self.dirname,
                self._resolution)  # FIXME: Doesn't make much sense...

        print('Monitoring deposition...')
        sys.stdout.flush()

        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(
                self._data_file.get_filepath(),
                datasets=['views/resistance_thickness'])

        try:
            """
            Initialize the data lists.
            """
            class MonData(object):
                resistance = np.array([])
                thickness = np.array([])

            mon_data = MonData()
            """
            Main loop:
            """
            mon_data.t0 = time.time(
            )  # note: Windows has limitations on time precision (about 16ms)
            for mon_data.it, _ in enumerate(self.x_vec):
                self._acquire(mon_data)

                if self.progress_bar:
                    self._p.iterate()

                # calculate the time when the next iteration should take place
                ti = mon_data.t0 + (float(mon_data.it) + 1) * self._resolution
                # wait until the total dt(iteration) has elapsed
                while time.time() < ti:
                    time.sleep(0.05)

        except KeyboardInterrupt:
            print('Monitoring interrupted by user.')

        except Exception as e:
            print(e)
            print(e.__doc__)
            print(e.message)

        finally:
            self._end_measurement()
Exemple #47
0
class spectrum(object):
    '''
    usage:

    m = spectrum(vna = vna1)

    m.set_x_parameters(arange(-0.05,0.05,0.01),'flux coil current',coil.set_current, unit = 'mA')
    m.set_y_parameters(arange(4e9,7e9,10e6),'excitation frequency',mw_src1.set_frequency, unit = 'Hz')

    m.gen_fit_function(...)      several times

    m.measure_XX()
    '''

    def __init__(self, IV_Device, exp_name = '', sample = None):

        self.IVD = IV_Device
        
        
        self.exp_name = exp_name
        self._sample = sample



        self.comment = ''
        self.dirname = None

        self.x_set_obj = None
        self.y_set_obj = None

        self.progress_bar = True

        self._plot_comment=""

        self.set_log_function()
        
        self.open_qviewkit = True
        self.qviewkit_singleInstance = False
        
        self._measurement_object = Measurement()
        self._measurement_object.measurement_type = 'transport'
        self._measurement_object.sample = self._sample
        
        self._qvk_process = False
        
        self.number_of_timetraces = 1   #relevant in time domain mode
        
        

    def set_log_function(self, func=None, name = None, unit = None, log_dtype = None):
        '''
        A function (object) can be passed to the measurement loop which is excecuted before every x iteration 
        but after executing the x_object setter in 2D measurements and before every line (but after setting 
        the x value) in 3D measurements.
        The return value of the function of type float or similar is stored in a value vector in the h5 file.

        Call without any arguments to delete all log functions. The timestamp is automatically saved.

        func: function object in list form
        name: name of logging parameter appearing in h5 file, default: 'log_param'
        unit: unit of logging parameter, default: ''
        log_dtype: h5 data type, default: 'f' (float32)
        '''

        if name == None:
            try:
                name = ['log_param']*len(func)
            except Exception:
                name = None
        if unit == None:
            try:
                unit = ['']*len(func)
            except Exception:
                unit = None
        if log_dtype == None:
            try:
                log_dtype = ['f']*len(func)
            except Exception:
                log_dtype = None

        self.log_function = []
        self.log_name = []
        self.log_unit = []
        self.log_dtype = []

        if func != None:
            for i,f in enumerate(func):
                self.log_function.append(f)
                self.log_name.append(name[i])
                self.log_unit.append(unit[i])
                self.log_dtype.append(log_dtype[i])

    def set_x_parameters(self, x_vec, x_coordname, x_set_obj, x_unit = ""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        x_vec (array): conains the sweeping values
        x_coordname (string)
        x_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        x_unit (string): optional
        '''
        self.x_vec = x_vec
        self.x_coordname = x_coordname
        self.x_set_obj = x_set_obj
        self.delete_fit_function()
        self.x_unit = x_unit

    def set_y_parameters(self, y_vec, y_coordname, y_set_obj, y_unit = ""):
        '''
        Sets parameters for sweep. In a 3D measurement, the x-parameters will be the "outer" sweep.
        For every x value all y values are swept
        Input:
        y_vec (array): contains the sweeping values
        y_coordname (string)
        y_instrument (obj): callable object to execute with x_vec-values (i.e. vna.set_power())
        y_unit (string): optional
        '''
        self.y_vec = y_vec
        self.y_coordname = y_coordname
        self.y_set_obj = y_set_obj
        self.delete_fit_function()
        self.y_unit = y_unit

        def set_sweep_type(self, sweep_type = 1):
        '''
        Sets the  sweep type, in the moment only simple sweep types are defined: 
        Input:
        sweep_type:
            0: single sweep START -> END 
            1: double sweep START -> END -> START (default)
            2: triple sweep START -> END -> START -> -END
            3: quad sweep   START -> END -> START -> -END -> START
        
        '''
        self.IV_sweep_type = sweep_type


    def _prepare_measurement_IVD(self):
        '''
        all the relevant settings from the vna are updated and called
        '''

        self.IVD.get_all()
        #ttip.get_temperature() 
        # bias mode is either  current=0 or voltage=1
        self._bias_mode = self.IVD.get_bias_mode()
        
        self._nop = self.IVD.get_nop()
        self._sweeptime_averages = self.IVD.get_sweeptime_averages()
        #self._freqpoints = self.IVD.get_freqpoints()

        if self.averaging_start_ready: self.vna.pre_measurement()

    def _prepare_measurement_file(self):
        '''
        creates the output .h5-file with distinct dataset structures for each measurement type.
        at this point all measurement parameters are known and put in the output file
        '''

        self._data_file = hdf.Data(name=self._file_name)
        self._measurement_object.uuid = self._data_file._uuid
        self._measurement_object.hdf_relpath = self._data_file._relpath
        self._measurement_object.instruments = qt.instruments.get_instruments()

        self._measurement_object.save()
        self._mo = self._data_file.add_textlist('measurement')
        self._mo.append(self._measurement_object.get_JSON())

        # write logfile and instrument settings
        self._write_settings_dataset()
        self._log = waf.open_log_file(self._data_file.get_filepath())

        #if not self._scan_time:
        #    self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
        #    self._data_freq.add(self._freqpoints)

        
        if self._scan_1D:
            if self._bias_mode:# current bias
                #self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
                for st in range(self.sweep_type):
                    self._data_I[st] = self._data_file.add_value_vector('I_'+str(st), unit = 'A', save_timestamp = True)
                    self._data_V[st] = self._data_file.add_value_vector('V_'+str(st), x = self._data_I, unit = 'V', save_timestamp = True)
                

        if self._scan_2D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_freq, unit = 'arb. unit', save_timestamp = True)
            self._data_pha = self._data_file.add_value_matrix('phase', x = self._data_x, y = self._data_freq, unit='rad', save_timestamp = True)

            if self.log_function != None:   #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(self._data_file.add_value_vector(self.log_name[i], x = self._data_x, unit = self.log_unit[i], dtype=self.log_dtype[i]))

            if self._nop < 10:
                """creates view: plot middle point vs x-parameter, for qubit measurements"""
                self._data_amp_mid = self._data_file.add_value_vector('amplitude_midpoint', unit = 'arb. unit', x = self._data_x, save_timestamp = True)
                self._data_pha_mid = self._data_file.add_value_vector('phase_midpoint', unit = 'rad', x = self._data_x, save_timestamp = True)
                #self._view = self._data_file.add_view("amplitude vs. " + self.x_coordname, x = self._data_x, y = self._data_amp[self._nop/2])

        if self._scan_3D:
            self._data_x = self._data_file.add_coordinate(self.x_coordname, unit = self.x_unit)
            self._data_x.add(self.x_vec)
            self._data_y = self._data_file.add_coordinate(self.y_coordname, unit = self.y_unit)
            self._data_y.add(self.y_vec)
            
            if self._nop == 0:   #saving in a 2D matrix instead of a 3D box HR: does not work yet !!! test things before you put them online.
                self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_y,  unit = 'arb. unit',   save_timestamp = False)
                self._data_pha = self._data_file.add_value_matrix('phase',     x = self._data_x, y = self._data_y,  unit = 'rad', save_timestamp = False)
            else:
                self._data_amp = self._data_file.add_value_box('amplitude', x = self._data_x, y = self._data_y, z = self._data_freq, unit = 'arb. unit', save_timestamp = False)
                self._data_pha = self._data_file.add_value_box('phase', x = self._data_x, y = self._data_y, z = self._data_freq, unit = 'rad', save_timestamp = False)
                
            if self.log_function != None:   #use logging
                self._log_value = []
                for i in range(len(self.log_function)):
                    self._log_value.append(self._data_file.add_value_vector(self.log_name[i], x = self._data_x, unit = self.log_unit[i], dtype=self.log_dtype[i]))

        if self._scan_time:
            self._data_freq = self._data_file.add_coordinate('frequency', unit = 'Hz')
            self._data_freq.add([self.vna.get_centerfreq()])
            
            self._data_time = self._data_file.add_coordinate('time', unit = 's')
            self._data_time.add(np.arange(0,self._nop,1)*self.vna.get_sweeptime()/(self._nop-1))
            
            self._data_x = self._data_file.add_coordinate('trace_number', unit = '')
            self._data_x.add(np.arange(0, self.number_of_timetraces, 1))
            
            self._data_amp = self._data_file.add_value_matrix('amplitude', x = self._data_x, y = self._data_time, unit = 'lin. mag.', save_timestamp = False)
            self._data_pha = self._data_file.add_value_matrix('phase', x = self._data_x, y = self._data_time, unit = 'rad.', save_timestamp = False)
                    
        if self.comment:
            self._data_file.add_comment(self.comment)
            
        if self.qviewkit_singleInstance and self.open_qviewkit and self._qvk_process:
            self._qvk_process.terminate() #terminate an old qviewkit instance

    def _write_settings_dataset(self):
        self._settings = self._data_file.add_textlist('settings')
        settings = waf.get_instrument_settings(self._data_file.get_filepath())
        self._settings.append(settings)

    def measure_1D(self, rescan = True, web_visible = True):
        '''
        measure method to record a single (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        rescan: If True (default), the averages on the VNA are cleared and a new measurement is started. 
                If False, it will directly take the data from the VNA without waiting.
        '''
        self._scan_1D = True
        self._scan_2D = False
        self._scan_3D = False
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_1D'
        self._measurement_object.x_axis = 'frequency'
        self._measurement_object.y_axis = ''
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = 'IVD_tracedata'
        self._file_name = self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name
            
        # prepare storage
        self._prepare_measurement_IVD()
        self._prepare_measurement_file()


        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self.open_qviewkit:
            self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['I_0', 'V_0'])
        print('recording trace...')
        sys.stdout.flush()

        qt.mstart()
        if rescan:
            if self.averaging_start_ready:
                self.vna.start_measurement()
                ti = time()
                if self.progress_bar: self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
                qt.msleep(.2)
                while not self.vna.ready():
                    if time()-ti > self.vna.get_sweeptime(query=False):
                        if self.progress_bar: self._p.iterate()
                        ti = time()
                    qt.msleep(.2)
                if self.progress_bar:
                    while self._p.progr < self._p.max_it:
                        self._p.iterate()
            else:
                self.vna.avg_clear()
                if self.vna.get_averages() == 1 or self.vna.get_Average() == False:   #no averaging
                    if self.progress_bar:self._p = Progress_Bar(1,self.dirname,self.vna.get_sweeptime())
                    qt.msleep(self.vna.get_sweeptime())      #wait single sweep
                    if self.progress_bar: self._p.iterate()
                else:   #with averaging
                    if self.progress_bar: self._p = Progress_Bar(self.vna.get_averages(),self.dirname,self.vna.get_sweeptime())
                    if "avg_status" in self.vna.get_function_names():
                        for a in range(self.vna.get_averages()):
                            while self.vna.avg_status() <= a:
                                qt.msleep(.2) #maybe one would like to adjust this at a later point
                            if self.progress_bar: self._p.iterate()
                    else: #old style
                        for a in range(self.vna.get_averages()):
                            qt.msleep(self.vna.get_sweeptime())      #wait single sweep time
                            if self.progress_bar: self._p.iterate()

        data_amp, data_pha = self.vna.get_tracedata()
        data_real, data_imag = self.vna.get_tracedata('RealImag')

        self._data_amp.append(data_amp)
        self._data_pha.append(data_pha)
        self._data_real.append(data_real)
        self._data_imag.append(data_imag)
        if self._fit_resonator:
            self._do_fit_resonator()

        qt.mend()
        self._end_measurement()
"""
    def measure_2D(self, web_visible = True):
        '''
        measure method to record a (averaged) VNA trace, S11 or S21 according to the setting on the VNA
        for all parameters x_vec in x_obj
        '''

        if not self.x_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = True
        self._scan_3D = False
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_2D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = 'frequency'
        self._measurement_object.z_axis = ''
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname
        self._file_name = '2D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar: self._p = Progress_Bar(len(self.x_vec),'2D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()

        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        if self._nop < 10:
            if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude_midpoint', 'phase_midpoint'])
        else:
            if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())
        self._measure()


    def measure_3D(self, web_visible = True):
        '''
        measure full window of vna while sweeping x_set_obj and y_set_obj with parameters x_vec/y_vec. sweep over y_set_obj is the inner loop, for every value x_vec[i] all values y_vec are measured.

        optional: measure method to perform the measurement according to landscape, if set
        self.span is the range (in units of the vertical plot axis) data is taken around the specified funtion(s)
        note: make sure to have properly set x,y vectors before generating traces
        '''
        if not self.x_set_obj or not self.y_set_obj:
            logging.error('axes parameters not properly set...aborting')
            return
        self._scan_1D = False
        self._scan_2D = False
        self._scan_3D = True
        self._scan_time = False
        
        self._measurement_object.measurement_func = 'measure_3D'
        self._measurement_object.x_axis = self.x_coordname
        self._measurement_object.y_axis = self.y_coordname
        self._measurement_object.z_axis = 'frequency'
        self._measurement_object.web_visible = web_visible

        if not self.dirname:
            self.dirname = self.x_coordname + ', ' + self.y_coordname
        self._file_name = '3D_' + self.dirname.replace(' ', '').replace(',','_')
        if self.exp_name:
            self._file_name += '_' + self.exp_name

        if self.progress_bar: self._p = Progress_Bar(len(self.x_vec)*len(self.y_vec),'3D VNA sweep '+self.dirname,self.vna.get_sweeptime_averages())

        self._prepare_measurement_vna()
        self._prepare_measurement_file()
        """opens qviewkit to plot measurement, amp and pha are opened by default"""
        """only middle point in freq array is plotted vs x and y"""
        if self.open_qviewkit: self._qvk_process = qviewkit.plot(self._data_file.get_filepath(), datasets=['amplitude', 'phase'])
        if self._fit_resonator:
            self._resonator = resonator(self._data_file.get_filepath())

        if self.landscape:
            self.center_freqs = np.array(self.landscape).T
        else:
            self.center_freqs = []     #load default sequence
            for i in range(len(self.x_vec)):
                self.center_freqs.append([0])

        self._measure()
"""        
        

    def _measure(self):
        '''
        measures and plots the data depending on the measurement type.
        the measurement loops feature the setting of the objects and saving the data in the .h5 file.
        '''
        qt.mstart()
        try:
            """
            loop: x_obj with parameters from x_vec
            """
            for ix, x in enumerate(self.x_vec):
                self.x_set_obj(x)
                sleep(self.tdx)
                
                if self.log_function != None:
                    for i,f in enumerate(self.log_function):
                        self._log_value[i].append(float(f()))

                if self._scan_3D:
                    for y in self.y_vec:
                        """
                        loop: y_obj with parameters from y_vec (only 3D measurement)
                        """
                        if (np.min(np.abs(self.center_freqs[ix]-y*np.ones(len(self.center_freqs[ix])))) > self.span/2.) and self.landscape:    #if point is not of interest (not close to one of the functions)
                            data_amp = np.zeros(int(self._nop))
                            data_pha = np.zeros(int(self._nop))      #fill with zeros
                        else:
                            self.y_set_obj(y)
                            sleep(self.tdy)
                            if self.averaging_start_ready:
                                self.vna.start_measurement()
                                qt.msleep(.2) #just to make sure, the ready command does not *still* show ready
                                while not self.vna.ready():
                                    qt.msleep(.2)
                            else:
                                self.vna.avg_clear()
                                qt.msleep(self._sweeptime_averages)
                                
                            #if "avg_status" in self.vna.get_function_names():
                            #       while self.vna.avg_status() < self.vna.get_averages():
                            #            qt.msleep(.2) #maybe one would like to adjust this at a later point
                            
                            """ measurement """
                            data_amp, data_pha = self.vna.get_tracedata()

                        if self._nop == 0: # this does not work yet.
                           print data_amp[0], data_amp, self._nop
                           self._data_amp.append(data_amp[0])
                           self._data_pha.append(data_pha[0])
                        else:
                           self._data_amp.append(data_amp)
                           self._data_pha.append(data_pha)
                        if self._fit_resonator:
                            self._do_fit_resonator()
                        if self.progress_bar:
                            self._p.iterate()
                        qt.msleep()
                    """
                    filling of value-box is done here.
                    after every y-loop the data is stored the next 2d structure
                    """
                    self._data_amp.next_matrix()
                    self._data_pha.next_matrix()

                if self._scan_2D:
                    if self.averaging_start_ready:
                        self.vna.start_measurement()
                        qt.msleep(.2) #just to make sure, the ready command does not *still* show ready
                        while not self.vna.ready():
                            qt.msleep(.2)
                    else:
                        self.vna.avg_clear()
                        qt.msleep(self._sweeptime_averages)
                    """ measurement """
                    data_amp, data_pha = self.vna.get_tracedata()
                    self._data_amp.append(data_amp)
                    self._data_pha.append(data_pha)
                    if self._nop < 10:
                        #print data_amp[self._nop/2]
                        self._data_amp_mid.append(float(data_amp[self._nop/2]))
                        self._data_pha_mid.append(float(data_pha[self._nop/2]))
                        
                    if self._fit_resonator:
                        self._do_fit_resonator()
                    if self.progress_bar:
                        self._p.iterate()
                    qt.msleep()
        except Exception as e:
            print e.__doc__
            print e.message        
        finally:
            self._end_measurement()
            qt.mend()

    def _end_measurement(self):
        '''
        the data file is closed and filepath is printed
        '''
        print self._data_file.get_filepath()
        #qviewkit.save_plots(self._data_file.get_filepath(),comment=self._plot_comment) #old version where we have to wait for the plots
        t = threading.Thread(target=qviewkit.save_plots,args=[self._data_file.get_filepath(),self._plot_comment])
        t.start()
        self._data_file.close_file()
        waf.close_log_file(self._log)
        self.dirname = None
        


    def set_span(self, span):
        self.span = span

    def get_span(self):
        return self.span

    def set_tdx(self, tdx):
        self.tdx = tdx

    def set_tdy(self, tdy):
        self.tdy = tdy

    def get_tdx(self):
        return self.tdx

    def get_tdy(self):
        return self.tdy

    def f_parab(self,x,a,b,c):
        return a*(x-b)**2+c

    def f_hyp(self,x,a,b,c):
        "hyperbolic function with the form y = sqrt[ a*(x-b)**2 + c ]"
        return np.sqrt(a*(x-b)**2+c)

    def set_plot_comment(self, comment):
        '''
        Small comment to add at the end of plot pics for more information i.e. good for wiki entries.
        '''
        self._plot_comment=comment