Beispiel #1
0
    def __init__(self,
                 name: str,
                 address: str,
                 terminator: str = '\n',
                 **kwargs: Any):
        """
        Create an instance of the instrument.

        Args:
            name: Name of the instrument instance
            address: Visa-resolvable instrument address.
        """
        super().__init__(name, address, terminator=terminator, **kwargs)

        self._measurement_pair = MeasurementPair(
            "CPD", ("capacitance", "dissipation_factor"), ("F", ""))

        self.add_parameter(
            "frequency",
            get_cmd=":FREQuency?",
            set_cmd=":FREQuency {}",
            get_parser=float,
            unit="Hz",
            vals=Numbers(20, 2E6),
            docstring="Gets and sets the frequency for normal measurement.")

        self.add_parameter(
            "current_level",
            get_cmd=":CURRent:LEVel?",
            set_cmd=":CURRent:LEVel {}",
            get_parser=float,
            unit="A",
            vals=Numbers(0, 0.1),
            docstring="Gets and sets the current level for measurement signal."
        )

        self.add_parameter(
            "voltage_level",
            get_cmd=":VOLTage:LEVel?",
            set_cmd=":VOLTage:LEVel {}",
            get_parser=float,
            unit="V",
            vals=Numbers(0, 20),
            docstring="Gets and sets the voltage level for measurement signal."
        )

        self.add_parameter("measurement_function",
                           get_cmd=":FUNCtion:IMPedance?",
                           set_cmd=self._set_measurement)

        self.add_parameter(
            "range",
            get_cmd=":FUNCtion:IMPedance:RANGe?",
            set_cmd=":FUNCtion:IMPedance:RANGe {}",
            unit='Ohm',
            vals=Enum(0.1, 1, 10, 100, 300, 1000, 3000, 10000, 30000, 100000),
            docstring="Selects the impedance measurement range, also turns "
            "the auto range function OFF.")

        self.add_submodule("_correction", Correction4980A(self, "correction"))

        self.connect_message()
Beispiel #2
0
    def __init__(self, parent: 'GS200', name: str, present: bool) -> None:
        super().__init__(parent, name)

        self.present = present

        # Start off with all disabled
        self._enabled = False
        self._output = False
        # Set up monitoring parameters
        if present:
            self.add_parameter('enabled',
                               label='Measurement Enabled',
                               get_cmd=self.state,
                               set_cmd=lambda x: self.on() if x else self.off(),
                               val_mapping={
                                    'off': 0,
                                    'on': 1,
                               })

            # Note: Measurement will only run if source and measurement is enabled.
            self.add_parameter('measure',
                               label='<unset>', unit='V/I',
                               get_cmd=self._get_measurement)

            self.add_parameter('NPLC',
                               label='NPLC',
                               unit='1/LineFreq',
                               vals=Ints(1, 25),
                               set_cmd=':SENS:NPLC {}',
                               set_parser=int,
                               get_cmd=':SENS:NPLC?',
                               get_parser=float_round)
            self.add_parameter('delay',
                               label='Measurement Delay',
                               unit='ms',
                               vals=Ints(0, 999999),
                               set_cmd=':SENS:DEL {}',
                               set_parser=int,
                               get_cmd=':SENS:DEL?',
                               get_parser=float_round)
            self.add_parameter('trigger',
                               label='Trigger Source',
                               set_cmd=':SENS:TRIG {}',
                               get_cmd=':SENS:TRIG?',
                               val_mapping={
                                    'READY': 'READ',
                                    'READ': 'READ',
                                    'TIMER': 'TIM',
                                    'TIM': 'TIM',
                                    'COMMUNICATE': 'COMM',
                                    'IMMEDIATE': 'IMM',
                                    'IMM': 'IMM'
                               })
            self.add_parameter('interval',
                               label='Measurement Interal',
                               unit='s',
                               vals=Numbers(0.1, 3600),
                               set_cmd=':SENS:INT {}',
                               set_parser=float,
                               get_cmd=':SENS:INT?',
                               get_parser=float)
Beispiel #3
0
    def __init__(self, name, alazar_name, **kwargs):
        self.number_of_channels = 2
        self.awgx = None
        self.awgy = None

        # make a call to the parent class and by extension,
        # create the parameter structure of this class
        super().__init__(name, alazar_name, **kwargs)

        self.add_parameter(name='acquisition', parameter_class=IQMagPhase)
        self.add_parameter('x_start',
                           parameter_class=ManualParameter,
                           label='Sweep x start voltage',
                           unit='V',
                           vals=Numbers(-10, 10))
        self.add_parameter('x_end',
                           parameter_class=ManualParameter,
                           label='Sweep x end voltage',
                           unit='V',
                           vals=Numbers(-10, 10))
        self.add_parameter(
            'x_npts',
            parameter_class=ManualParameter,
            label='Number of point x (needs to be multiple of 128)',
            unit=None,
            vals=Numbers(1, 10000))
        self.add_parameter('y_start',
                           parameter_class=ManualParameter,
                           label='Sweep x end voltage',
                           unit='V',
                           vals=Numbers(-10, 10))
        self.add_parameter('y_end',
                           parameter_class=ManualParameter,
                           label='Sweep x end voltage',
                           unit='V',
                           vals=Numbers(-10, 10))
        self.add_parameter('y_npts',
                           parameter_class=ManualParameter,
                           label='Number of point x',
                           unit=None,
                           vals=Numbers(1, 10000))
        self.add_parameter('sample_rate',
                           parameter_class=ManualParameter,
                           initial_value=500000.,
                           label='Sample rate',
                           unit=None,
                           vals=Numbers(1, 250e6))
        self.add_parameter('input_coupling',
                           parameter_class=ManualParameter,
                           initial_value='DC',
                           label='Coupling',
                           unit=None,
                           vals=Enum('DC', 'AC'))
        self.add_parameter('input_range',
                           parameter_class=ManualParameter,
                           initial_value=2.,
                           label='Range',
                           unit=None,
                           vals=Enum(0.2, 0.4, 0.8, 2., 4., 8, 16))
        self.add_parameter('impedance',
                           parameter_class=ManualParameter,
                           initial_value=50,
                           label='Impedance',
                           unit=None,
                           vals=Enum(50, 1000000))
Beispiel #4
0
    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, **kwargs)

        # Reference and phase
        self.add_parameter('phase',
                           label='Phase',
                           get_cmd='PHAS?',
                           get_parser=float,
                           set_cmd='PHAS {:.2f}',
                           unit='deg',
                           vals=Numbers(min_value=-360, max_value=729.99))

        self.add_parameter('reference_source',
                           label='Reference source',
                           get_cmd='FMOD?',
                           set_cmd='FMOD {}',
                           val_mapping={
                               'external': 0,
                               'internal': 1,
                           })

        self.add_parameter('frequency',
                           label='Frequency',
                           get_cmd='FREQ?',
                           get_parser=float,
                           set_cmd='FREQ {:.4f}',
                           unit='Hz',
                           vals=Numbers(min_value=1e-3, max_value=102e3))

        self.add_parameter('ext_trigger',
                           label='External trigger',
                           get_cmd='RSLP?',
                           set_cmd='RSLP {}',
                           val_mapping={
                               'sine': 0,
                               'TTL rising': 1,
                               'TTL falling': 2,
                           })

        self.add_parameter('harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=19999))

        self.add_parameter('amplitude',
                           label='Amplitude',
                           get_cmd='SLVL?',
                           get_parser=float,
                           set_cmd='SLVL {:.3f}',
                           unit='V',
                           vals=Numbers(min_value=0.004, max_value=5.000))

        # Input and filter
        self.add_parameter('input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           get_parser=self._get_input_config,
                           set_cmd='ISRC {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_CONFIG_TO_N.keys()))

        self.add_parameter('input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1,
                           })

        self.add_parameter('input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'AC': 0,
                               'DC': 1,
                           })

        self.add_parameter('notch_filter',
                           label='Notch filter',
                           get_cmd='ILIN?',
                           set_cmd='ILIN {}',
                           val_mapping={
                               'off': 0,
                               'line in': 1,
                               '2x line in': 2,
                               'both': 3,
                           })

        # Gain and time constant
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SENS?',
                           set_cmd='SENS {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity)

        self.add_parameter('reserve',
                           label='Reserve',
                           get_cmd='RMOD?',
                           set_cmd='RMOD {}',
                           val_mapping={
                               'high': 0,
                               'normal': 1,
                               'low noise': 2,
                           })

        self.add_parameter('time_constant',
                           label='Time constant',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           unit='s',
                           val_mapping={
                               10e-6: 0,
                               30e-6: 1,
                               100e-6: 2,
                               300e-6: 3,
                               1e-3: 4,
                               3e-3: 5,
                               10e-3: 6,
                               30e-3: 7,
                               100e-3: 8,
                               300e-3: 9,
                               1: 10,
                               3: 11,
                               10: 12,
                               30: 13,
                               100: 14,
                               300: 15,
                               1e3: 16,
                               3e3: 17,
                               10e3: 18,
                               30e3: 19,
                           })

        self.add_parameter('filter_slope',
                           label='Filter slope',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           unit='dB/oct',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3,
                           })

        self.add_parameter('sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        def parse_offset_get(s):
            parts = s.split(',')

            return float(parts[0]), int(parts[1])

        # TODO: Parameters that can be set with multiple arguments
        # For the OEXP command for example two arguments are needed
        self.add_parameter('X_offset',
                           get_cmd='OEXP? 1',
                           get_parser=parse_offset_get)

        self.add_parameter('Y_offset',
                           get_cmd='OEXP? 2',
                           get_parser=parse_offset_get)

        self.add_parameter('R_offset',
                           get_cmd='OEXP? 3',
                           get_parser=parse_offset_get)

        # Aux input/output
        for i in [1, 2, 3, 4]:
            self.add_parameter('aux_in{}'.format(i),
                               label='Aux input {}'.format(i),
                               get_cmd='OAUX? {}'.format(i),
                               get_parser=float,
                               unit='V')

            self.add_parameter('aux_out{}'.format(i),
                               label='Aux output {}'.format(i),
                               get_cmd='AUXV? {}'.format(i),
                               get_parser=float,
                               set_cmd='AUXV {0}, {{}}'.format(i),
                               unit='V')

        # Setup
        self.add_parameter('output_interface',
                           label='Output interface',
                           get_cmd='OUTX?',
                           set_cmd='OUTX {}',
                           val_mapping={
                               'RS232': '0\n',
                               'GPIB': '1\n',
                           })

        # Auto functions
        self.add_function('auto_gain', call_cmd='AGAN')
        self.add_function('auto_reserve', call_cmd='ARSV')
        self.add_function('auto_phase', call_cmd='APHS')
        self.add_function('auto_offset',
                          call_cmd='AOFF {0}',
                          args=[Enum(1, 2, 3)])

        # Data transfer
        self.add_parameter('X', get_cmd='OUTP? 1', get_parser=float, unit='V')

        self.add_parameter('Y', get_cmd='OUTP? 2', get_parser=float, unit='V')

        self.add_parameter('R', get_cmd='OUTP? 3', get_parser=float, unit='V')

        self.add_parameter('P',
                           get_cmd='OUTP? 4',
                           get_parser=float,
                           unit='deg')

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        # Initialize the proper units of the outputs and sensitivities
        self.input_config()

        self.connect_message()
Beispiel #5
0
    def __init__(self,
                 name: str,
                 address: str,
                 # Set frequency ranges
                 min_freq: Union[int, float], max_freq: Union[int, float],
                 # Set power ranges
                 min_power: Union[int, float], max_power: Union[int, float],
                 nports: int, # Number of ports on the PNA
                 **kwargs: Any) -> None:
        super().__init__(name, address, terminator='\n', **kwargs)
        self.min_freq = min_freq
        self.max_freq = max_freq

        #Ports
        ports = ChannelList(self, "PNAPorts", PNAPort)
        for port_num in range(1, nports+1):
            port = PNAPort(self, f"port{port_num}", port_num,
                           min_power, max_power)
            ports.append(port)
            self.add_submodule(f"port{port_num}", port)
        ports.lock()
        self.add_submodule("ports", ports)

        # Drive power
        self.add_parameter('power',
                           label='Power',
                           get_cmd='SOUR:POW?',
                           get_parser=float,
                           set_cmd='SOUR:POW {:.2f}',
                           unit='dBm',
                           vals=Numbers(min_value=min_power,
                                        max_value=max_power))

        # IF bandwidth
        self.add_parameter('if_bandwidth',
                           label='IF Bandwidth',
                           get_cmd='SENS:BAND?',
                           get_parser=float,
                           set_cmd='SENS:BAND {:.2f}',
                           unit='Hz',
                           vals=Numbers(min_value=1, max_value=15e6))

        # Number of averages (also resets averages)
        self.add_parameter('averages_enabled',
                           label='Averages Enabled',
                           get_cmd="SENS:AVER?",
                           set_cmd="SENS:AVER {}",
                           val_mapping={True: '1', False: '0'})
        self.add_parameter('averages',
                           label='Averages',
                           get_cmd='SENS:AVER:COUN?',
                           get_parser=int,
                           set_cmd='SENS:AVER:COUN {:d}',
                           unit='',
                           vals=Numbers(min_value=1, max_value=65536))
        # RF OUT -> Turns the VNA ON/OFF

        self.add_parameter('rf_out',
                           label='RF Out',
                           get_cmd="OUTP:STAT?",
                           set_cmd="OUTP:STAT {}",
                           val_mapping={True: '1', False: '0'})


        # Setting frequency range
        self.add_parameter('start',
                           label='Start Frequency',
                           get_cmd='SENS:FREQ:STAR?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:STAR {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))
        self.add_parameter('stop',
                           label='Stop Frequency',
                           get_cmd='SENS:FREQ:STOP?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:STOP {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))
        self.add_parameter('center',
                           label='Center Frequency',
                           get_cmd='SENS:FREQ:CENT?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:CENT {}',
                           unit='Hz',
                           vals=Numbers(min_value=min_freq,
                                        max_value=max_freq))
        self.add_parameter('span',
                           label='Frequency Span',
                           get_cmd='SENS:FREQ:SPAN?',
                           get_parser=float,
                           set_cmd='SENS:FREQ:SPAN {}',
                           unit='Hz',
                           vals=Numbers(min_value=0,
                                        max_value=max_freq))

        # Number of points in a sweep
        self.add_parameter('points',
                           label='Points',
                           get_cmd='SENS:SWE:POIN?',
                           get_parser=int,
                           set_cmd='SENS:SWE:POIN {}',
                           unit='',
                           vals=Numbers(min_value=1, max_value=100001))

        # Electrical delay
        self.add_parameter('electrical_delay',
                           label='Electrical Delay',
                           get_cmd='CALC:CORR:EDEL:TIME?',
                           get_parser=float,
                           set_cmd='CALC:CORR:EDEL:TIME {:.6e}',
                           unit='s',
                           vals=Numbers(min_value=0, max_value=100000))

        # Sweep Time
        self.add_parameter('sweep_time',
                           label='Time',
                           get_cmd='SENS:SWE:TIME?',
                           get_parser=float,
                           unit='s',
                           vals=Numbers(0, 1e6))
        # Sweep Mode
        self.add_parameter('sweep_mode',
                           label='Mode',
                           get_cmd='SENS:SWE:MODE?',
                           set_cmd='SENS:SWE:MODE {}',
                           vals=Enum("HOLD", "CONT", "GRO", "SING"))
        # Group trigger count
        self.add_parameter('group_trigger_count',
                           get_cmd="SENS:SWE:GRO:COUN?",
                           get_parser=int,
                           set_cmd="SENS:SWE:GRO:COUN {}",
                           vals=Ints(1, 2000000))
        # Trigger Source
        self.add_parameter('trigger_source',
                           get_cmd="TRIG:SOUR?",
                           set_cmd="TRIG:SOUR {}",
                           vals=Enum("EXT", "IMM", "MAN"))

        # Traces
        self.add_parameter('active_trace',
                           label='Active Trace',
                           get_cmd="CALC:PAR:MNUM?",
                           get_parser=int,
                           set_cmd="CALC:PAR:MNUM {}",
                           vals=Numbers(min_value=1, max_value=24))
        # Note: Traces will be accessed through the traces property which
        # updates the channellist to include only active trace numbers
        self._traces = ChannelList(self, "PNATraces", PNATrace)
        self.add_submodule("traces", self._traces)
        # Add shortcuts to first trace
        trace1 = self.traces[0]
        params = trace1.parameters
        if not isinstance(params, dict):
            raise RuntimeError(f"Expected trace.parameters to be a dict got "
                               f"{type(params)}")
        for param in params.values():
            self.parameters[param.name] = param
        # And also add a link to run sweep
        self.run_sweep = trace1.run_sweep
        # Set this trace to be the default (it's possible to end up in a
        # situation where no traces are selected, causing parameter snapshots
        # to fail)
        self.active_trace(trace1.trace_num)

        # Set auto_sweep parameter
        # If we want to return multiple traces per setpoint without sweeping
        # multiple times, we should set this to false
        self.add_parameter('auto_sweep',
                           label='Auto Sweep',
                           set_cmd=None,
                           get_cmd=None,
                           vals=Bool(),
                           initial_value=True)

        # A default output format on initialisation
        self.write('FORM REAL,32')
        self.write('FORM:BORD NORM')

        self.connect_message()
Beispiel #6
0
    def __init__(self, name, address, reset=False, **kwargs):
        super().__init__(name, address, terminator='\n', **kwargs)

        model = self.get_idn()['model']

        models = ['DG4202',  'DG4162',   'DG4102',   'DG4062']

        if model in models:
            i = models.index(model)

            sine_freq = [200e6, 160e6, 100e6, 60e6][i]
            square_freq = [60e6, 50e6, 40e6, 25e6][i]
            ramp_freq = [5e6, 4e6, 3e6, 1e6][i]
            pulse_freq = [50e6, 40e6, 25e6, 15e6][i]
            harmonic_freq = [100e6, 80e6, 50e6, 30e6][i]
            arb_freq = [50e6, 40e6, 25e6, 15e6][i]
        else:
            raise KeyError('Model code ' + model + ' is not recognized')

        on_off_map = {True: 'ON', False: 'OFF'}

        # Counter
        self.add_parameter('counter_attenuation',
                           get_cmd='COUN:ATT?',
                           set_cmd='COUN:ATT {}',
                           val_mapping={1: '1X', 10: '10X'})

        self.add_function('auto_counter', call_cmd='COUN:AUTO')

        self.add_parameter('counter_coupling',
                           get_cmd='COUN:COUP?',
                           set_cmd='COUN:COUP {}',
                           vals=Enum('AC', 'DC'))

        self.add_parameter('counter_gate_time',
                           get_cmd='COUN:GATE?',
                           set_cmd='COUN:GATE {}',
                           units='s',
                           val_mapping={
                               'auto': 'AUTO',
                               0.001:  'USER1',
                               0.01:   'USER2',
                               0.1:    'USER3',
                               1:      'USER4',
                               10:     'USER5',
                               '>10':  'USER6',
                           })

        self.add_parameter('counter_hf_reject_enabled',
                           get_cmd='COUN:HF?',
                           set_cmd='COUN:HF {}',
                           val_mapping=on_off_map)

        self.add_parameter('counter_impedance',
                           get_cmd='COUN:IMP?',
                           set_cmd='COUN:IMP {}',
                           units='Ohm',
                           val_mapping={50: '50', 1e6: '1M'})

        self.add_parameter('counter_trigger_level',
                           get_cmd='COUN:LEVE?',
                           get_parser=float,
                           set_cmd='COUN:LEVE {}',
                           units='V',
                           vals=Numbers(min_value=-2.5, max_value=2.5))

        self.add_parameter('counter_enabled',
                           get_cmd='COUN:STAT?',
                           set_cmd='COUN:STAT {}',
                           val_mapping=on_off_map)

        measure_params = ['frequency', 'period', 'duty_cycle',
                          'positive_width', 'negative_width']

        # TODO: Check units of outputs
        for i, param in enumerate(measure_params):
            self.add_parameter('counter_{}'.format(param),
                               get_cmd='COUN:MEAS?',
                               get_parser=partial(parse_single_output, i))

        self.add_parameter('counter_trigger_sensitivity',
                           get_cmd='COUN:SENS?',
                           get_parser=float,
                           set_cmd='COUN:SENS {}',
                           units='%',
                           vals=Numbers(min_value=0, max_value=100))

        # Output and Source parameters for both channel 1 and 2
        for i in [1, 2]:
            ch = 'ch{}_'.format(i)
            output = 'OUTP{}:'.format(i)
            source = 'SOUR{}:'.format(i)

            self.add_parameter(ch + 'output_impedance',
                               get_cmd=output + 'IMP?',
                               get_parser=parse_string_output,
                               set_cmd=output + 'IMP {}',
                               units='Ohm',
                               vals=MultiType(Numbers(min_value=1,
                                                      max_value=10e3),
                                              Enum('infinity',
                                                   'minimum',
                                                   'maximum')))

            self.add_parameter(ch + 'add_noise_scale',
                               get_cmd=output + 'NOIS:SCAL?',
                               get_parser=float,
                               set_cmd=output + 'NOIS:SCAL',
                               units='%',
                               vals=Numbers(min_value=0, max_value=50))

            self.add_parameter(ch + 'add_noise_enabled',
                               get_cmd=output + 'NOIS?',
                               set_cmd=output + 'NOIS {}',
                               val_mapping=on_off_map)

            self.add_parameter(ch + 'output_polarity',
                               get_cmd=output + 'POL?',
                               set_cmd=output + 'POL {}',
                               val_mapping={'normal': 'NORM',
                                            'inverted': 'INV'})

            self.add_parameter(ch + 'output_enabled',
                               get_cmd=output + 'STAT?',
                               set_cmd=output + 'STAT {}',
                               val_mapping=on_off_map)

            self.add_parameter(ch + 'sync_polarity',
                               get_cmd=output + 'SYNC:POL?',
                               set_cmd=output + 'SYNC:POL {}',
                               val_mapping={'positive': 'POS',
                                            'negative': 'NEG'})

            self.add_parameter(ch + 'sync_enabled',
                               get_cmd=output + 'SYNC?',
                               set_cmd=output + 'SYNC {}',
                               val_mapping=on_off_map)

            # Source Apply
            # TODO: Various parameters are limited by
            # impedance/freq/period/amplitude settings, this might be very hard
            # to implement in here
            self.add_function(ch + 'custom',
                              call_cmd=source + 'APPL:CUST '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, arb_freq),
                                    Numbers(), Numbers(), Numbers(0, 360)])

            self.add_function(ch + 'harmonic',
                              call_cmd=source + 'APPL:HARM '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, harmonic_freq),
                                    Numbers(), Numbers(), Numbers(0, 360)])

            self.add_function(ch + 'noise',
                              call_cmd=source + 'APPL:NOIS {:.6e},{:.6e}',
                              args=[Numbers(0, 10), Numbers()])

            self.add_function(ch + 'pulse',
                              call_cmd=source + 'APPL:PULS '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, pulse_freq),
                                    Numbers(), Numbers(), Numbers(0)])

            self.add_function(ch + 'ramp',
                              call_cmd=source + 'APPL:RAMP '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, ramp_freq),
                                    Numbers(), Numbers(), Numbers(0, 360)])

            self.add_function(ch + 'sinusoid',
                              call_cmd=source + 'APPL:SIN '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, sine_freq),
                                    Numbers(), Numbers(), Numbers(0, 360)])

            self.add_function(ch + 'square',
                              call_cmd=source + 'APPL:SQU '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, square_freq),
                                    Numbers(), Numbers(), Numbers(0, 360)])

            self.add_function(ch + 'user',
                              call_cmd=source + 'APPL:USER '
                                                '{:.6e},{:.6e},{:.6e},{:.6e}',
                              args=[Numbers(1e-6, arb_freq),
                                    Numbers(), Numbers(), Numbers(0, 360)])

            self.add_parameter(ch + 'configuration',
                               get_cmd=source + 'APPL?',
                               get_parser=parse_multiple_outputs)

            # Source Burst
            self.add_parameter(ch + 'burst_mode',
                               get_cmd=source + 'BURS:MODE?',
                               set_cmd=source + 'BURS:MODE {}',
                               val_mapping={'triggered': 'TRIG',
                                            'gated': 'GAT',
                                            'infinity': 'INF'})

            self.add_parameter(ch + 'burst_cycles',
                               get_cmd=source + 'BURS:NCYC?',
                               get_parser=float,
                               set_cmd=source + 'BURS:NCYC {}',
                               vals=Ints(1, 1000000))

            self.add_parameter(ch + 'burst_period',
                               get_cmd=source + 'BURS:INT:PER?',
                               get_parser=float,
                               set_cmd=source + 'BURS:INT:PER {}',
                               units='s',
                               vals=Numbers(1e-6))

            self.add_parameter(ch + 'burst_phase',
                               get_cmd=source + 'BURS:PHAS?',
                               get_parser=float,
                               set_cmd=source + 'BURS:PHAS {}',
                               units='deg',
                               vals=Numbers(0, 360))

            self.add_parameter(ch + 'burst_trigger_edge',
                               get_cmd=source + 'BURS:TRIG:SLOP?',
                               set_cmd=source + 'BURS:TRIG:SLOP {}',
                               val_mapping={'positive': 'POS',
                                            'negative': 'NEG'})

            self.add_parameter(ch + 'burst_trigger_source',
                               get_cmd=source + 'BURS:TRIG:SOUR?',
                               set_cmd=source + 'BURS:TRIG:SOUR {}',
                               val_mapping={'internal': 'INT',
                                            'external': 'EXT',
                                            'manual': 'MAN'})

            self.add_parameter(ch + 'burst_trigger_out',
                               get_cmd=source + 'BURS:TRIG:TRIGO?',
                               set_cmd=source + 'BURS:TRIG:TRIGO {}',
                               val_mapping={'off': 'OFF',
                                            'positive': 'POS',
                                            'negative': 'NEG'})

            # Source Frequency
            # TODO: The upper bounds of these parameters also depend on the
            # current waveform
            self.add_parameter(ch + 'frequency_center',
                               get_cmd=source + 'FREQ:CENT?',
                               get_parser=float,
                               set_cmd=source + 'FREQ:CENT {}',
                               units='Hz',
                               vals=Numbers(1e-6))

            self.add_parameter(ch + 'frequency',
                               get_cmd=source + 'FREQ?',
                               get_parser=float,
                               set_cmd=source + 'FREQ {}',
                               units='Hz',
                               vals=Numbers(1e-6))

            self.add_parameter(ch + 'frequency_start',
                               get_cmd=source + 'FREQ:STAR?',
                               get_parser=float,
                               set_cmd=source + 'FREQ:STAR {}',
                               units='Hz',
                               vals=Numbers(1e-6))

            self.add_parameter(ch + 'frequency_stop',
                               get_cmd=source + 'FREQ:STOP?',
                               get_parser=float,
                               set_cmd=source + 'FREQ:STOP {}',
                               units='Hz',
                               vals=Numbers(1e-6))

            # Source Function
            self.add_parameter(ch + 'ramp_symmetry',
                               get_cmd=source + 'FUNC:RAMP:SYMM?',
                               get_parser=float,
                               set_cmd=source + 'FUNC:RAMP:SYMM {}',
                               units='%',
                               vals=Numbers(0, 100))

            self.add_parameter(ch + 'square_duty_cycle',
                               get_cmd=source + 'FUNC:SQU:DCYC?',
                               get_parser=float,
                               set_cmd=source + 'FUNC:SQU:DCYC {}',
                               units='%',
                               vals=Numbers(20, 80))

            # Source Harmonic
            self.add_function(ch + 'set_harmonic_amplitude',
                              call_cmd=source + 'HARM:AMPL {},{:.6e}',
                              args=[Ints(2, 16), Numbers(0)])

            self.add_function(ch + 'get_harmonic_amplitude',
                              call_cmd=source + 'HARM:AMPL? {}',
                              args=[Ints(2, 16)],
                              return_parser=float)

            self.add_parameter(ch + 'harmonic_order',
                               get_cmd=source + 'HARM:ORDE?',
                               get_parser=int,
                               set_cmd=source + 'HARM:ORDE {}',
                               vals=Ints(2, 16))

            self.add_function(ch + 'set_harmonic_phase',
                              call_cmd=source + 'HARM:PHAS {},{:.6e}',
                              args=[Ints(2, 16), Numbers(0, 360)])

            self.add_function(ch + 'get_harmonic_phase',
                              call_cmd=source + 'HARM:PHAS? {}',
                              args=[Ints(2, 16)],
                              return_parser=float)

            self.add_parameter(ch + 'harmonic_type',
                               get_cmd=source + 'HARM:TYP?',
                               get_parser=str.lower,
                               set_cmd=source + 'HARM:TYP {}',
                               vals=Enum('even', 'odd', 'all', 'user'))

            # Source Marker
            self.add_parameter(ch + 'marker_frequency',
                               get_cmd=source + 'MARK:FREQ?',
                               get_parser=float,
                               set_cmd=source + 'HMARK:FREQ {}',
                               units='Hz',
                               vals=Numbers(1e-6))

            self.add_parameter(ch + 'marker_enabled',
                               get_cmd=source + 'MARK?',
                               set_cmd=source + 'MARK {}',
                               val_mapping=on_off_map)

            # Source Modulation (not implemented yet)

            # Source Period (not implemented yet)

            # Source Phase
            self.add_parameter(ch + 'phase',
                               get_cmd=source + 'PHAS?',
                               get_parser=float,
                               set_cmd=source + 'PHAS {}',
                               units='deg',
                               vals=Numbers(0, 360))

            self.add_function(ch + 'align_phase',
                              call_cmd=source + 'PHAS:INIT')

            # Source Pulse
            self.add_parameter(ch + 'pulse_duty_cycle',
                               get_cmd=source + 'PULS:DCYC?',
                               get_parser=float,
                               set_cmd=source + 'PULS:DCYC {}',
                               units='%',
                               vals=Numbers(0, 100))

            self.add_parameter(ch + 'pulse_delay',
                               get_cmd=source + 'PULS:DEL?',
                               get_parser=float,
                               set_cmd=source + 'PULS:DEL {}',
                               units='s',
                               vals=Numbers(0))

            self.add_parameter(ch + 'pulse_hold',
                               get_cmd=source + 'PULS:HOLD?',
                               set_cmd=source + 'PULS:HOLD {}',
                               units='s',
                               val_mapping={'width': 'WIDT', 'duty': 'DUTY'})

            self.add_parameter(ch + 'pulse_leading_edge',
                               get_cmd=source + 'PULS:TRAN:LEAD?',
                               get_parser=float,
                               set_cmd=source + 'PULS:TRAN:LEAD {}',
                               units='s',
                               vals=Numbers(0))

            self.add_parameter(ch + 'pulse_trailing_edge',
                               get_cmd=source + 'PULS:TRAN:TRA?',
                               get_parser=float,
                               set_cmd=source + 'PULS:TRAN:TRA {}',
                               units='s',
                               vals=Numbers(0))

            self.add_parameter(ch + 'pulse_width',
                               get_cmd=source + 'PULS:WIDT?',
                               get_parser=float,
                               set_cmd=source + 'PULS:WIDT {}',
                               units='s',
                               vals=Numbers(0))

            # Source Sweep
            self.add_parameter(ch + 'sweep_hold_start',
                               get_cmd=source + 'SWE:HTIM:STAR?',
                               get_parser=float,
                               set_cmd=source + 'SWE:HTIM:STAR {}',
                               units='s',
                               vals=Numbers(0, 300))

            self.add_parameter(ch + 'sweep_hold_stop',
                               get_cmd=source + 'SWE:HTIM:STOP?',
                               get_parser=float,
                               set_cmd=source + 'SWE:HTIM:STOP {}',
                               units='s',
                               vals=Numbers(0, 300))

            self.add_parameter(ch + 'sweep_return_time',
                               get_cmd=source + 'SWE:RTIM?',
                               get_parser=float,
                               set_cmd=source + 'SWE:RTIM {}',
                               units='s',
                               vals=Numbers(0, 300))

            self.add_parameter(ch + 'sweep_spacing',
                               get_cmd=source + 'SWE:SPAC?',
                               set_cmd=source + 'SWE:SPAC {}',
                               val_mapping={'linear': 'LIN',
                                            'logarithmic': 'LOG',
                                            'step': 'STE'})

            self.add_parameter(ch + 'sweep_enabled',
                               get_cmd=source + 'SWE:STAT?',
                               set_cmd=source + 'SWE:STAT {}',
                               val_mapping=on_off_map)

            self.add_parameter(ch + 'sweep_step',
                               get_cmd=source + 'SWE:STEP?',
                               get_parser=int,
                               set_cmd=source + 'SWE:STEP {}',
                               vals=Ints(2, 2048))

            self.add_parameter(ch + 'sweep_time',
                               get_cmd=source + 'SWE:TIME?',
                               get_parser=float,
                               set_cmd=source + 'SWE:TIME {}',
                               units='s',
                               vals=Numbers(1e-3, 300))

            # Source Voltage
            self.add_parameter(ch + 'amplitude',
                               get_cmd=source + 'VOLT?',
                               get_parser=float,
                               set_cmd=source + 'VOLT {}',
                               units='V',
                               vals=Numbers())

            self.add_parameter(ch + 'offset',
                               get_cmd=source + 'VOLT:OFFS?',
                               get_parser=float,
                               set_cmd=source + 'VOLT:OFFS {}',
                               units='V',
                               vals=Numbers())

            self.add_parameter(ch + 'unit',
                               get_cmd=source + 'VOLT:UNIT?',
                               get_parser=str.lower,
                               set_cmd=source + 'VOLT:UNIT {}',
                               vals=Enum('vpp', 'vrms', 'dbm'))

        # System
        self.add_function('beep', call_cmd='SYST:BEEP')

        self.add_parameter('beeper_enabled',
                           get_cmd='SYST:BEEP:STAT?',
                           set_cmd='SYST:BEEP:STAT {}',
                           val_mapping=on_off_map)

        self.add_function('copy_config_to_ch1', call_cmd='SYST:CSC CH2,CH1')
        self.add_function('copy_config_to_ch2', call_cmd='SYST:CSC CH1,CH2')

        self.add_function('copy_waveform_to_ch1', call_cmd='SYST:CWC CH2,CH1')
        self.add_function('copy_waveform_to_ch2', call_cmd='SYST:CWC CH1,CH2')

        self.add_function('get_error', call_cmd='SYST:ERR?', return_parser=str)

        self.add_parameter('keyboard_locked',
                           get_cmd='SYST:KLOCK?',
                           set_cmd='SYST:KLOCK {}',
                           val_mapping=on_off_map)

        self.add_parameter('startup_mode',
                           get_cmd='SYST:POWS?',
                           get_parser=str.lower,
                           set_cmd='SYST:POWS {}',
                           vals=Enum('user', 'auto'))

        system_states = Enum('default', 'user1', 'user2', 'user3',
                             'user4', 'user5', 'user6', 'user7',
                             'user8', 'user9', 'user10')

        self.add_function('preset',
                          call_cmd='SYST:PRES {}',
                          args=[system_states])

        self.add_function('restart', call_cmd='SYST:RESTART')

        self.add_parameter('reference_clock_source',
                           get_cmd='SYST:ROSC:SOUR?',
                           set_cmd='SYST:ROSC:SOUR {}',
                           val_mapping={'internal': 'INT', 'external': 'EXT'})

        self.add_function('shutdown', call_cmd='SYST:SHUTDOWN')

        self.add_parameter('scpi_version', get_cmd='SYST:VERS?')

        # Trace
        self.add_function('upload_data',
                          call_cmd=self._upload_data,
                          args=[Anything()])

        self.add_function('reset', call_cmd='*RST')

        if reset:
            self.reset()

        self.connect_message()
Beispiel #7
0
    def __init__(self,
                 name: str,
                 address: str,
                 reset_device: bool = False,
                 **kwargs: Any):
        """ Driver for the Keithley 6500 multimeter. Based on the Keithley 2000 driver,
            commands have been adapted for the Keithley 6500. This driver does not contain
            all commands available, but only the ones most commonly used.

            Status: beta-version.

        Args:
            name (str): The name used internally by QCoDeS in the DataSet.
            address (str): The VISA device address.
            reset_device (bool): Reset the device on startup if true.
        """
        super().__init__(name, address, terminator='\n', **kwargs)

        command_set = self.ask('*LANG?')
        if command_set != 'SCPI':
            error_msg = "This driver only compatible with the 'SCPI' command " \
                        "set, not '{}' set".format(command_set)
            raise CommandSetError(error_msg)

        self._trigger_sent = False

        self._mode_map = {
            'ac current': 'CURR:AC',
            'dc current': 'CURR:DC',
            'ac voltage': 'VOLT:AC',
            'dc voltage': 'VOLT:DC',
            '2w resistance': 'RES',
            '4w resistance': 'FRES',
            'temperature': 'TEMP',
            'frequency': 'FREQ'
        }

        self.add_parameter(
            "mode",
            get_cmd="SENS:FUNC?",
            set_cmd="SENS:FUNC '{}'",
            val_mapping=self._mode_map,
        )

        self.add_parameter('nplc',
                           get_cmd=partial(self._get_mode_param, 'NPLC',
                                           float),
                           set_cmd=partial(self._set_mode_param, 'NPLC'),
                           vals=Numbers(min_value=0.01, max_value=10))

        #  TODO: validator, this one is more difficult since different modes
        #  require different validation ranges.
        self.add_parameter('range',
                           get_cmd=partial(self._get_mode_param, 'RANG',
                                           float),
                           set_cmd=partial(self._set_mode_param, 'RANG'),
                           vals=Numbers())

        self.add_parameter('auto_range_enabled',
                           get_cmd=partial(self._get_mode_param, 'RANG:AUTO',
                                           _parse_output_bool),
                           set_cmd=partial(self._set_mode_param, 'RANG:AUTO'),
                           vals=Bool())

        self.add_parameter('digits',
                           get_cmd='DISP:VOLT:DC:DIG?',
                           get_parser=int,
                           set_cmd='DISP:VOLT:DC:DIG? {}',
                           vals=Ints(min_value=4, max_value=7))

        self.add_parameter('averaging_type',
                           get_cmd=partial(self._get_mode_param, 'AVER:TCON',
                                           _parse_output_string),
                           set_cmd=partial(self._set_mode_param, 'AVER:TCON'),
                           vals=Enum('moving', 'repeat'))

        self.add_parameter('averaging_count',
                           get_cmd=partial(self._get_mode_param, 'AVER:COUN',
                                           int),
                           set_cmd=partial(self._set_mode_param, 'AVER:COUN'),
                           vals=Ints(min_value=1, max_value=100))

        self.add_parameter('averaging_enabled',
                           get_cmd=partial(self._get_mode_param, 'AVER:STAT',
                                           _parse_output_bool),
                           set_cmd=partial(self._set_mode_param, 'AVER:STAT'),
                           vals=Bool())

        # Global parameters
        self.add_parameter('display_backlight',
                           docstring='Control the brightness of the display '
                           'backligt. Off turns the display off and'
                           'Blackout also turns off indicators and '
                           'key lights on the device.',
                           get_cmd='DISP:LIGH:STAT?',
                           set_cmd='DISP:LIGH:STAT {}',
                           val_mapping={
                               'On 100': 'ON100',
                               'On 75': 'ON75',
                               'On 50': 'ON50',
                               'On 25': 'ON25',
                               'Off': 'OFF',
                               'Blackout': 'BLACkout'
                           })

        self.add_parameter('trigger_count',
                           get_parser=int,
                           get_cmd='ROUT:SCAN:COUN:SCAN?',
                           set_cmd='ROUT:SCAN:COUN:SCAN {}',
                           vals=MultiType(
                               Ints(min_value=1, max_value=9999),
                               Enum('inf', 'default', 'minimum', 'maximum')))

        for trigger in range(1, 5):
            self.add_parameter('trigger%i_delay' % trigger,
                               docstring='Set and read trigger delay for '
                               'timer %i.' % trigger,
                               get_parser=float,
                               get_cmd='TRIG:TIM%i:DEL?' % trigger,
                               set_cmd='TRIG:TIM%i:DEL {}' % trigger,
                               unit='s',
                               vals=Numbers(min_value=0, max_value=999999.999))

            self.add_parameter('trigger%i_source' % trigger,
                               docstring='Set the trigger source for '
                               'timer %i.' % trigger,
                               get_cmd='TRIG:TIM%i:STAR:STIM?' % trigger,
                               set_cmd='TRIG:TIM%i:STAR:STIM {}' % trigger,
                               val_mapping={
                                   'immediate': 'NONE',
                                   'timer1': 'TIM1',
                                   'timer2': 'TIM2',
                                   'timer3': 'TIM3',
                                   'timer4': 'TIM4',
                                   'notify1': 'NOT1',
                                   'notify2': 'NOT2',
                                   'notify3': 'NOT3',
                                   'front-panel': 'DISP',
                                   'bus': 'COMM',
                                   'external': 'EXT'
                               })

        # Control interval between scans; the default value from the instrument is 0,
        # hence 0 is included in the validator's range of this parameter.
        self.add_parameter('trigger_timer',
                           get_parser=float,
                           get_cmd='ROUT:SCAN:INT?',
                           set_cmd='ROUT:SCAN:INT {}',
                           unit='s',
                           vals=Numbers(min_value=0, max_value=999999.999))

        self.add_parameter('amplitude',
                           get_cmd=self._read_next_value,
                           set_cmd=False,
                           unit='a.u.')

        if reset_device:
            self.reset()
        self.write('FORM:DATA ASCII')
        self.connect_message()
    def __init__(self, parent:'NGE100Base', channel:int):
        """
        Arguments:
            parent: Parent instrument.
            channel: Channel number.
        """

        if channel < 1 or channel > parent.nb_channels:
            raise ValueError(f"Invalid channel '{channel}', channels can "
                             f"only be between 1 and {parent.NB_CHANNELS}.")

        super().__init__(parent, name=f"ch{channel}")
        self.channel = channel

        # Store dummy values for virtual instrument
        if self.parent.virtual:
            self._virtual_parameters = {}

        self.add_parameter(
            name="voltage",
            get_cmd=partial(self._get_channel_parameter, "VOLTage?"),
            set_cmd=partial(self._set_channel_parameter, "VOLTage {}"),
            get_parser=float,
            unit="V",
            vals=Numbers(0, 32.0),
            docstring="The voltage is adjustable in 10 mV steps. If the set "
                      "value is not on the 10 mV grid, it will be rounded to "
                      "the closest possible value "
                      "(e.g.`` 0.014 -> 0.01``; ``0.015 -> 0.02``)."
        )

        self.add_parameter(
            name="current_limit",
            get_cmd=partial(self._get_channel_parameter, "CURRent?"),
            set_cmd=partial(self._set_channel_parameter, "CURRent {}"),
            get_parser=float,
            unit="A",
            vals=Numbers(0, 3.0),
            docstring="Note that the actual limit may be lower as the maximum "
                      "output power is 33.6 W per channel."
        )

        self.add_parameter(
            name="output",
            get_cmd=partial(self._get_channel_parameter, "OUTPut?"),
            set_cmd=partial(self._set_channel_parameter, "OUTPut {}"),
            get_parser=int,
            vals=Enum(0, 1, "OFF", "ON"),
            docstring="Enable or disable the channel output."
        )

        self.add_parameter(
            name="measured_voltage",
            get_cmd=partial(self._get_channel_parameter, "MEASure:VOLTage?"),
            get_parser=float,
            unit="V",
            docstring="(readonly)"
        )

        self.add_parameter(
            name="measured_current",
            get_cmd=partial(self._get_channel_parameter, "MEASure:CURRent?"),
            get_parser=float,
            unit="A",
            docstring="(readonly)"
        )

        self.add_parameter(
            name="measured_power",
            get_cmd=partial(self._get_channel_parameter, "MEASure:POWer?"),
            get_parser=float,
            unit="W",
            docstring="(readonly)"
        )

        if self.parent.virtual:
            self.add_parameter(
                name="mock_output_current",
                parameter_class=ManualParameter,
                unit="A",
                initial_value=0.0,
                vals=Numbers(0, 3.0),
                snapshot_exclude=True,
                docstring="This value will be forwarded to ``measured_current``. "
                          "Only available for virtual instruments."
            )
Beispiel #9
0
class Sense2450(InstrumentChannel):
    """
    The sense module of the Keithley 2450 SMU.

    Args:
        parent
        name
        proper_function: This can be one of either "current", "voltage"
            or "resistance". All parameters and methods in this submodule
            should only be accessible to the user if
            self.parent.sense_function.get() == self._proper_function. We
            ensure this through the 'sense' property on the main driver class
            which returns the proper submodule for any given function mode
    """

    function_modes = {
        "current": {
            "name": '"CURR:DC"',
            "unit": "A",
            "range_vals": Numbers(10E-9, 1)
        },
        "resistance": {
            "name": '"RES"',
            "unit": "Ohm",
            "range_vals": Numbers(20, 200E6)
        },
        "voltage": {
            "name": '"VOLT:DC"',
            "unit": "V",
            "range_vals": Numbers(0.02, 200)
        }
    }

    def __init__(self, parent: 'Keithley2450', name: str,
                 proper_function: str) -> None:
        super().__init__(parent, name)
        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.sense_function

        self.add_parameter(
            "four_wire_measurement",
            set_cmd=f":SENSe:{self._proper_function}:RSENse {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RSENse?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        self.add_parameter(
            "range",
            set_cmd=f":SENSe:{self._proper_function}:RANGe {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RANGe?",
            vals=range_vals,
            get_parser=float,
            unit=unit)

        self.add_parameter(
            "auto_range",
            set_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        self.add_parameter(self._proper_function,
                           get_cmd=self._measure,
                           get_parser=float,
                           unit=unit,
                           snapshot_value=False)

        self.add_parameter("sweep",
                           label=self._proper_function,
                           get_cmd=self._measure_sweep,
                           unit=unit,
                           vals=Arrays(shape=(self.parent.npts, )),
                           parameter_class=ParameterWithSetpointsCustomized)

        self.add_parameter(
            "nplc",
            get_cmd=f":SENSe:{self._proper_function}:NPLCycles?",
            set_cmd=f":SENSe:{self._proper_function}:NPLCycles {{}}",
            vals=Numbers(0.001, 10))

        self.add_parameter('user_number',
                           get_cmd=None,
                           set_cmd=None,
                           initial_value=1,
                           vals=Ints(1, 5))

        self.add_parameter("user_delay",
                           get_cmd=self._get_user_delay,
                           set_cmd=self._set_user_delay,
                           vals=Numbers(0, 1e4))

        self.add_parameter(
            'auto_zero_enabled',
            get_cmd=f":SENSe:{self._proper_function}:AZERo?",
            set_cmd=f":SENSe:{self._proper_function}:AZERo {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="This command enables or disables automatic updates to"
            "the internal reference measurements (autozero) of the"
            "instrument.")

        self.add_parameter(
            'count',
            get_cmd=":SENSe:COUNt?",
            set_cmd=":SENSe:COUNt {}",
            docstring="The number of measurements to make when a measurement "
            "is requested.")

    def _measure(self) -> Union[float, str]:
        if not self.parent.output_enabled():
            raise RuntimeError("Output needs to be on for a measurement")
        buffer_name = self.parent.buffer_name()
        return float(self.ask(f":MEASure? '{buffer_name}'"))

    def _measure_sweep(self) -> np.ndarray:

        source = cast(Source2450, self.parent.source)
        source.sweep_start()
        buffer_name = self.parent.buffer_name()
        buffer = cast(Buffer2450,
                      self.parent.submodules[f"_buffer_{buffer_name}"])
        end_idx = self.parent.npts()
        raw_data = buffer.get_data(1, end_idx, readings_only=True)
        raw_data_with_extra = buffer.get_data(1, end_idx)
        self.parent.sense.sweep._user_selected_data = raw_data_with_extra
        # Clear the trace so we can be assured that a subsequent measurement
        # will not be contaminated with data from this run.
        buffer.clear_buffer()
        return np.array([float(i) for i in raw_data])

    def auto_zero_once(self) -> None:
        """
        This command causes the instrument to refresh the reference and zero
        measurements once.
        """
        self.write(":SENSe:AZERo:ONCE")

    def clear_trace(self, buffer_name: str = "defbuffer1") -> None:
        """
        Clear the data buffer
        """
        self.write(f":TRACe:CLEar '{buffer_name}'")

    def _get_user_delay(self) -> str:
        get_cmd = f":SENSe:{self._proper_function}:DELay:USER" \
                  f"{self.user_number()}?"
        return self.ask(get_cmd)

    def _set_user_delay(self, value) -> None:
        set_cmd = f":SENSe:{self._proper_function}:DELay:USER" \
                  f"{self.user_number()} {value}"
        self.write(set_cmd)
Beispiel #10
0
class Sense2450(InstrumentChannel):
    """
    The sense module of the Keithley 2450 SMU.

    Args:
        parent
        name
        proper_function: This can be one of either "current", "voltage"
            or "resistance". All parameters and methods in this submodule
            should only be accessible to the user if
            self.parent.sense_function.get() == self._proper_function. We
            ensure this through the 'sense' property on the main driver class
            which returns the proper submodule for any given function mode
    """

    function_modes = {
        "current": {
            "name": '"CURR:DC"',
            "unit": "A",
            "range_vals": Numbers(10E-9, 1)
        },
        "resistance": {
            "name": '"RES"',
            "unit": "Ohm",
            "range_vals": Numbers(20, 200E6)
        },
        "voltage": {
            "name": '"VOLT:DC"',
            "unit": "V",
            "range_vals": Numbers(0.02, 200)
        }
    }

    def __init__(self, parent: 'Keithley2450', name: str, proper_function: str) -> None:
        super().__init__(parent, name)
        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.sense_function

        self.add_parameter(
            "four_wire_measurement",
            set_cmd=f":SENSe:{self._proper_function}:RSENse {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RSENse?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0")
        )

        self.add_parameter(
            "range",
            set_cmd=f":SENSe:{self._proper_function}:RANGe {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RANGe?",
            vals=range_vals,
            get_parser=float,
            unit=unit
        )

        self.add_parameter(
            "auto_range",
            set_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0")
        )

        self.add_parameter(
            self._proper_function,
            get_cmd=self._measure,
            get_parser=float,
            unit=unit,
            snapshot_value=False
        )

        self.add_parameter(
            "sweep",
            label=self._proper_function,
            get_cmd=self._measure_sweep,
            unit=unit,
            vals=Arrays(shape=(self.parent.npts,)),
            parameter_class=ParameterWithSetpoints
        )

    def _measure(self) -> str:
        if not self.parent.output_enabled():
            raise RuntimeError("Output needs to be on for a measurement")
        return self.ask(":MEASure?")

    def _measure_sweep(self) -> np.ndarray:

        source = cast(Source2450, self.parent.source)
        source.sweep_start()
        raw_data = self.ask(f":TRACe:DATA? 1, {self.parent.npts()}")
        # Clear the trace so we can be assured that a subsequent measurement
        # will not be contaminated with data from this run.
        self.clear_trace()

        return np.array([float(i) for i in raw_data.split(",")])

    def clear_trace(self) -> None:
        """
        Clear the data buffer
        """
        self.write(":TRACe:CLEar")
Beispiel #11
0
    def __init__(self, name: str, instrument_x: Union[AMI430, str],
                 instrument_y: Union[AMI430, str], instrument_z: Union[AMI430,
                                                                       str],
                 field_limit: Union[numbers.Real,
                                    Iterable[CartesianFieldLimitFunction]],
                 **kwargs: Any):
        """
        Driver for controlling three American Magnetics Model 430 magnet power
        supplies simultaneously for setting magnetic field vectors.

        The individual magnet power supplies can be passed in as either
        instances of AMI430 driver or as names of existing AMI430 instances.
        In the latter case, the instances will be found via the passed names.

        Args:
            name: a name for the instrument
            instrument_x: AMI430 instance or a names of existing AMI430
                instance for controlling the X axis of magnetic field
            instrument_y: AMI430 instance or a names of existing AMI430
                instance for controlling the Y axis of magnetic field
            instrument_z: AMI430 instance or a names of existing AMI430
                instance for controlling the Z axis of magnetic field
            field_limit: a number for maximum allows magnetic field or an
                iterable of callable field limit functions that define
                region(s) of allowed values in 3D magnetic field space
        """
        super().__init__(name, **kwargs)

        if not isinstance(name, str):
            raise ValueError("Name should be a string")

        for instrument, arg_name in zip(
            (instrument_x, instrument_y, instrument_z),
            ("instrument_x", "instrument_y", "instrument_z"),
        ):
            if not isinstance(instrument, (AMI430, str)):
                raise ValueError(
                    f"Instruments need to be instances of the class AMI430 "
                    f"or be valid names of already instantiated instances "
                    f"of AMI430 class; {arg_name} argument is "
                    f"neither of those")

        def find_ami430_with_name(ami430_name: str) -> AMI430:
            found_ami430 = AMI430.find_instrument(name=ami430_name,
                                                  instrument_class=AMI430)
            return found_ami430

        self._instrument_x = (instrument_x if isinstance(instrument_x, AMI430)
                              else find_ami430_with_name(instrument_x))
        self._instrument_y = (instrument_y if isinstance(instrument_y, AMI430)
                              else find_ami430_with_name(instrument_y))
        self._instrument_z = (instrument_z if isinstance(instrument_z, AMI430)
                              else find_ami430_with_name(instrument_z))

        self._field_limit: Union[float, Iterable[CartesianFieldLimitFunction]]
        if isinstance(field_limit, collections.abc.Iterable):
            self._field_limit = field_limit
        elif isinstance(field_limit, numbers.Real):
            # Conversion to float makes related driver logic simpler
            self._field_limit = float(field_limit)
        else:
            raise ValueError("field limit should either be a number or "
                             "an iterable of callable field limit functions.")

        self._set_point = FieldVector(x=self._instrument_x.field(),
                                      y=self._instrument_y.field(),
                                      z=self._instrument_z.field())

        # Get-only parameters that return a measured value
        self.add_parameter('cartesian_measured',
                           get_cmd=partial(self._get_measured, 'x', 'y', 'z'),
                           unit='T')

        self.add_parameter('x_measured',
                           get_cmd=partial(self._get_measured, 'x'),
                           unit='T')

        self.add_parameter('y_measured',
                           get_cmd=partial(self._get_measured, 'y'),
                           unit='T')

        self.add_parameter('z_measured',
                           get_cmd=partial(self._get_measured, 'z'),
                           unit='T')

        self.add_parameter('spherical_measured',
                           get_cmd=partial(self._get_measured, 'r', 'theta',
                                           'phi'),
                           unit='T')

        self.add_parameter('phi_measured',
                           get_cmd=partial(self._get_measured, 'phi'),
                           unit='deg')

        self.add_parameter('theta_measured',
                           get_cmd=partial(self._get_measured, 'theta'),
                           unit='deg')

        self.add_parameter('field_measured',
                           get_cmd=partial(self._get_measured, 'r'),
                           unit='T')

        self.add_parameter('cylindrical_measured',
                           get_cmd=partial(self._get_measured, 'rho', 'phi',
                                           'z'),
                           unit='T')

        self.add_parameter('rho_measured',
                           get_cmd=partial(self._get_measured, 'rho'),
                           unit='T')

        # Get and set parameters for the set points of the coordinates
        self.add_parameter('cartesian',
                           get_cmd=partial(self._get_setpoints,
                                           ('x', 'y', 'z')),
                           set_cmd=partial(self._set_setpoints,
                                           ('x', 'y', 'z')),
                           unit='T',
                           vals=Anything())

        self.add_parameter('x',
                           get_cmd=partial(self._get_setpoints, ('x', )),
                           set_cmd=partial(self._set_setpoints, ('x', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('y',
                           get_cmd=partial(self._get_setpoints, ('y', )),
                           set_cmd=partial(self._set_setpoints, ('y', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('z',
                           get_cmd=partial(self._get_setpoints, ('z', )),
                           set_cmd=partial(self._set_setpoints, ('z', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('spherical',
                           get_cmd=partial(self._get_setpoints,
                                           ('r', 'theta', 'phi')),
                           set_cmd=partial(self._set_setpoints,
                                           ('r', 'theta', 'phi')),
                           unit='tuple?',
                           vals=Anything())

        self.add_parameter('phi',
                           get_cmd=partial(self._get_setpoints, ('phi', )),
                           set_cmd=partial(self._set_setpoints, ('phi', )),
                           unit='deg',
                           vals=Numbers())

        self.add_parameter('theta',
                           get_cmd=partial(self._get_setpoints, ('theta', )),
                           set_cmd=partial(self._set_setpoints, ('theta', )),
                           unit='deg',
                           vals=Numbers())

        self.add_parameter('field',
                           get_cmd=partial(self._get_setpoints, ('r', )),
                           set_cmd=partial(self._set_setpoints, ('r', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('cylindrical',
                           get_cmd=partial(self._get_setpoints,
                                           ('rho', 'phi', 'z')),
                           set_cmd=partial(self._set_setpoints,
                                           ('rho', 'phi', 'z')),
                           unit='tuple?',
                           vals=Anything())

        self.add_parameter('rho',
                           get_cmd=partial(self._get_setpoints, ('rho', )),
                           set_cmd=partial(self._set_setpoints, ('rho', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('block_during_ramp',
                           set_cmd=None,
                           initial_value=True,
                           unit='',
                           vals=Bool())

        self.ramp_mode = Parameter(
            name="ramp_mode",
            instrument=self,
            get_cmd=None,
            set_cmd=None,
            vals=Enum("default", "simultaneous"),
            initial_value="default",
        )

        self.ramping_state_check_interval = Parameter(
            name="ramping_state_check_interval",
            instrument=self,
            initial_value=0.05,
            unit="s",
            vals=Numbers(0, 10),
            set_cmd=None,
            get_cmd=None,
        )

        self.vector_ramp_rate = Parameter(
            name="vector_ramp_rate",
            instrument=self,
            unit="T/s",
            vals=Numbers(min_value=0.0),
            set_cmd=None,
            get_cmd=None,
            set_parser=self._set_vector_ramp_rate_units,
            docstring="Ramp rate along a line (vector) in 3D space. Only active"
            " if `ramp_mode='simultaneous'`.")
        """Ramp rate along a line (vector) in 3D field space"""
Beispiel #12
0
class Source2450(InstrumentChannel):
    """
    The source module of the Keithley 2450 SMU.

    Args:
        parent
        name
        proper_function: This can be one of either "current" or "voltage"
            All parameters and methods in this submodule should only be
            accessible to the user if
            self.parent.source_function.get() == self._proper_function. We
            ensure this through the 'source' property on the main driver class
            which returns the proper submodule for any given function mode
    """
    function_modes = {
        "current": {
            "name": "CURR",
            "unit": "A",
            "range_vals": Numbers(-1, 1)
        },
        "voltage": {
            "name": "VOLT",
            "unit": "V",
            "range_vals": Numbers(-200, 200)
        }
    }

    def __init__(self, parent: 'Keithley2450', name: str, proper_function: str) -> None:
        super().__init__(parent, name)
        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.source_function
        self._sweep_arguments: Dict[str, Union[float, int, str]] = {}

        self.add_parameter(
            "range",
            set_cmd=f":SOUR:{self._proper_function}:RANGe {{}}",
            get_cmd=f":SOUR:{self._proper_function}:RANGe?",
            vals=range_vals,
            get_parser=float,
            unit=unit
        )

        self.add_parameter(
            "auto_range",
            set_cmd=f":SOURce:{self._proper_function}:RANGe:AUTO {{}}",
            get_cmd=f":SOURce:{self._proper_function}:RANGe:AUTO?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0")
        )

        limit_cmd = {"current": "VLIM", "voltage": "ILIM"}[self._proper_function]
        self.add_parameter(
            "limit",
            set_cmd=f"SOUR:{self._proper_function}:{limit_cmd} {{}}",
            get_cmd=f"SOUR:{self._proper_function}:{limit_cmd}?",
            get_parser=float,
            unit=unit
        )

        self.add_parameter(
            self._proper_function,
            set_cmd=f"SOUR:{self._proper_function} {{}}",
            get_cmd=f"SOUR:{self._proper_function}?",
            get_parser=float,
            unit=unit,
            snapshot_value=False
        )

        self.add_parameter(
            "sweep_axis",
            label=self._proper_function,
            get_cmd=self.get_sweep_axis,
            vals=Arrays(shape=(self.parent.npts,)),
            unit=unit
        )

    def get_sweep_axis(self) -> np.ndarray:
        if self._sweep_arguments == {}:
            raise ValueError(
                "Please setup the sweep before getting values of this parameter"
            )

        return np.linspace(
            start=self._sweep_arguments["start"],
            stop=self._sweep_arguments["stop"],
            num=self._sweep_arguments["step_count"]
        )

    def sweep_setup(
            self,
            start: float,
            stop: float,
            step_count: int,
            delay: float = 0,
            sweep_count: int = 1,
            range_mode: str = "AUTO"
    ) -> None:

        self._sweep_arguments = dict(
            start=start,
            stop=stop,
            step_count=step_count,
            delay=delay,
            sweep_count=sweep_count,
            range_mode=range_mode
        )

    def sweep_start(self) -> None:
        """
        Start a sweep and return when the sweep has finished.
        Note: This call is blocking
        """
        cmd_args = dict(self._sweep_arguments)
        cmd_args["function"] = self._proper_function

        cmd = ":SOURce:SWEep:{function}:LINear {start},{stop}," \
              "{step_count},{delay},{sweep_count},{range_mode}".format(**cmd_args)

        self.write(cmd)
        self.write(":INITiate")
        self.write("*WAI")

    def sweep_reset(self) -> None:
        self._sweep_arguments = {}
Beispiel #13
0
    def __init__(self, name, address, reset=False, **kwargs):
        super().__init__(name, address, terminator='\n', **kwargs)

        on_off_map = {True: 'ON', False: 'OFF'}

        for channel in ['A', 'B', 'C', 'D']:
            c = 'ch{}_'.format(channel)

            self.add_parameter(c + 'temperature',
                               get_cmd='input? {}'.format(channel),
                               get_parser=float)

            self.add_parameter(c + 'units',
                               get_cmd='input {}:units?'.format(channel),
                               get_parser=str.upper,
                               set_cmd='input {}:units {{}}'.format(channel),
                               vals=Enum('K', 'C', 'F', 'S'))

            self.add_parameter(c + 'sensor',
                               get_cmd='input {}:sensor?'.format(channel),
                               get_parser=int,
                               set_cmd='input {}:sensor {{}}'.format(channel),
                               vals=Ints(0))

            self.add_parameter(c + 'sensor_power',
                               get_cmd='input {}:sensp {{}}'.format(channel),
                               get_parser=float)

            self.add_parameter(c + 'min',
                               get_cmd='input? {}:min'.format(channel),
                               get_parser=float)

            self.add_parameter(c + 'max',
                               get_cmd='input? {}:max'.format(channel),
                               get_parser=float)

            self.add_parameter(c + 'variance',
                               get_cmd='input? {}:variance'.format(channel),
                               get_parser=float)

            self.add_parameter(c + 'slope',
                               get_cmd='input? {}:slope'.format(channel),
                               get_parser=float)

            self.add_parameter(c + 'offset',
                               get_cmd='input? {}:offset'.format(channel),
                               get_parser=float)

        self.add_function('stop_control_loops', call_cmd='stop')
        self.add_function('start_control_loops', call_cmd='control')

        # TODO: check case of returned strings
        self.add_parameter('control_enabled',
                           get_cmd='control?',
                           val_mapping=on_off_map)

        for loop in [1, 2, 3, 4]:
            l = 'loop{}_'.format(loop)

            self.add_parameter(l + 'source',
                               get_cmd='loop {}:source?'.format(loop),
                               get_parser=str.upper,
                               set_cmd='loop {}:source {{}}'.format(loop),
                               vals=Enum('A', 'B', 'C', 'D'))

            self.add_parameter(l + 'setpoint',
                               get_cmd='loop {}:setpt?'.format(loop),
                               get_parser=float,
                               set_cmd='loop {}:setpt {{}}'.format(loop),
                               vals=Numbers())

            self.add_parameter(l + 'type',
                               get_cmd='loop {}:type?',
                               set_cmd='loop {}:type {{}}'.format(loop),
                               val_mapping={
                                   'off': 'OFF',
                                   'manual': 'MAN',
                                   'PID': 'PID',
                                   'table': 'TABLE',
                                   'ramp': 'RAMPP'
                               })

            mapping = {'high': 'HI', 'medium': 'MID', 'low': 'LOW'}

            if loop == 1:
                mapping['100W'] = '100W'

            self.add_parameter(l + 'range',
                               get_cmd='loop {}:range?',
                               set_cmd='loop {}:range {{}}'.format(loop),
                               val_mapping=mapping)

            self.add_parameter(l + 'is_ramping',
                               get_cmd='loop {}:ramp?',
                               val_mapping=on_off_map)

            self.add_parameter(l + 'ramp_rate',
                               get_cmd='loop {}:rate?'.format(loop),
                               get_parser=float,
                               set_cmd='loop {}:rate {{}}'.format(loop),
                               vals=Numbers(0, 100),
                               unit='units/min')

            self.add_parameter(l + 'P',
                               get_cmd='loop {}:pgain?'.format(loop),
                               get_parser=float,
                               set_cmd='loop {}:pgain {{}}'.format(loop),
                               vals=Numbers(0, 1000),
                               unit='-')

            self.add_parameter(l + 'I',
                               get_cmd='loop {}:igain?'.format(loop),
                               get_parser=float,
                               set_cmd='loop {}:igain {{}}'.format(loop),
                               vals=Numbers(0, 1000),
                               unit='s')

            self.add_parameter(l + 'D',
                               get_cmd='loop {}:dgain?'.format(loop),
                               get_parser=float,
                               set_cmd='loop {}:dgain {{}}'.format(loop),
                               vals=Numbers(0, 1000),
                               unit='1/s')

            self.add_parameter(l + 'manual_power',
                               get_cmd='loop {}:pman?',
                               get_parser=float,
                               set_cmd='loop {}:pman {{}}'.format(loop),
                               vals=Numbers(0, 100),
                               unit='%')

            self.add_parameter(l + 'output_power',
                               get_cmd='loop {}:outp?',
                               get_parser=float,
                               unit='%')

            self.add_parameter(l + 'read_heater',
                               get_cmd='loop {}:htrread?',
                               get_parser=float,
                               unit='%')

            self.add_parameter(l + 'max_power',
                               get_cmd='loop {}:maxp?',
                               get_parser=float,
                               set_cmd='loop {}:maxp {{}}'.format(loop),
                               vals=Numbers(0, 100),
                               unit='%')
    def __init__(self, name, address, coil_constant=0.113375, current_rating=105.84,
                 current_ramp_limit=0.0506, reset=False, timeout=5, **kwargs):

        log.debug('Initializing instrument')

        if 'terminator' in kwargs.keys():
            kwargs.pop('terminator')
            log.warning('Passing terminator to CryogenicSMS is no longer supported and has no effect')

        super().__init__(name, address, terminator='\r\n', **kwargs)

        self.visa_handle.baud_rate = 9600
        self.visa_handle.parity = visa.constants.Parity.none
        self.visa_handle.stop_bits = visa.constants.StopBits.one
        self.visa_handle.data_bits = 8
        self.visa_handle.flow_control = 0
        self.visa_handle.flush(vi_const.VI_READ_BUF_DISCARD |
                               vi_const.VI_WRITE_BUF_DISCARD)  # keep for debugging

        idn = self.IDN.get()
        print(idn)

        self._persistentField = 0  # temp code stub
        self._coil_constant = coil_constant
        self._current_rating = current_rating
        self._current_ramp_limit = current_ramp_limit
        self._field_rating = coil_constant * \
            current_rating  # corresponding max field based
        self._field_ramp_limit = coil_constant * current_ramp_limit

        self.add_parameter(name='unit',
                           get_cmd=self._get_unit,
                           set_cmd=self._set_unit,
                           val_mapping={'AMPS': 0, 'TESLA': 1})

        self.add_parameter('rampStatus',
                           get_cmd=self._get_rampStatus,
                           val_mapping={'HOLDING': 0,
                                        'RAMPING': 1,
                                        'QUENCH DETECTED': 2,
                                        'EXTERNAL TRIP': 3,
                                        'FAULT': 4,
                                        })

        self.add_parameter('polarity',
                           get_cmd=self._get_polarity,
                           set_cmd=self._set_polarity,
                           val_mapping={'POSITIVE': '+', 'NEGATIVE': '-'})

        self.add_parameter(name='switchHeater',
                           get_cmd=self._get_switchHeater,
                           set_cmd=self._set_switchHeater,
                           val_mapping={False: 0, True: 1})

        self.add_parameter('persistentMode',
                           get_cmd=self._get_persistentMode,
                           set_cmd=self._set_persistentMode,
                           val_mapping={False: 0, True: 1})

        self.add_parameter(name='persistentField',
                           get_cmd=self._get_persistentField,
                           vals=Numbers(self._persistentField))

        self.add_parameter(name='field',
                           get_cmd=self._get_field,
                           set_cmd=self._set_field,
                           vals=Numbers(-self._field_rating,  # i.e. ~12T, calculated
                                        self._field_rating))

        self.add_parameter(name='maxField',
                           get_cmd=self._get_maxField,
                           set_cmd=self._set_maxField,
                           vals=Numbers(0,  # i.e. ~12T, calculated
                                        self._field_rating))

        self.add_parameter(name='rampRate',
                           get_cmd=self._get_rampRate,
                           set_cmd=self._set_rampRate,
                           vals=Numbers(0,
                                        self._current_ramp_limit))

        self.add_parameter('pauseRamp',
                           set_cmd=self._set_pauseRamp,
                           get_cmd=self._get_pauseRamp,
                           val_mapping={False: 0, True: 1})
Beispiel #15
0
    def __init__(self, name, address=None, port=None,
                 reset=False, terminator='\r\n',
                 current_ramp_limit=None, has_current_rating=False,
                 **kwargs):

        super().__init__(name, address, port, terminator=terminator,
                         write_confirmation=False, **kwargs)
        self._parent_instrument = None
        self.has_current_rating = has_current_rating

        # Add reset function
        self.add_function('reset', call_cmd='*RST')
        if reset:
            self.reset()

        # Add parameters setting instrument units
        self.add_parameter("ramp_rate_units",
                           get_cmd='RAMP:RATE:UNITS?',
                           set_cmd=(lambda units:
                                    self._update_units(ramp_rate_units=units)),
                           val_mapping={'seconds': 0,
                                        'minutes': 1})
        self.add_parameter('field_units',
                           get_cmd='FIELD:UNITS?',
                           set_cmd=(lambda units:
                                    self._update_units(field_units=units)),
                           val_mapping={'kilogauss': 0,
                                        'tesla': 1})

        # Set programatic safety limits
        self.add_parameter('current_ramp_limit',
                           get_cmd=lambda: self._current_ramp_limit,
                           set_cmd=self._update_ramp_rate_limit,
                           unit="A/s")
        self.add_parameter('field_ramp_limit',
                           get_cmd=lambda: self.current_ramp_limit(),
                           set_cmd=lambda x: self.current_ramp_limit(x),
                           scale=1/float(self.ask("COIL?")),
                           unit="T/s")
        if current_ramp_limit is None:
            self._update_ramp_rate_limit(AMI430._DEFAULT_CURRENT_RAMP_LIMIT,
                                         update=False)
        else:
            self._update_ramp_rate_limit(current_ramp_limit, update=False)

        # Add solenoid parameters
        self.add_parameter('coil_constant',
                           get_cmd=self._update_coil_constant,
                           set_cmd=self._update_coil_constant,
                           vals=Numbers(0.001, 999.99999))

        # TODO: Not all AMI430s expose this setting. Currently, we
        # don't know why, but this most likely a firmware version issue,
        # so eventually the following condition will be smth like
        # if firmware_version > XX
        if has_current_rating:
            self.add_parameter('current_rating',
                               get_cmd="CURR:RATING?",
                               get_parser=float,
                               set_cmd="CONF:CURR:RATING {}",
                               unit="A",
                               vals=Numbers(0.001, 9999.9999))

            self.add_parameter('field_rating',
                               get_cmd=lambda: self.current_rating(),
                               set_cmd=lambda x: self.current_rating(x),
                               scale=1/float(self.ask("COIL?")))

        self.add_parameter('current_limit',
                           unit="A",
                           set_cmd="CONF:CURR:LIMIT {}",
                           get_cmd='CURR:LIMIT?',
                           get_parser=float,
                           vals=Numbers(0, 80))  # what are good numbers here?

        self.add_parameter('field_limit',
                           set_cmd=self.current_limit.set,
                           get_cmd=self.current_limit.get,
                           scale=1/float(self.ask("COIL?")))

        # Add current solenoid parameters
        # Note that field is validated in set_field
        self.add_parameter('field',
                           get_cmd='FIELD:MAG?',
                           get_parser=float,
                           set_cmd=self.set_field)
        self.add_parameter('ramp_rate',
                           get_cmd=self._get_ramp_rate,
                           set_cmd=self._set_ramp_rate)
        self.add_parameter('setpoint',
                           get_cmd='FIELD:TARG?',
                           get_parser=float)
        self.add_parameter('is_quenched',
                           get_cmd='QU?',
                           val_mapping={True: 1, False: 0})
        self.add_function('reset_quench', call_cmd='QU 0')
        self.add_function('set_quenched', call_cmd='QU 1')
        self.add_parameter('ramping_state',
                           get_cmd='STATE?',
                           get_parser=int,
                           val_mapping={
                               'ramping': 1,
                               'holding': 2,
                               'paused': 3,
                               'manual up': 4,
                               'manual down': 5,
                               'zeroing current': 6,
                               'quench detected': 7,
                               'at zero current': 8,
                               'heating switch': 9,
                               'cooling switch': 10,
                           })

        # Add persistent switch
        switch_heater = AMI430SwitchHeater(self)
        self.add_submodule("switch_heater", switch_heater)

        # Add interaction functions
        self.add_function('get_error', call_cmd='SYST:ERR?')
        self.add_function('ramp', call_cmd='RAMP')
        self.add_function('pause', call_cmd='PAUSE')
        self.add_function('zero', call_cmd='ZERO')

        # Correctly assign all units
        self._update_units()

        self.connect_message()
Beispiel #16
0
    def __init__(self, parent: 'Keithley2450', name: str,
                 proper_function: str) -> None:
        super().__init__(parent, name)
        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.sense_function

        self.add_parameter(
            "four_wire_measurement",
            set_cmd=f":SENSe:{self._proper_function}:RSENse {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RSENse?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        self.add_parameter(
            "range",
            set_cmd=f":SENSe:{self._proper_function}:RANGe {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RANGe?",
            vals=range_vals,
            get_parser=float,
            unit=unit)

        self.add_parameter(
            "auto_range",
            set_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO {{}}",
            get_cmd=f":SENSe:{self._proper_function}:RANGe:AUTO?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        self.add_parameter(self._proper_function,
                           get_cmd=self._measure,
                           get_parser=float,
                           unit=unit,
                           snapshot_value=False)

        self.add_parameter("sweep",
                           label=self._proper_function,
                           get_cmd=self._measure_sweep,
                           unit=unit,
                           vals=Arrays(shape=(self.parent.npts, )),
                           parameter_class=ParameterWithSetpointsCustomized)

        self.add_parameter(
            "nplc",
            get_cmd=f":SENSe:{self._proper_function}:NPLCycles?",
            set_cmd=f":SENSe:{self._proper_function}:NPLCycles {{}}",
            vals=Numbers(0.001, 10))

        self.add_parameter('user_number',
                           get_cmd=None,
                           set_cmd=None,
                           initial_value=1,
                           vals=Ints(1, 5))

        self.add_parameter("user_delay",
                           get_cmd=self._get_user_delay,
                           set_cmd=self._set_user_delay,
                           vals=Numbers(0, 1e4))

        self.add_parameter(
            'auto_zero_enabled',
            get_cmd=f":SENSe:{self._proper_function}:AZERo?",
            set_cmd=f":SENSe:{self._proper_function}:AZERo {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="This command enables or disables automatic updates to"
            "the internal reference measurements (autozero) of the"
            "instrument.")

        self.add_parameter(
            'count',
            get_cmd=":SENSe:COUNt?",
            set_cmd=":SENSe:COUNt {}",
            docstring="The number of measurements to make when a measurement "
            "is requested.")
Beispiel #17
0
    def __init__(self, name, instrument_x, instrument_y,
                 instrument_z, field_limit, **kwargs):
        super().__init__(name, **kwargs)

        if not isinstance(name, str):
            raise ValueError("Name should be a string")

        instruments = [instrument_x, instrument_y, instrument_z]

        if not all([isinstance(instrument, AMI430)
                    for instrument in instruments]):
            raise ValueError("Instruments need to be instances "
                             "of the class AMI430")

        self._instrument_x = instrument_x
        self._instrument_y = instrument_y
        self._instrument_z = instrument_z

        if repr(field_limit).isnumeric() or isinstance(field_limit, collections.Iterable):
            self._field_limit = field_limit
        else:
            raise ValueError("field limit should either be"
                             " a number or an iterable")

        self._set_point = FieldVector(
            x=self._instrument_x.field(),
            y=self._instrument_y.field(),
            z=self._instrument_z.field()
        )

        # Get-only parameters that return a measured value
        self.add_parameter(
            'cartesian_measured',
            get_cmd=partial(self._get_measured, 'x', 'y', 'z'),
            unit='T'
        )

        self.add_parameter(
            'x_measured',
            get_cmd=partial(self._get_measured, 'x'),
            unit='T'
        )

        self.add_parameter(
            'y_measured',
            get_cmd=partial(self._get_measured, 'y'),
            unit='T'
        )

        self.add_parameter(
            'z_measured',
            get_cmd=partial(self._get_measured, 'z'),
            unit='T'
        )

        self.add_parameter(
            'spherical_measured',
            get_cmd=partial(
                self._get_measured,
                'r',
                'theta',
                'phi'
            ),
            unit='T'
        )

        self.add_parameter(
            'phi_measured',
            get_cmd=partial(self._get_measured, 'phi'),
            unit='deg'
        )

        self.add_parameter(
            'theta_measured',
            get_cmd=partial(self._get_measured, 'theta'),
            unit='deg'
        )

        self.add_parameter(
            'field_measured',
            get_cmd=partial(self._get_measured, 'r'),
            unit='T')

        self.add_parameter(
            'cylindrical_measured',
            get_cmd=partial(self._get_measured,
                            'rho',
                            'phi',
                            'z'),
            unit='T')

        self.add_parameter(
            'rho_measured',
            get_cmd=partial(self._get_measured, 'rho'),
            unit='T'
        )

        # Get and set parameters for the set points of the coordinates
        self.add_parameter(
            'cartesian',
            get_cmd=partial(self._get_setpoints, ('x', 'y', 'z')),
            set_cmd=partial(self._set_setpoints, ('x', 'y', 'z')),
            unit='T',
            vals=Anything()
        )

        self.add_parameter(
            'x',
            get_cmd=partial(self._get_setpoints, ('x',)),
            set_cmd=partial(self._set_setpoints, ('x',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'y',
            get_cmd=partial(self._get_setpoints, ('y',)),
            set_cmd=partial(self._set_setpoints, ('y',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'z',
            get_cmd=partial(self._get_setpoints, ('z',)),
            set_cmd=partial(self._set_setpoints, ('z',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'spherical',
            get_cmd=partial(
                self._get_setpoints, ('r', 'theta', 'phi')
            ),
            set_cmd=partial(
                self._set_setpoints, ('r', 'theta', 'phi')
            ),
            unit='tuple?',
            vals=Anything()
        )

        self.add_parameter(
            'phi',
            get_cmd=partial(self._get_setpoints, ('phi',)),
            set_cmd=partial(self._set_setpoints, ('phi',)),
            unit='deg',
            vals=Numbers()
        )

        self.add_parameter(
            'theta',
            get_cmd=partial(self._get_setpoints, ('theta',)),
            set_cmd=partial(self._set_setpoints, ('theta',)),
            unit='deg',
            vals=Numbers()
        )

        self.add_parameter(
            'field',
            get_cmd=partial(self._get_setpoints, ('r',)),
            set_cmd=partial(self._set_setpoints, ('r',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'cylindrical',
            get_cmd=partial(
                self._get_setpoints, ('rho', 'phi', 'z')
            ),
            set_cmd=partial(
                self._set_setpoints, ('rho', 'phi', 'z')
            ),
            unit='tuple?',
            vals=Anything()
        )

        self.add_parameter(
            'rho',
            get_cmd=partial(self._get_setpoints, ('rho',)),
            set_cmd=partial(self._set_setpoints, ('rho',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'block_during_ramp',
            set_cmd=None,
            initial_value=True,
            unit='',
            vals=Bool()
        )
Beispiel #18
0
class Source2450(InstrumentChannel):
    """
    The source module of the Keithley 2450 SMU.

    Args:
        parent
        name
        proper_function: This can be one of either "current" or "voltage"
            All parameters and methods in this submodule should only be
            accessible to the user if
            self.parent.source_function.get() == self._proper_function. We
            ensure this through the 'source' property on the main driver class
            which returns the proper submodule for any given function mode
    """
    function_modes = {
        "current": {
            "name": "CURR",
            "unit": "A",
            "range_vals": Numbers(-1, 1)
        },
        "voltage": {
            "name": "VOLT",
            "unit": "V",
            "range_vals": Numbers(-200, 200)
        }
    }

    def __init__(self, parent: 'Keithley2450', name: str,
                 proper_function: str) -> None:
        super().__init__(parent, name)
        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.source_function
        self._sweep_arguments: Dict[str, Union[float, int, str]] = {}

        self.add_parameter("range",
                           set_cmd=f":SOUR:{self._proper_function}:RANGe {{}}",
                           get_cmd=f":SOUR:{self._proper_function}:RANGe?",
                           vals=range_vals,
                           get_parser=float,
                           unit=unit)

        self.add_parameter(
            "auto_range",
            set_cmd=f":SOURce:{self._proper_function}:RANGe:AUTO {{}}",
            get_cmd=f":SOURce:{self._proper_function}:RANGe:AUTO?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        limit_cmd = {
            "current": "VLIM",
            "voltage": "ILIM"
        }[self._proper_function]
        self.add_parameter(
            "limit",
            set_cmd=f"SOUR:{self._proper_function}:{limit_cmd} {{}}",
            get_cmd=f"SOUR:{self._proper_function}:{limit_cmd}?",
            get_parser=float,
            unit=unit)

        self.add_parameter(
            "limit_tripped",
            get_cmd=f":SOUR:{self._proper_function}:{limit_cmd}:TRIPped?",
            val_mapping={
                True: 1,
                False: 0
            })

        self.add_parameter(self._proper_function,
                           set_cmd=f"SOUR:{self._proper_function} {{}}",
                           get_cmd=f"SOUR:{self._proper_function}?",
                           get_parser=float,
                           unit=unit,
                           snapshot_value=False)

        self.add_parameter("sweep_axis",
                           label=self._proper_function,
                           get_cmd=self.get_sweep_axis,
                           vals=Arrays(shape=(self.parent.npts, )),
                           unit=unit)

        self.add_parameter(
            "delay",
            get_cmd=f":SOURce:{self._proper_function}:DELay?",
            set_cmd=f":SOURce:{self._proper_function}:DELay {{}}",
            vals=Numbers(0, 1e4))

        self.add_parameter('user_number',
                           get_cmd=None,
                           set_cmd=None,
                           initial_value=1,
                           vals=Ints(1, 5))

        self.add_parameter("user_delay",
                           get_cmd=self._get_user_delay,
                           set_cmd=self._set_user_delay,
                           vals=Numbers(0, 1e4))

        self.add_parameter(
            "auto_delay",
            get_cmd=f":SOURce:{self._proper_function}:DELay:AUTO?",
            set_cmd=f":SOURce:{self._proper_function}:DELay:AUTO {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        self.add_parameter(
            "read_back_enabled",
            get_cmd=f":SOURce:{self._proper_function}:READ:BACK?",
            set_cmd=f":SOURce:{self._proper_function}:READ:BACK {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="This command determines if the instrument records the "
            "measured source value or the configured source value "
            "when making a measurement.")

    def get_sweep_axis(self) -> np.ndarray:
        if self._sweep_arguments == {}:
            raise ValueError(
                "Please setup the sweep before getting values of this parameter"
            )

        return np.linspace(start=self._sweep_arguments["start"],
                           stop=self._sweep_arguments["stop"],
                           num=self._sweep_arguments["step_count"])

    def sweep_setup(self,
                    start: float,
                    stop: float,
                    step_count: int,
                    delay: float = 0,
                    sweep_count: int = 1,
                    range_mode: str = "AUTO",
                    fail_abort: str = "ON",
                    dual: str = "OFF",
                    buffer_name: str = "defbuffer1") -> None:

        self._sweep_arguments = dict(start=start,
                                     stop=stop,
                                     step_count=step_count,
                                     delay=delay,
                                     sweep_count=sweep_count,
                                     range_mode=range_mode,
                                     fail_abort=fail_abort,
                                     dual=dual,
                                     buffer_name=buffer_name)

    def sweep_start(self) -> None:
        """
        Start a sweep and return when the sweep has finished.
        Note: This call is blocking
        """
        cmd_args = dict(self._sweep_arguments)
        cmd_args["function"] = self._proper_function

        cmd = ":SOURce:SWEep:{function}:LINear {start},{stop}," \
              "{step_count},{delay},{sweep_count},{range_mode}," \
              "{fail_abort},{dual},'{buffer_name}'".format(**cmd_args)

        self.write(cmd)
        self.write(":INITiate")
        self.write("*WAI")

    def sweep_reset(self) -> None:
        self._sweep_arguments = {}

    def _get_user_delay(self) -> str:
        get_cmd = f":SOURce:{self._proper_function}:DELay:USER" \
                  f"{self.user_number()}?"
        return self.ask(get_cmd)

    def _set_user_delay(self, value) -> None:
        set_cmd = f":SOURce:{self._proper_function}:DELay:USER" \
                  f"{self.user_number()} {value}"
        self.write(set_cmd)
Beispiel #19
0
    def initialize(self, reverse_clearance: int = 0) -> None:
        """
        Prepares motor for operation

        Configure the motor settings and perform mechanical limit seeking
        Digital input 6 is configured as the external limit switch with
        inverted polarity (such that the controller is triggered when
        the limit switch turns off).
        The external limit switch is configured for free run backwards
        mode during an external reference run and stop mode during normal
        runs.
        """
        self.command_response('Enabled')
        self.firmware_version()
        self.phase_current(20)
        self.phase_current_standstill(0)
        self.limit_switch_behavior(int(0b0010010000100010))
        self.io_polarity(int(0b110000000000011111))
        self.digital_input_6_function('ExternalLimitSwitch')
        self.error_correction('Off')
        self.reverse_clearance(reverse_clearance)
        self.acceleration_mode('Jerk-free')
        self.acceleration_jerk(1)
        self.braking_jerk(100000000)
        self.step_mode(4)

        # Escape the limit if we are currently at one
        previous_direction = self.direction()
        if self.limit_switch_on():
            for i in range(1, 3):
                if previous_direction == 'Left':
                    direction = 'Right'
                else:
                    direction = 'Left'
                self._escape_limit(direction, steps=30 * i)
                previous_direction = self.direction()

        # Find the limits by driving to the upper limit in external reference
        # run mode and then driving to lower limit in relative mode until
        # the limit switch is reached and the motor stops
        print(f'Finding {self.name} motor travel limits')
        self._find_limits()
        # Travel away from the limit
        self._travel_away_from_limit()
        self.limit_switch_behavior(0b10010000100010)
        self._is_initialized = True

        self.add_parameter(
            'setting_normalized',
            label='Normalized Setting',
            unit='',
            get_cmd=(lambda: self.position()),
            set_cmd=(lambda x: self.drive_motor(x)),
            get_parser=(lambda x: float(x) / self._upper_bound),
            set_parser=(lambda x: round(self._upper_bound * x)),
            vals=Numbers(min_value=0.0, max_value=1.0),
            docstring=('Normalized setting (position)'
                       'Min value: 0'
                       'Max value: 1'
                       'Automatically mapped between lower and upper'
                       'bound of limit switch'))
Beispiel #20
0
    def __init__(self, parent: 'Keithley2450', name: str,
                 proper_function: str) -> None:
        super().__init__(parent, name)
        self._proper_function = proper_function
        range_vals = self.function_modes[self._proper_function]["range_vals"]
        unit = self.function_modes[self._proper_function]["unit"]

        self.function = self.parent.source_function
        self._sweep_arguments: Dict[str, Union[float, int, str]] = {}

        self.add_parameter("range",
                           set_cmd=f":SOUR:{self._proper_function}:RANGe {{}}",
                           get_cmd=f":SOUR:{self._proper_function}:RANGe?",
                           vals=range_vals,
                           get_parser=float,
                           unit=unit)

        self.add_parameter(
            "auto_range",
            set_cmd=f":SOURce:{self._proper_function}:RANGe:AUTO {{}}",
            get_cmd=f":SOURce:{self._proper_function}:RANGe:AUTO?",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        limit_cmd = {
            "current": "VLIM",
            "voltage": "ILIM"
        }[self._proper_function]
        self.add_parameter(
            "limit",
            set_cmd=f"SOUR:{self._proper_function}:{limit_cmd} {{}}",
            get_cmd=f"SOUR:{self._proper_function}:{limit_cmd}?",
            get_parser=float,
            unit=unit)

        self.add_parameter(
            "limit_tripped",
            get_cmd=f":SOUR:{self._proper_function}:{limit_cmd}:TRIPped?",
            val_mapping={
                True: 1,
                False: 0
            })

        self.add_parameter(self._proper_function,
                           set_cmd=f"SOUR:{self._proper_function} {{}}",
                           get_cmd=f"SOUR:{self._proper_function}?",
                           get_parser=float,
                           unit=unit,
                           snapshot_value=False)

        self.add_parameter("sweep_axis",
                           label=self._proper_function,
                           get_cmd=self.get_sweep_axis,
                           vals=Arrays(shape=(self.parent.npts, )),
                           unit=unit)

        self.add_parameter(
            "delay",
            get_cmd=f":SOURce:{self._proper_function}:DELay?",
            set_cmd=f":SOURce:{self._proper_function}:DELay {{}}",
            vals=Numbers(0, 1e4))

        self.add_parameter('user_number',
                           get_cmd=None,
                           set_cmd=None,
                           initial_value=1,
                           vals=Ints(1, 5))

        self.add_parameter("user_delay",
                           get_cmd=self._get_user_delay,
                           set_cmd=self._set_user_delay,
                           vals=Numbers(0, 1e4))

        self.add_parameter(
            "auto_delay",
            get_cmd=f":SOURce:{self._proper_function}:DELay:AUTO?",
            set_cmd=f":SOURce:{self._proper_function}:DELay:AUTO {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"))

        self.add_parameter(
            "read_back_enabled",
            get_cmd=f":SOURce:{self._proper_function}:READ:BACK?",
            set_cmd=f":SOURce:{self._proper_function}:READ:BACK {{}}",
            val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"),
            docstring="This command determines if the instrument records the "
            "measured source value or the configured source value "
            "when making a measurement.")
    def __init__(self, name, address, **kwargs):
        super().__init__(name, address, **kwargs)

        # Reference and phase
        self.add_parameter('phase',
                           label='Phase',
                           get_cmd='PHAS?',
                           get_parser=float,
                           set_cmd='PHAS {:.2f}',
                           unit='deg',
                           vals=Numbers(min_value=-360, max_value=729.99))

        self.add_parameter('reference_source',
                           label='Reference source',
                           get_cmd='FMOD?',
                           set_cmd='FMOD {}',
                           val_mapping={
                               'external': 0,
                               'internal': 1,
                           },
                           vals=Enum('external', 'internal'))

        self.add_parameter('frequency',
                           label='Frequency',
                           get_cmd='FREQ?',
                           get_parser=float,
                           set_cmd='FREQ {:.4f}',
                           unit='Hz',
                           vals=Numbers(min_value=1e-3, max_value=102e3))

        self.add_parameter('ext_trigger',
                           label='External trigger',
                           get_cmd='RSLP?',
                           set_cmd='RSLP {}',
                           val_mapping={
                               'sine': 0,
                               'TTL rising': 1,
                               'TTL falling': 2,
                           })

        self.add_parameter('harmonic',
                           label='Harmonic',
                           get_cmd='HARM?',
                           get_parser=int,
                           set_cmd='HARM {:d}',
                           vals=Ints(min_value=1, max_value=19999))

        self.add_parameter('amplitude',
                           label='Amplitude',
                           get_cmd='SLVL?',
                           get_parser=float,
                           set_cmd='SLVL {:.3f}',
                           unit='V',
                           vals=Numbers(min_value=0.004, max_value=5.000))

        # Input and filter
        self.add_parameter('input_config',
                           label='Input configuration',
                           get_cmd='ISRC?',
                           get_parser=self._get_input_config,
                           set_cmd='ISRC {}',
                           set_parser=self._set_input_config,
                           vals=Enum(*self._INPUT_CONFIG_TO_N.keys()))

        self.add_parameter('input_shield',
                           label='Input shield',
                           get_cmd='IGND?',
                           set_cmd='IGND {}',
                           val_mapping={
                               'float': 0,
                               'ground': 1,
                           })

        self.add_parameter('input_coupling',
                           label='Input coupling',
                           get_cmd='ICPL?',
                           set_cmd='ICPL {}',
                           val_mapping={
                               'AC': 0,
                               'DC': 1,
                           })

        self.add_parameter('notch_filter',
                           label='Notch filter',
                           get_cmd='ILIN?',
                           set_cmd='ILIN {}',
                           val_mapping={
                               'off': 0,
                               'line in': 1,
                               '2x line in': 2,
                               'both': 3,
                           })

        # Gain and time constant
        self.add_parameter(name='sensitivity',
                           label='Sensitivity',
                           get_cmd='SENS?',
                           set_cmd='SENS {:d}',
                           get_parser=self._get_sensitivity,
                           set_parser=self._set_sensitivity)

        self.add_parameter('reserve',
                           label='Reserve',
                           get_cmd='RMOD?',
                           set_cmd='RMOD {}',
                           val_mapping={
                               'high': 0,
                               'normal': 1,
                               'low noise': 2,
                           })

        self.add_parameter('time_constant',
                           label='Time constant',
                           get_cmd='OFLT?',
                           set_cmd='OFLT {}',
                           unit='s',
                           val_mapping={
                               10e-6: 0,
                               30e-6: 1,
                               100e-6: 2,
                               300e-6: 3,
                               1e-3: 4,
                               3e-3: 5,
                               10e-3: 6,
                               30e-3: 7,
                               100e-3: 8,
                               300e-3: 9,
                               1: 10,
                               3: 11,
                               10: 12,
                               30: 13,
                               100: 14,
                               300: 15,
                               1e3: 16,
                               3e3: 17,
                               10e3: 18,
                               30e3: 19,
                           })

        self.add_parameter('filter_slope',
                           label='Filter slope',
                           get_cmd='OFSL?',
                           set_cmd='OFSL {}',
                           unit='dB/oct',
                           val_mapping={
                               6: 0,
                               12: 1,
                               18: 2,
                               24: 3,
                           })

        self.add_parameter('sync_filter',
                           label='Sync filter',
                           get_cmd='SYNC?',
                           set_cmd='SYNC {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        def parse_offset_get(s):
            parts = s.split(',')

            return float(parts[0]), int(parts[1])

        # TODO: Parameters that can be set with multiple arguments
        # For the OEXP command for example two arguments are needed
        self.add_parameter('X_offset',
                           get_cmd='OEXP? 1',
                           get_parser=parse_offset_get)

        self.add_parameter('Y_offset',
                           get_cmd='OEXP? 2',
                           get_parser=parse_offset_get)

        self.add_parameter('R_offset',
                           get_cmd='OEXP? 3',
                           get_parser=parse_offset_get)

        # Aux input/output
        for i in [1, 2, 3, 4]:
            self.add_parameter('aux_in{}'.format(i),
                               label='Aux input {}'.format(i),
                               get_cmd='OAUX? {}'.format(i),
                               get_parser=float,
                               unit='V')

            self.add_parameter('aux_out{}'.format(i),
                               label='Aux output {}'.format(i),
                               get_cmd='AUXV? {}'.format(i),
                               get_parser=float,
                               set_cmd='AUXV {0}, {{}}'.format(i),
                               unit='V')

        # Setup
        self.add_parameter('output_interface',
                           label='Output interface',
                           get_cmd='OUTX?',
                           set_cmd='OUTX {}',
                           val_mapping={
                               'RS232': '0\n',
                               'GPIB': '1\n',
                           })

        # Channel setup
        for ch in range(1, 3):

            # detailed validation and mapping performed in set/get functions
            self.add_parameter('ch{}_ratio'.format(ch),
                               label='Channel {} ratio'.format(ch),
                               get_cmd=partial(self._get_ch_ratio, ch),
                               set_cmd=partial(self._set_ch_ratio, ch),
                               vals=Strings())
            self.add_parameter('ch{}_display'.format(ch),
                               label='Channel {} display'.format(ch),
                               get_cmd=partial(self._get_ch_display, ch),
                               set_cmd=partial(self._set_ch_display, ch),
                               vals=Strings())
            self.add_parameter('ch{}_databuffer'.format(ch),
                               channel=ch,
                               parameter_class=ChannelBuffer)

        # Data transfer
        self.add_parameter('X', get_cmd='OUTP? 1', get_parser=float, unit='V')

        self.add_parameter('Y', get_cmd='OUTP? 2', get_parser=float, unit='V')

        self.add_parameter('R', get_cmd='OUTP? 3', get_parser=float, unit='V')

        self.add_parameter('P',
                           get_cmd='OUTP? 4',
                           get_parser=float,
                           unit='deg')

        # Data buffer settings
        self.add_parameter('buffer_SR',
                           label='Buffer sample rate',
                           get_cmd='SRAT ?',
                           set_cmd=self._set_buffer_SR,
                           unit='Hz',
                           val_mapping={
                               62.5e-3: 0,
                               0.125: 1,
                               0.250: 2,
                               0.5: 3,
                               1: 4,
                               2: 5,
                               4: 6,
                               8: 7,
                               16: 8,
                               32: 9,
                               64: 10,
                               128: 11,
                               256: 12,
                               512: 13,
                               'Trigger': 14
                           },
                           get_parser=int)

        self.add_parameter('buffer_acq_mode',
                           label='Buffer acquistion mode',
                           get_cmd='SEND ?',
                           set_cmd='SEND {}',
                           val_mapping={
                               'single shot': 0,
                               'loop': 1
                           },
                           get_parser=int)

        self.add_parameter('buffer_trig_mode',
                           label='Buffer trigger start mode',
                           get_cmd='TSTR ?',
                           set_cmd='TSTR {}',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           get_parser=int)

        self.add_parameter('buffer_npts',
                           label='Buffer number of stored points',
                           get_cmd='SPTS ?',
                           get_parser=int)

        # Auto functions
        self.add_function('auto_gain', call_cmd='AGAN')
        self.add_function('auto_reserve', call_cmd='ARSV')
        self.add_function('auto_phase', call_cmd='APHS')
        self.add_function('auto_offset',
                          call_cmd='AOFF {0}',
                          args=[Enum(1, 2, 3)])

        # Interface
        self.add_function('reset', call_cmd='*RST')

        self.add_function('disable_front_panel', call_cmd='OVRM 0')
        self.add_function('enable_front_panel', call_cmd='OVRM 1')

        self.add_function('send_trigger',
                          call_cmd='TRIG',
                          docstring=("Send a software trigger. "
                                     "This command has the same effect as a "
                                     "trigger at the rear panel trigger"
                                     " input."))

        self.add_function('buffer_start',
                          call_cmd='STRT',
                          docstring=("The buffer_start command starts or "
                                     "resumes data storage. buffer_start"
                                     " is ignored if storage is already in"
                                     " progress."))

        self.add_function('buffer_pause',
                          call_cmd='PAUS',
                          docstring=("The buffer_pause command pauses data "
                                     "storage. If storage is already paused "
                                     "or reset then this command is ignored."))

        self.add_function('buffer_reset',
                          call_cmd='REST',
                          docstring=("The buffer_reset command resets the data"
                                     " buffers. The buffer_reset command can "
                                     "be sent at any time - any storage in "
                                     "progress, paused or not, will be reset."
                                     " This command will erase the data "
                                     "buffer."))

        # Initialize the proper units of the outputs and sensitivities
        self.input_config()

        # start keeping track of buffer setpoints
        self._buffer1_ready = False
        self._buffer2_ready = False

        self.connect_message()
Beispiel #22
0
    def __init__(self,
                 name: str,
                 address: str,
                 terminator: str = "\n",
                 **kwargs) -> None:
        super().__init__(name, address, terminator=terminator, **kwargs)

        self.add_parameter('output',
                           label='Output State',
                           get_cmd=self.state,
                           set_cmd=lambda x: self.on() if x else self.off(),
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        self.add_parameter('source_mode',
                           label='Source Mode',
                           get_cmd=':SOUR:FUNC?',
                           set_cmd=self._set_source_mode,
                           vals=Enum('VOLT', 'CURR'))

        # We need to get the source_mode value here as we cannot rely on the
        # default value that may have been changed before we connect to the
        # instrument (in a previous session or via the frontpanel).
        self.source_mode()

        self.add_parameter('voltage_range',
                           label='Voltage Source Range',
                           unit='V',
                           get_cmd=partial(self._get_range, "VOLT"),
                           set_cmd=partial(self._set_range, "VOLT"),
                           vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0),
                           snapshot_exclude=self.source_mode() == 'CURR')

        self.add_parameter('current_range',
                           label='Current Source Range',
                           unit='I',
                           get_cmd=partial(self._get_range, "CURR"),
                           set_cmd=partial(self._set_range, "CURR"),
                           vals=Enum(1e-3, 10e-3, 100e-3, 200e-3),
                           snapshot_exclude=self.source_mode() == "VOLT")

        self.add_parameter('range',
                           parameter_class=DelegateParameter,
                           source=None)

        # The instrument does not support auto range. The parameter
        # auto_range is introduced to add this capability with
        # setting the initial state at False mode.
        self.add_parameter('auto_range',
                           label='Auto Range',
                           set_cmd=self._set_auto_range,
                           get_cmd=None,
                           initial_cache_value=False,
                           vals=Bool())

        self.add_parameter('voltage',
                           label='Voltage',
                           unit='V',
                           set_cmd=partial(self._get_set_output, "VOLT"),
                           get_cmd=partial(self._get_set_output, "VOLT"),
                           snapshot_exclude=self.source_mode() == "CURR")

        self.add_parameter('current',
                           label='Current',
                           unit='I',
                           set_cmd=partial(self._get_set_output, "CURR"),
                           get_cmd=partial(self._get_set_output, "CURR"),
                           snapshot_exclude=self.source_mode() == 'VOLT')

        self.add_parameter('output_level',
                           parameter_class=DelegateParameter,
                           source=None)

        # We need to pass the source parameter for delegate parameters
        # (range and output_level) here according to the present
        # source_mode.
        if self.source_mode() == 'VOLT':
            self.range.source = self.voltage_range
            self.output_level.source = self.voltage
        else:
            self.range.source = self.current_range
            self.output_level.source = self.current

        self.add_parameter('voltage_limit',
                           label='Voltage Protection Limit',
                           unit='V',
                           vals=Ints(1, 30),
                           get_cmd=":SOUR:PROT:VOLT?",
                           set_cmd=":SOUR:PROT:VOLT {}",
                           get_parser=float_round,
                           set_parser=int)

        self.add_parameter('current_limit',
                           label='Current Protection Limit',
                           unit='I',
                           vals=Numbers(1e-3, 200e-3),
                           get_cmd=":SOUR:PROT:CURR?",
                           set_cmd=":SOUR:PROT:CURR {:.3f}",
                           get_parser=float,
                           set_parser=float)

        self.add_parameter('four_wire',
                           label='Four Wire Sensing',
                           get_cmd=':SENS:REM?',
                           set_cmd=':SENS:REM {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        # Note: The guard feature can be used to remove common mode noise.
        # Read the manual to see if you would like to use it
        self.add_parameter('guard',
                           label='Guard Terminal',
                           get_cmd=':SENS:GUAR?',
                           set_cmd=':SENS:GUAR {}',
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        # Return measured line frequency
        self.add_parameter("line_freq",
                           label='Line Frequency',
                           unit="Hz",
                           get_cmd="SYST:LFR?",
                           get_parser=int)

        # Check if monitor is present, and if so enable measurement
        monitor_present = '/MON' in self.ask("*OPT?")
        measure = GS200_Monitor(self, 'measure', monitor_present)
        self.add_submodule('measure', measure)

        # Reset function
        self.add_function('reset', call_cmd='*RST')

        self.connect_message()
Beispiel #23
0
 def __init__(self, name: str, address: str, **kwargs) -> None:
     super().__init__(name, address,  terminator='\n', **kwargs)
     # general commands
     self.add_parameter(name='frequency',
                        label='Frequency',
                        unit='Hz',
                        get_cmd='FREQ?',
                        set_cmd='FREQ {}',
                        get_parser=float,
                        vals=Numbers(min_value=100e3,
                                     max_value=40e9))
     self.add_parameter(name='freq_offset',
                        label='Frequency offset',
                        unit='Hz',
                        get_cmd='FREQ:OFFS?',
                        set_cmd='FREQ:OFFS {}',
                        get_parser=float,
                        vals=Numbers(min_value=-200e9,
                                     max_value=200e9))
     self.add_parameter('freq_mode',
                        label='Frequency mode',
                        set_cmd='FREQ:MODE {}',
                        get_cmd='FREQ:MODE?',
                        vals=vals.Enum('FIX', 'CW', 'SWE', 'LIST'))
     self.add_parameter('pulse_width',
                        label='Pulse width',
                        unit='ns',
                        set_cmd='PULM:INT:PWID {}',
                        get_cmd='PULM:INT:PWID?',
                        vals=Numbers(min_value=10e-9,
                                     max_value=20e-9))
     self.add_parameter(name='phase',
                        label='Phase',
                        unit='deg',
                        get_cmd='PHAS?',
                        set_cmd='PHAS {}',
                        get_parser=self.rad_to_deg,
                        set_parser=self.deg_to_rad,
                        vals=Numbers(min_value=-180,
                                     max_value=179))
     self.add_parameter(name='power',
                        label='Power',
                        unit='dBm',
                        get_cmd='POW?',
                        set_cmd='POW {}',
                        get_parser=float,
                        vals=Numbers(min_value=-135,
                                     max_value=25))
     self.add_parameter(name='power_offset',
                        label='Power offset',
                        unit='dBm',
                        get_cmd='POW:OFFS?',
                        set_cmd='POW:OFFS {}',
                        get_parser=float,
                        vals=Numbers(min_value=-200,
                                     max_value=200))
     self.add_parameter(name='output_rf',
                        get_cmd='OUTP?',
                        set_cmd='OUTP {}',
                        val_mapping={'OFF': 0,
                                     'ON': 1})
     self.add_parameter(name='modulation_rf',
                        get_cmd='OUTP:MOD?',
                        set_cmd='OUTP:MOD {}',
                        val_mapping={'OFF': 0,
                                     'ON': 1})
     # reset values after each reconnect
     self.power(0)
     self.power_offset(0)
     self.connect_message()
     self.add_function('reset', call_cmd='*RST')
Beispiel #24
0
    def __init__(self, name, cardid='spcm0', **kwargs):
        """Driver for the Spectrum M4i.44xx-x8 cards.

        For more information see: http://spectrum-instrumentation.com/en/m4i-platform-overview

        Example:

            Example usage for acquisition with channel 2 using an external trigger
            that triggers multiple times with trigger mode HIGH::

                m4 = M4i(name='M4i', server_name=None)
                m4.enable_channels(pyspcm.CHANNEL2)
                m4.set_channel_settings(2,mV_range, input_path, termination, coupling, compensation)
                m4.set_ext0_OR_trigger_settings(pyspcm.SPC_TM_HIGH,termination,coupling,level0)
                calc = m4.multiple_trigger_acquisition(mV_range,memsize,seg_size,posttrigger_size)

        Todo:
          Whenever an error occurs (including validation errors) the python
          console needs to be restarted


        """
        super().__init__(name, **kwargs)

        self.hCard = pyspcm.spcm_hOpen(cardid)
        if self.hCard is None:
            logging.warning("M4i: no card found\n")

        # add parameters for getting
        self.add_parameter('card_id',
                           label='card id',
                           get_cmd=None,
                           set_cmd=None,
                           initial_value=cardid,
                           vals=Anything(),
                           docstring='The card ID')
        self.add_parameter('max_sample_rate',
                           label='max sample rate',
                           unit='Hz',
                           get_cmd=self.get_max_sample_rate,
                           docstring='The maximumum sample rate')
        self.add_parameter('memory',
                           label='memory',
                           unit='bytes',
                           get_cmd=self.get_card_memory,
                           docstring='Amount of memory on card')
        self.add_parameter('resolution',
                           label='resolution',
                           unit='bits',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_BITSPERSAMPLE),
                           docstring='Resolution of the card')
        self.add_parameter('pcidate',
                           label='pcidate',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_PCIDATE),
                           docstring='The PCI date')
        self.add_parameter('serial_number',
                           label='serial number',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_PCISERIALNO),
                           docstring='The serial number of the board')
        self.add_parameter('channel_count',
                           label='channel count',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_CHCOUNT),
                           docstring='Return number of enabled channels')
        self.add_parameter('input_path_count',
                           label='input path count',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_READAIPATHCOUNT),
                           docstring='Return number of analog input paths')
        self.add_parameter(
            'input_ranges_count',
            label='input ranges count',
            get_cmd=partial(self._param32bit, pyspcm.SPC_READIRCOUNT),
            docstring='Return number of input ranges for the current input path'
        )
        self.add_parameter(
            'input_path_features',
            label='input path features',
            get_cmd=partial(self._param32bit, pyspcm.SPC_READAIFEATURES),
            docstring='Return a bitmap of features for current input path')
        self.add_parameter('available_card_modes',
                           label='available card modes',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_AVAILCARDMODES),
                           docstring='Return a bitmap of available card modes')
        self.add_parameter(
            'card_status',
            label='card status',
            get_cmd=partial(self._param32bit, pyspcm.SPC_M2STATUS),
            docstring='Return a bitmap for the status information')
        self.add_parameter(
            'read_range_min_0',
            label='read range min 0',
            unit='mV',
            get_cmd=partial(self._param32bit, pyspcm.SPC_READRANGEMIN0),
            docstring='Return the lower border of input range 0')

        # buffer handling
        self.add_parameter(
            'user_available_length',
            label='user available length',
            get_cmd=partial(self._param32bit, pyspcm.SPC_DATA_AVAIL_USER_LEN),
            docstring=
            'returns the number of currently to the user available bytes inside a sample data transfer'
        )
        self.add_parameter(
            'user_available_position',
            label='user available position',
            get_cmd=partial(self._param32bit, pyspcm.SPC_DATA_AVAIL_USER_POS),
            docstring=
            'returns the position as byte index where the currently available data samles start'
        )
        self.add_parameter(
            'buffer_fill_size',
            label='buffer fill size',
            get_cmd=partial(self._param32bit, pyspcm.SPC_FILLSIZEPROMILLE),
            docstring=
            'returns the current fill size of the on-board memory (FIFO buffer) in promille (1/1000)'
        )

        # triggering
        self.add_parameter(
            'available_trigger_or_mask',
            label='available trigger or mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_AVAILORMASK),
            docstring=
            'bitmask, in which all bits of sources for the OR mask are set, if available'
        )
        self.add_parameter(
            'available_channel_or_mask',
            label='available channel or mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_AVAILORMASK0),
            docstring=
            'bitmask, in which all bits of sources/channels (0-31) for the OR mask are set, if available'
        )
        self.add_parameter(
            'available_trigger_and_mask',
            label='available trigger and mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_AVAILANDMASK),
            docstring=
            'bitmask, in which all bits of sources for the AND mask are set, if available'
        )
        self.add_parameter(
            'available_channel_and_mask',
            label='available channel and mask',
            get_cmd=partial(self._param32bit,
                            pyspcm.SPC_TRIG_CH_AVAILANDMASK0),
            docstring=
            'bitmask, in which all bits of sources/channels (0-31) for the AND mask are set, if available'
        )
        self.add_parameter(
            'available_trigger_delay',
            label='available trigger delay',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_AVAILDELAY),
            docstring=
            'contains the maximum available delay as decimal integer value')
        self.add_parameter(
            'available_external_trigger_modes',
            label='available external trigger modes',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT0_AVAILMODES),
            docstring=
            'bitmask showing all available trigger modes for external 0 (main analog trigger input)'
        )
        self.add_parameter('external_trigger_min_level',
                           label='external trigger min level',
                           unit='mV',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT_AVAIL0_MIN),
                           docstring='returns the minimum trigger level')
        self.add_parameter('external_trigger_max_level',
                           label='external trigger max level',
                           unit='mV',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TRIG_EXT_AVAIL0_MAX),
                           docstring='returns the maximum trigger level')
        self.add_parameter(
            'external_trigger_level_step_size',
            label='external trigger level step size',
            unit='mV',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT_AVAIL0_STEP),
            docstring='returns the step size of the trigger level')
        self.add_parameter(
            'available_channel_trigger_modes',
            label='available channel trigger modes',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_AVAILMODES),
            docstring=
            'bitmask, in which all bits of the modes for the channel trigger are set'
        )
        self.add_parameter(
            'trigger_counter',
            label='trigger counter',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIGGERCOUNTER),
            docstring=
            'returns the number of triger events since acquisition start')
        # data per sample
        self.add_parameter('bytes_per_sample',
                           label='bytes per sample',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_BYTESPERSAMPLE),
                           docstring='returns the number of bytes per sample')
        self.add_parameter('bits_per_sample',
                           label='bits per sample',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_MIINST_BITSPERSAMPLE),
                           docstring='returns the number of bits per sample')

        # available clock modes
        self.add_parameter(
            'available_clock_modes',
            label='available clock modes',
            get_cmd=partial(self._param32bit, pyspcm.SPC_AVAILCLOCKMODES),
            docstring=
            'returns a bitmask in which the bits of the clock modes are set, if available'
        )

        # converting ADC samples to voltage values
        self.add_parameter(
            'ADC_to_voltage',
            label='ADC to voltage',
            get_cmd=partial(self._param32bit, pyspcm.SPC_MIINST_MAXADCVALUE),
            docstring=
            'contains the decimal code (in LSB) of the ADC full scale value')

        self.add_parameter('oversampling_factor',
                           label='oversampling factor',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_OVERSAMPLINGFACTOR),
                           docstring='Reads the oversampling factor')

        # add parameters for setting and getting (read/write direction
        # registers)

        self.add_parameter('enable_channels',
                           label='Channels enabled',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_CHENABLE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_CHENABLE),
                           vals=Enum(1, 2, 4, 8, 3, 5, 9, 6, 10, 12, 15),
                           docstring='Set and get enabled channels')

        # analog input path functions
        # TODO: change Enum validator to set_parser for the numbered functions
        # if we want string inputs

        self.add_parameter(
            'read_input_path',
            label='read input path',
            get_cmd=partial(self._param32bit, pyspcm.SPC_READAIPATH),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_READAIPATH),
            vals=Enum(0, 1, 2, 3),
            docstring=
            'Select the input path which is used to read out the features')

        for i in [0, 1, 2, 3]:
            self.add_parameter(
                'input_path_{}'.format(i),
                label='input path {}'.format(i),
                get_cmd=partial(self._param32bit,
                                getattr(pyspcm, 'SPC_PATH{}'.format(i))),
                set_cmd=partial(self._set_param32bit,
                                getattr(pyspcm, 'SPC_PATH{}'.format(i))),
                vals=Enum(0, 1),
                docstring='Set and get analog input path for channel {}'.
                format(i))

            # channel range functions
            # TODO: check the input path to set the right validator (either by
            # directly calling input_path_x() or by storing a variable)
            self.add_parameter(
                'range_channel_{}'.format(i),
                label='range channel {}'.format(i),
                get_cmd=partial(self._param32bit,
                                getattr(pyspcm, 'SPC_AMP{}'.format(i))),
                set_cmd=partial(self._set_param32bit,
                                getattr(pyspcm, 'SPC_AMP{}'.format(i))),
                vals=Enum(200, 500, 1000, 2000, 2500, 5000, 10000),
                docstring='Set and get input range of channel {}'.format(i))

            # input termination functions
            self.add_parameter(
                'termination_{}'.format(i),
                label='termination {}'.format(i),
                get_cmd=partial(self._param32bit,
                                getattr(pyspcm, 'SPC_50OHM{}'.format(i))),
                set_cmd=partial(self._set_param32bit,
                                getattr(pyspcm, 'SPC_50OHM{}'.format(i))),
                vals=Enum(0, 1),
                docstring=
                'if 1 sets termination to 50 Ohm, otherwise 1 MOhm for channel {}'
                .format(i))

            # input coupling
            self.add_parameter(
                'ACDC_coupling_{}'.format(i),
                label='ACDC coupling {}'.format(i),
                get_cmd=partial(self._param32bit,
                                getattr(pyspcm, 'SPC_ACDC{}'.format(i))),
                set_cmd=partial(self._set_param32bit,
                                getattr(pyspcm, 'SPC_ACDC{}'.format(i))),
                vals=Enum(0, 1),
                docstring=
                'if 1 sets the AC coupling, otherwise sets the DC coupling for channel {}'
                .format(i))

            # AC/DC offset compensation
            self.add_parameter(
                'ACDC_offs_compensation_{}'.format(i),
                label='ACDC offs compensation {}'.format(i),
                get_cmd=partial(self._get_compensation, i),
                set_cmd=partial(self._set_compensation, i),
                vals=Enum(0, 1),
                docstring=
                'if 1 enables compensation, if 0 disables compensation for channel {}'
                .format(i))

            # anti aliasing filter (Bandwidth limit)
            self.add_parameter(
                'anti_aliasing_filter_{}'.format(i),
                label='anti aliasing filter {}'.format(i),
                get_cmd=partial(self._param32bit,
                                getattr(pyspcm, 'SPC_FILTER{}'.format(i))),
                set_cmd=partial(self._set_param32bit,
                                getattr(pyspcm, 'SPC_FILTER{}'.format(i))),
                vals=Enum(0, 1),
                docstring=
                'if 1 selects bandwidth limit, if 0 sets to full bandwidth for channel {}'
                .format(i))

            self.add_parameter('channel_{}'.format(i),
                               label='channel {}'.format(i),
                               unit='a.u.',
                               get_cmd=partial(self._read_channel, i))

        # acquisition modes
        # TODO: If required, the other acquisition modes can be added to the
        # validator
        self.add_parameter(
            'card_mode',
            label='card mode',
            get_cmd=partial(self._param32bit, pyspcm.SPC_CARDMODE),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_CARDMODE),
            vals=Enum(pyspcm.SPC_REC_STD_SINGLE, pyspcm.SPC_REC_STD_MULTI,
                      pyspcm.SPC_REC_STD_GATE, pyspcm.SPC_REC_STD_ABA,
                      pyspcm.SPC_REC_FIFO_SINGLE, pyspcm.SPC_REC_FIFO_MULTI,
                      pyspcm.SPC_REC_FIFO_GATE, pyspcm.SPC_REC_FIFO_ABA,
                      pyspcm.SPC_REC_STD_AVERAGE),
            docstring='defines the used operating mode')

        # wait command
        self.add_parameter('timeout',
                           label='timeout',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_TIMEOUT),
                           unit='ms',
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_TIMEOUT),
                           docstring='defines the timeout for wait commands')

        # Single acquisition mode memory, pre- and posttrigger (pretrigger = memory size - posttrigger)
        # TODO: improve the validators to make them take into account the
        # current state of the instrument
        self.add_parameter(
            'data_memory_size',
            label='data memory size',
            get_cmd=partial(self._param32bit, pyspcm.SPC_MEMSIZE),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_MEMSIZE),
            vals=Numbers(min_value=16),
            docstring='sets the memory size in samples per channel')
        self.add_parameter(
            'posttrigger_memory_size',
            label='posttrigger memory size',
            get_cmd=partial(self._param32bit, pyspcm.SPC_POSTTRIGGER),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_POSTTRIGGER),
            docstring=
            'sets the number of samples to be recorded after trigger event')

        # FIFO single acquisition length and pretrigger
        self.add_parameter(
            'pretrigger_memory_size',
            label='pretrigger memory size',
            get_cmd=partial(self._param32bit, pyspcm.SPC_PRETRIGGER),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_PRETRIGGER),
            docstring=
            'sets the number of samples to be recorded before trigger event')
        self.add_parameter('segment_size',
                           label='segment size',
                           get_cmd=partial(self._param32bit,
                                           pyspcm.SPC_SEGMENTSIZE),
                           set_cmd=partial(self._set_param32bit,
                                           pyspcm.SPC_SEGMENTSIZE),
                           docstring='length of segments to acquire')
        self.add_parameter(
            'total_segments',
            label='total segments',
            get_cmd=partial(self._param32bit, pyspcm.SPC_LOOPS),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_LOOPS),
            docstring=
            'number of segments to acquire in total. Setting 0 makes it run until stopped by user'
        )

        # clock generation
        self.add_parameter(
            'clock_mode',
            label='clock mode',
            get_cmd=partial(self._param32bit, pyspcm.SPC_CLOCKMODE),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_CLOCKMODE),
            vals=Enum(pyspcm.SPC_CM_INTPLL, pyspcm.SPC_CM_QUARTZ2,
                      pyspcm.SPC_CM_EXTREFCLOCK, pyspcm.SPC_CM_PXIREFCLOCK),
            docstring=
            'defines the used clock mode or reads out the actual selected one')
        self.add_parameter(
            'sample_rate',
            label='sample rate',
            get_cmd=partial(self._param32bit, pyspcm.SPC_SAMPLERATE),
            unit='Hz',
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_SAMPLERATE),
            docstring=
            'write the sample rate for internal sample generation or read rate nearest to desired'
        )
        self.add_parameter(
            'special_clock',
            label='special clock',
            get_cmd=partial(self._param32bit, pyspcm.SPC_SPECIALCLOCK),
            unit='Hz',
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_SPECIALCLOCK),
            docstring=
            'Activate/Deactivate the special clock mode (lower and more sampling clock rates)'
        )

        # triggering
        self.add_parameter(
            'trigger_or_mask',
            label='trigger or mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_ORMASK),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_ORMASK),
            vals=Enum(pyspcm.SPC_TMASK_NONE, pyspcm.SPC_TMASK_SOFTWARE,
                      pyspcm.SPC_TMASK_EXT0, pyspcm.SPC_TMASK_EXT1),
            docstring=
            'defines the events included within the  trigger OR mask card')
        self.add_parameter(
            'channel_or_mask',
            label='channel or mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_ORMASK0),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_CH_ORMASK0),
            docstring=
            'includes the channels (0-31) within the channel trigger OR mask of the card'
        )
        self.add_parameter(
            'trigger_and_mask',
            label='trigger and mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_ANDMASK),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_ANDMASK),
            vals=Enum(pyspcm.SPC_TMASK_NONE, pyspcm.SPC_TMASK_EXT0,
                      pyspcm.SPC_TMASK_EXT1),
            docstring=
            'defines the events included within the  trigger AND mask card')
        self.add_parameter(
            'channel_and_mask',
            label='channel and mask',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_CH_ANDMASK0),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_CH_ANDMASK0),
            docstring=
            'includes the channels (0-31) within the channel trigger AND mask of the card'
        )
        self.add_parameter(
            'trigger_delay',
            label='trigger delay',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_DELAY),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_DELAY),
            docstring='defines the delay for the detected trigger events')
        self.add_parameter(
            'external_trigger_mode',
            label='external trigger mode',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT0_MODE),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_EXT0_MODE),
            docstring=
            'defines the external trigger mode for the external SMA connector trigger input'
        )
        self.add_parameter(
            'external_trigger_termination',
            label='external trigger termination',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_TERM),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_TERM),
            vals=Enum(0, 1),
            docstring=
            'A 1 sets the 50 Ohm termination, a 0 sets high impedance termination'
        )
        self.add_parameter(
            'external_trigger_input_coupling',
            label='external trigger input coupling',
            get_cmd=partial(self._param32bit, pyspcm.SPC_TRIG_EXT0_ACDC),
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_TRIG_EXT0_ACDC),
            vals=Enum(0, 1),
            docstring=
            'A 1 sets the AC coupling for the external trigger, a 0 sets DC')

        for l in [0, 1]:
            self.add_parameter(
                'external_trigger_level_{}'.format(l),
                label='external trigger level {}'.format(l),
                get_cmd=partial(
                    self._param32bit,
                    getattr(pyspcm, 'SPC_TRIG_EXT0_LEVEL{}'.format(l))),
                set_cmd=partial(
                    self._set_param32bit,
                    getattr(pyspcm, 'SPC_TRIG_EXT0_LEVEL{}'.format(l))),
                docstring='trigger level {} for external trigger'.format(l))

        for i in [0, 1, 2, 3]:
            self.add_parameter(
                'trigger_mode_channel_{}'.format(i),
                label='trigger mode channel {}'.format(i),
                get_cmd=partial(
                    self._param32bit,
                    getattr(pyspcm, 'SPC_TRIG_CH{}_MODE'.format(i))),
                set_cmd=partial(
                    self._set_param32bit,
                    getattr(pyspcm, 'SPC_TRIG_CH{}_MODE'.format(i))),
                docstring='sets the trigger mode for channel {}'.format(i))
            for l in [0, 1]:
                self.add_parameter(
                    'trigger_channel_{}_level_{}'.format(i, l),
                    label='trigger channel {} level {}'.format(i, l),
                    get_cmd=partial(
                        self._param32bit,
                        getattr(pyspcm, 'SPC_TRIG_CH{}_LEVEL{}'.format(i, l))),
                    set_cmd=partial(
                        self._set_param32bit,
                        getattr(pyspcm, 'SPC_TRIG_CH{}_LEVEL{}'.format(i, l))),
                    docstring='trigger level {} channel {}'.format(l, i))

        # add parameters for setting (write only registers)

        # Buffer handling
        self.add_parameter(
            'card_available_length',
            label='card available length',
            set_cmd=partial(self._set_param32bit,
                            pyspcm.SPC_DATA_AVAIL_CARD_LEN),
            docstring=
            'writes the number of bytes that the card can now use for sample data transfer again'
        )

        # General
        self.add_parameter(
            'general_command',
            label='general command',
            set_cmd=partial(self._set_param32bit, pyspcm.SPC_M2CMD),
            docstring='executes a command for the card or data transfer')

        # memsize used for simple channel read-out
        self._channel_memsize = 2**12
Beispiel #25
0
    def __init__(self, name: str, address: str, terminator: str="\n",
                 **kwargs) -> None:
        super().__init__(name, address, terminator=terminator, **kwargs)

        self.add_parameter('output',
                           label='Output State',
                           get_cmd=self.state,
                           set_cmd=lambda x: self.on() if x else self.off(),
                           val_mapping={
                               'off': 0,
                               'on': 1,
                           })

        self.add_parameter('source_mode',
                           label='Source Mode',
                           get_cmd=':SOUR:FUNC?',
                           set_cmd=self._set_source_mode,
                           vals=Enum('VOLT', 'CURR'))

        # When getting the mode internally in the driver, look up the mode as recorded by the _cached_mode property,
        # instead of calling source_mode(). This will prevent frequent VISA calls to the instrument. Calling
        # _set_source_mode will change the chased value.
        self._cached_mode = "VOLT"

        # We want to cache the range value so communication with the instrument only happens when the set the
        # range. Getting the range always returns the cached value. This value is adjusted when calling
        # self._set_range
        self._cached_range_value = None # type: Optional[Union[float,int]]

        self.add_parameter('voltage_range',
                           label='Voltage Source Range',
                           unit='V',
                           get_cmd=partial(self._get_range, "VOLT"),
                           set_cmd=partial(self._set_range, "VOLT"),
                           vals=Enum(10e-3, 100e-3, 1e0, 10e0, 30e0))

        # The driver is initialized in the volt mode. In this mode we cannot
        # get 'current_range'. Hence the snapshot is excluded.
        self.add_parameter('current_range',
                           label='Current Source Range',
                           unit='I',
                           get_cmd=partial(self._get_range, "CURR"),
                           set_cmd=partial(self._set_range, "CURR"),
                           vals=Enum(1e-3, 10e-3, 100e-3, 200e-3),
                           snapshot_exclude=True
                           )

        # This is changed through the source_mode interface
        self.range = self.voltage_range

        self._auto_range = False
        self.add_parameter('auto_range',
                           label='Auto Range',
                           set_cmd=self._set_auto_range,
                           get_cmd=lambda: self._auto_range,
                           vals=Bool())

        self.add_parameter('voltage',
                           label='Voltage',
                           unit='V',
                           set_cmd=partial(self._get_set_output, "VOLT"),
                           get_cmd=partial(self._get_set_output, "VOLT")
                           )
        # Again, at init we are in "VOLT" mode. Hence, exclude the snapshot of
        # 'current' as instrument does not support this parameter in
        # "VOLT" mode.
        self.add_parameter('current',
                           label='Current',
                           unit='I',
                           set_cmd=partial(self._get_set_output, "CURR"),
                           get_cmd=partial(self._get_set_output, "CURR"),
                           snapshot_exclude=True
                           )

        # This is changed through the source_mode interface
        self.output_level = self.voltage

        self.add_parameter('voltage_limit',
                           label='Voltage Protection Limit',
                           unit='V',
                           vals=Ints(1, 30),
                           get_cmd=":SOUR:PROT:VOLT?",
                           set_cmd=":SOUR:PROT:VOLT {}",
                           get_parser=float_round,
                           set_parser=int)

        self.add_parameter('current_limit',
                           label='Current Protection Limit',
                           unit='I',
                           vals=Numbers(1e-3, 200e-3),
                           get_cmd=":SOUR:PROT:CURR?",
                           set_cmd=":SOUR:PROT:CURR {:.3f}",
                           get_parser=float,
                           set_parser=float)

        self.add_parameter('four_wire',
                           label='Four Wire Sensing',
                           get_cmd=':SENS:REM?',
                           set_cmd=':SENS:REM {}',
                           val_mapping={
                              'off': 0,
                              'on': 1,
                           })
        # Note: The guard feature can be used to remove common mode noise.
        # Read the manual to see if you would like to use it
        self.add_parameter('guard',
                          label='Guard Terminal',
                          get_cmd=':SENS:GUAR?',
                          set_cmd=':SENS:GUAR {}',
                          val_mapping={
                              'off': 0,
                              'on': 1,
                          })

        # Return measured line frequency
        self.add_parameter("line_freq",
                           label='Line Frequency',
                           unit="Hz",
                           get_cmd="SYST:LFR?",
                           get_parser=int)

        # Check if monitor is present, and if so enable measurement
        monitor_present = '/MON' in self.ask("*OPT?")
        measure = GS200_Monitor(self, 'measure', monitor_present)
        self.add_submodule('measure', measure)

        # Reset function
        self.add_function('reset', call_cmd='*RST')

        self.connect_message()
Beispiel #26
0
    def test_max(self):
        for max_val in [-1e20, -1, -0.1, 0, 0.1, 10]:
            n = Numbers(max_value=max_val)

            n.validate(n.valid_values[0])
            for v in self.numbers:
                if v <= max_val:
                    n.validate(v)
                else:
                    with self.assertRaises(ValueError):
                        n.validate(v)

        for v in self.not_numbers:
            with self.assertRaises(TypeError):
                n.validate(v)

        with self.assertRaises(ValueError):
            n.validate(float('nan'))
Beispiel #27
0
    def __init__(self, name: str, address: str,
                 timeout: float = 20,
                 **kwargs: Any):
        """
        Initialises the oscilloscope.

        Args:
            name: Name of the instrument used by QCoDeS
            address: Instrument address as used by VISA
            timeout: visa timeout, in secs.
        """

        super().__init__(name, address, timeout=timeout,
                         terminator='\n', **kwargs)
        self.connect_message()

        # Scope trace boolean
        self.trace_ready = False

        # switch the response header off,
        # else none of our parameters will work
        self.write(':SYSTem:HEADer OFF')

        # functions

        # general parameters

        # the parameters are in the same order as the front panel.
        # Beware, he list of implemented parameters is not complete. Refer to
        # the manual (Infiniium prog guide) for an equally infiniium list.

        # time base

        # timebase_scale is commented out for same reason as channel scale
        # use range instead
        # self.add_parameter('timebase_scale',
        #                    label='Scale of the one time devision',
        #                    unit='s/Div',
        #                    get_cmd=':TIMebase:SCALe?',
        #                    set_cmd=':TIMebase:SCALe {}',
        #                    vals=Numbers(),
        #                    get_parser=float,
        #                    )

        self.add_parameter('timebase_range',
                           label='Range of the time axis',
                           unit='s',
                           get_cmd=':TIMebase:RANGe?',
                           set_cmd=':TIMebase:RANGe {}',
                           vals=Numbers(5e-12, 20),
                           get_parser=float,
                           )
        self.add_parameter('timebase_position',
                           label='Offset of the time axis',
                           unit='s',
                           get_cmd=':TIMebase:POSition?',
                           set_cmd=':TIMebase:POSition {}',
                           vals=Numbers(),
                           get_parser=float,
                           )

        self.add_parameter('timebase_roll_enabled',
                           label='Is rolling mode enabled',
                           get_cmd=':TIMebase:ROLL:ENABLE?',
                           set_cmd=':TIMebase:ROLL:ENABLE {}',
                           val_mapping={True: 1, False: 0}
                           )

        # trigger
        self.add_parameter('trigger_enabled',
                           label='Is trigger enabled',
                           get_cmd=':TRIGger:AND:ENABLe?',
                           set_cmd=':TRIGger:AND:ENABLe {}',
                           val_mapping={True: 1, False: 0}
                           )

        self.add_parameter('trigger_edge_source',
                           label='Source channel for the edge trigger',
                           get_cmd=':TRIGger:EDGE:SOURce?',
                           set_cmd=':TRIGger:EDGE:SOURce {}',
                           vals=Enum(*(
                               [f'CHANnel{i}' for i in range(1, 4 + 1)] +
                               [f'CHAN{i}' for i in range(1, 4 + 1)] +
                               [f'DIGital{i}' for i in range(16 + 1)] +
                               [f'DIG{i}' for i in range(16 + 1)] +
                               ['AUX', 'LINE']))
                           )  # add enum for case insesitivity
        self.add_parameter('trigger_edge_slope',
                           label='slope of the edge trigger',
                           get_cmd=':TRIGger:EDGE:SLOPe?',
                           set_cmd=':TRIGger:EDGE:SLOPe {}',
                           vals=Enum('positive', 'negative', 'neither')
                           )
        self.add_parameter('trigger_level_aux',
                           label='Tirgger level AUX',
                           unit='V',
                           get_cmd=':TRIGger:LEVel? AUX',
                           set_cmd=':TRIGger:LEVel AUX,{}',
                           get_parser=float,
                           vals=Numbers(),
                           )
        # Aquisition
        # If sample points, rate and timebase_scale are set in an
        # incomensurate way, the scope only displays part of the waveform
        self.add_parameter('acquire_points',
                           label='sample points',
                           get_cmd='ACQ:POIN?',
                           get_parser=int,
                           set_cmd=self._cmd_and_invalidate('ACQ:POIN {}'),
                           unit='pts',
                           vals=vals.Numbers(min_value=1, max_value=100e6)
                           )

        self.add_parameter('acquire_sample_rate',
                           label='sample rate',
                           get_cmd='ACQ:SRAT?',
                           set_cmd=self._cmd_and_invalidate('ACQ:SRAT {}'),
                           unit='Sa/s',
                           get_parser=float
                           )

        # this parameter gets used internally for data aquisition. For now it
        # should not be used manually
        self.add_parameter(
            "data_source",
            label="Waveform Data source",
            get_cmd=":WAVeform:SOURce?",
            set_cmd=":WAVeform:SOURce {}",
            vals=Enum(
                *(
                    [f"CHANnel{i}" for i in range(1, 4 + 1)]
                    + [f"CHAN{i}" for i in range(1, 4 + 1)]
                    + [f"DIFF{i}" for i in range(1, 2 + 1)]
                    + [f"COMMonmode{i}" for i in range(3, 4 + 1)]
                    + [f"COMM{i}" for i in range(3, 4 + 1)]
                    + [f"FUNCtion{i}" for i in range(1, 16 + 1)]
                    + [f"FUNC{i}" for i in range(1, 16 + 1)]
                    + [f"WMEMory{i}" for i in range(1, 4 + 1)]
                    + [f"WMEM{i}" for i in range(1, 4 + 1)]
                    + [f"BUS{i}" for i in range(1, 4 + 1)]
                    + ["HISTogram", "HIST", "CLOCK"]
                    + ["MTRend", "MTR"]
                )
            ),
        )

        # TODO: implement as array parameter to allow for setting the other filter
        # ratios
        self.add_parameter('acquire_interpolate',
                            get_cmd=':ACQuire:INTerpolate?',
                            set_cmd=self._cmd_and_invalidate(':ACQuire:INTerpolate {}'),
                            val_mapping={True: 1, False: 0}
                            )

        self.add_parameter('acquire_mode',
                            label='Acquisition mode',
                            get_cmd= 'ACQuire:MODE?',
                            set_cmd='ACQuire:MODE {}',
                            vals=Enum('ETIMe', 'RTIMe', 'PDETect',
                                      'HRESolution', 'SEGMented',
                                      'SEGPdetect', 'SEGHres')
                            )

        self.add_parameter('acquire_timespan',
                            get_cmd=(lambda: self.acquire_points.get_latest() \
                                            /self.acquire_sample_rate.get_latest()),
                            unit='s',
                            get_parser=float
                            )

        # time of the first point
        self.add_parameter('waveform_xorigin',
                            get_cmd='WAVeform:XORigin?',
                            unit='s',
                            get_parser=float
                            )

        self.add_parameter('data_format',
                           set_cmd='SAV:WAV:FORM {}',
                           val_mapping={'csv': 'CSV',
                                        'binary': 'BIN',
                                        'asciixy': 'ASC'},
                           docstring=("Set the format for saving "
                                      "files using save_data function")
                           )
        # Channels
        channels = ChannelList(self, "Channels", InfiniiumChannel,
                               snapshotable=False)

        for i in range(1,5):
            channel = InfiniiumChannel(self, f'chan{i}', i)
            channels.append(channel)
            self.add_submodule(f"ch{i}", channel)
        self.add_submodule("channels", channels.to_channel_tuple())

        # Submodules
        meassubsys = MeasurementSubsystem(self, 'measure')
        self.add_submodule('measure', meassubsys)
    def __init__(self, name: str, ats, sgen1, sgen2, aeroflex, **kwargs):

        super().__init__(name, **kwargs)
        self.sgen1 = sgen1
        self.sgen2 = sgen2

        self.aeroflex = aeroflex
        self.aeroflex_CH_map = {'In': 'CH1', 'Out': 'CH2'}

        self.ats = ats
        self.delta_frequency = ats.delta_frequency

        self.rangeCHA = self.ats.channel_range1.get()
        self.rangeCHB = self.ats.channel_range2.get()

        self.add_parameter(name='IQ', iqmixer=self, parameter_class=IQPair)

        self.add_parameter(name='AmPh', iqmixer=self, parameter_class=AmPhPair)

        self.add_parameter(
            name='frequency',
            label='fprobe',
            unit='Hz',
            get_cmd=self.sgen1.frequency.get,  # get freq in MHz
            set_cmd=self.set_IQfrequency,  #set freq in range F1 in GHz
            vals=Numbers(min_value=1e3, max_value=40e9))

        self.add_parameter(
            name='S21',
            label='S21',
            #                           unit='Hz',
            get_cmd=self.get_S21,
            set_cmd=None)

        self.add_parameter(name='S21_ampl',
                           label='Amplitude',
                           unit='V',
                           get_cmd=self.get_S21ampl,
                           set_cmd=None)

        self.add_parameter(name='S21_phase',
                           label='Phase',
                           unit='rad',
                           get_cmd=self.get_S21phase,
                           set_cmd=None)

        self.add_parameter(name='S21_I',
                           label='I',
                           unit='V',
                           get_cmd=self.get_S21I,
                           set_cmd=None)

        self.add_parameter(name='S21_Q',
                           label='Q',
                           unit='V',
                           get_cmd=self.get_S21Q,
                           set_cmd=None)

        self.add_parameter(name='P_dBm',
                           label='ADC power',
                           unit='dBm',
                           get_cmd=self.get_PdBm,
                           set_cmd=None)

        self.add_parameter(name='S21_dB',
                           label='S21',
                           unit='dB',
                           get_cmd=self.get_S21dB,
                           set_cmd=None)

        for io, ch in self.aeroflex_CH_map.items():
            self.add_parameter(
                'att{}'.format(io),
                label='att {}'.format(io),
                unit='dB',
                get_cmd=getattr(self.aeroflex,
                                'attenuation{}'.format(ch)).get,  # 
                set_cmd=getattr(self.aeroflex,
                                'attenuation{}'.format(ch)).set,  # 
                vals=vals.Enum(*np.arange(0, 100.1, 2).tolist()))
Beispiel #29
0
    def __init__(
            self,
            name: str,
            address: str,
            port: Optional[int] = None,
            reset: bool = False,
            terminator: str = '\r\n',
            current_ramp_limit: Optional[float] = None,
            **kwargs: Any):
        if "has_current_rating" in kwargs.keys():
            warnings.warn(
                "'has_current_rating' kwarg to AMI430 "
                "is deprecated and has no effect",
                category=QCoDeSDeprecationWarning)
            kwargs.pop("has_current_rating")

        super().__init__(name, address, port, terminator=terminator,
                         write_confirmation=False, **kwargs)
        self._parent_instrument = None

        # Add reset function
        self.add_function('reset', call_cmd='*RST')
        if reset:
            self.reset()

        # Add parameters setting instrument units
        self.add_parameter("ramp_rate_units",
                           get_cmd='RAMP:RATE:UNITS?',
                           set_cmd=(lambda units:
                                    self._update_units(ramp_rate_units=units)),
                           val_mapping={'seconds': 0,
                                        'minutes': 1})
        self.add_parameter('field_units',
                           get_cmd='FIELD:UNITS?',
                           set_cmd=(lambda units:
                                    self._update_units(field_units=units)),
                           val_mapping={'kilogauss': 0,
                                        'tesla': 1})

        # Set programmatic safety limits
        self.add_parameter('current_ramp_limit',
                           get_cmd=lambda: self._current_ramp_limit,
                           set_cmd=self._update_ramp_rate_limit,
                           unit="A/s")
        self.add_parameter('field_ramp_limit',
                           get_cmd=lambda: self.current_ramp_limit(),
                           set_cmd=lambda x: self.current_ramp_limit(x),
                           scale=1/float(self.ask("COIL?")),
                           unit="T/s")
        if current_ramp_limit is None:
            self._update_ramp_rate_limit(AMI430._DEFAULT_CURRENT_RAMP_LIMIT,
                                         update=False)
        else:
            self._update_ramp_rate_limit(current_ramp_limit, update=False)

        # Add solenoid parameters
        self.add_parameter('coil_constant',
                           get_cmd=self._update_coil_constant,
                           set_cmd=self._update_coil_constant,
                           vals=Numbers(0.001, 999.99999))

        self.add_parameter('current_limit',
                           unit="A",
                           set_cmd="CONF:CURR:LIMIT {}",
                           get_cmd='CURR:LIMIT?',
                           get_parser=float,
                           vals=Numbers(0, 80))  # what are good numbers here?

        self.add_parameter('field_limit',
                           set_cmd=self.current_limit.set,
                           get_cmd=self.current_limit.get,
                           scale=1/float(self.ask("COIL?")))

        # Add current solenoid parameters
        # Note that field is validated in set_field
        self.add_parameter('field',
                           get_cmd='FIELD:MAG?',
                           get_parser=float,
                           set_cmd=self.set_field)
        self.add_parameter('ramp_rate',
                           get_cmd=self._get_ramp_rate,
                           set_cmd=self._set_ramp_rate)
        self.add_parameter('setpoint',
                           get_cmd='FIELD:TARG?',
                           get_parser=float)
        self.add_parameter('is_quenched',
                           get_cmd='QU?',
                           val_mapping={True: 1, False: 0})
        self.add_function('reset_quench', call_cmd='QU 0')
        self.add_function('set_quenched', call_cmd='QU 1')
        self.add_parameter('ramping_state',
                           get_cmd='STATE?',
                           get_parser=int,
                           val_mapping={
                               'ramping': 1,
                               'holding': 2,
                               'paused': 3,
                               'manual up': 4,
                               'manual down': 5,
                               'zeroing current': 6,
                               'quench detected': 7,
                               'at zero current': 8,
                               'heating switch': 9,
                               'cooling switch': 10,
                           })

        # Add persistent switch
        switch_heater = AMI430SwitchHeater(self)
        self.add_submodule("switch_heater", switch_heater)

        # Add interaction functions
        self.add_function('get_error', call_cmd='SYST:ERR?')
        self.add_function('ramp', call_cmd='RAMP')
        self.add_function('pause', call_cmd='PAUSE')
        self.add_function('zero', call_cmd='ZERO')

        # Correctly assign all units
        self._update_units()

        self.connect_message()
Beispiel #30
0
    def __init__(self,
                 name: str,
                 serial_number: str,
                 dll=None,
                 debug=False,
                 **kwargs: Any):
        super().__init__(name, **kwargs)
        logging.info(
            __name__ +
            f' : Initializing instrument SignalCore generator {serial_number}')
        if dll is not None:
            self._dll = dll
        else:
            self._dll = ctypes.CDLL(DLL.__path__._path[0] + '//sc5511a.dll')

        if debug:
            print(self._dll)

        self._dll.sc5511a_open_device.restype = ctypes.c_uint64
        self._handle = ctypes.c_void_p(
            self._dll.sc5511a_open_device(
                ctypes.c_char_p(bytes(serial_number, 'utf-8'))))
        self._serial_number = ctypes.c_char_p(bytes(serial_number, 'utf-8'))
        self._rf_params = Device_rf_params_t(0, 0, 0, 0, 0, 0, 0, 0, 0)
        self._status = Operate_status_t(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                        0, 0)
        self._open = False
        self._temperature = Device_temperature_t(0)

        self._pll_status = Pll_status_t()
        self._list_mode = List_mode_t()
        self._device_status = Device_status_t(self._list_mode, self._status,
                                              self._pll_status)
        if debug:
            print(serial_number, self._handle)
            self._dll.sc5511a_get_device_status(
                self._handle, ctypes.byref(self._device_status))
            status = self._device_status.operate_status_t.rf1_out_enable
            print('check status', status)

        self._dll.sc5511a_close_device(self._handle)
        self._device_info = Device_info_t(0, 0, 0, 0)
        self.get_idn()
        self.do_set_auto_level_disable(
            0)  # setting this to 1 will lead to unstable output power

        self.add_parameter('power',
                           label='power',
                           get_cmd=self.do_get_power,
                           get_parser=float,
                           set_cmd=self.do_set_power,
                           set_parser=float,
                           unit='dBm',
                           vals=Numbers(min_value=-144, max_value=19))

        self.add_parameter('output_status',
                           label='output_status',
                           get_cmd=self.do_get_output_status,
                           get_parser=int,
                           set_cmd=self.do_set_output_status,
                           set_parser=int,
                           vals=Numbers(min_value=0, max_value=1))

        self.add_parameter('frequency',
                           label='frequency',
                           get_cmd=self.do_get_frequency,
                           get_parser=float,
                           set_cmd=self.do_set_frequency,
                           set_parser=float,
                           unit='Hz',
                           vals=Numbers(min_value=0, max_value=20e9))

        self.add_parameter('reference_source',
                           label='reference_source',
                           get_cmd=self.do_get_reference_source,
                           get_parser=int,
                           set_cmd=self.do_set_reference_source,
                           set_parser=int,
                           vals=Numbers(min_value=0, max_value=1))

        self.add_parameter('auto_level_disable',
                           label='0 = power is leveled on frequency change',
                           get_cmd=self.do_get_auto_level_disable,
                           get_parser=int,
                           set_cmd=self.do_set_auto_level_disable,
                           set_parser=int,
                           vals=Numbers(min_value=0, max_value=1))

        self.add_parameter('temperature',
                           label='temperature',
                           get_cmd=self.do_get_device_temp,
                           get_parser=float,
                           unit="C",
                           vals=Numbers(min_value=0, max_value=200))

        if self._device_status.operate_status_t.ext_ref_lock_enable == 0:
            self.do_set_reference_source(1)