Esempio n. 1
0
    def __init__(self, parent: 'DG1062', name: str, channel: int) -> None:
        super().__init__(parent, name)
        self.channel = channel

        self.add_parameter("on",
                           get_cmd=f":SOUR{channel}:BURS?",
                           set_cmd=f":SOUR{channel}:BURS {{}}",
                           vals=vals.Enum(0, 1, "ON", "OFF"))

        self.add_parameter("polarity",
                           get_cmd=f":SOUR{channel}:BURS:GATE:POL?",
                           set_cmd=f":SOUR{channel}:BURS:GATE:POL {{}}",
                           vals=vals.Enum("NORM", "INV"))

        self.add_parameter("period",
                           get_cmd=f":SOUR{channel}:BURS:INT:PER?",
                           set_cmd=f":SOUR{channel}:BURS:INT:PER {{}}",
                           vals=vals.MultiType(
                               vals.Numbers(min_value=3E-6, max_value=500),
                               vals.Enum("MIN", "MAX")))

        self.add_parameter("mode",
                           get_cmd=f":SOUR{channel}:BURS:MODE?",
                           set_cmd=f":SOUR{channel}:BURS:MODE {{}}",
                           vals=vals.Enum("TRIG", "INF", "GAT"))

        self.add_parameter("ncycles",
                           get_cmd=f":SOUR{channel}:BURS:NCYC?",
                           set_cmd=f":SOUR{channel}:BURS:NCYC {{}}",
                           vals=vals.Numbers(min_value=1, max_value=500000))

        self.add_parameter("phase",
                           get_cmd=f":SOUR{channel}:BURS:PHAS?",
                           set_cmd=f":SOUR{channel}:BURS:PHAS {{}}",
                           vals=vals.Numbers(min_value=0, max_value=360))

        self.add_parameter("time_delay",
                           get_cmd=f":SOUR{channel}:BURS:TDEL?",
                           set_cmd=f":SOUR{channel}:BURS:TDEL {{}}",
                           vals=vals.Numbers(min_value=0))

        self.add_parameter("trigger_slope",
                           get_cmd=f":SOUR{channel}:BURS:TRIG:SLOP?",
                           set_cmd=f":SOUR{channel}:BURS:TRIG:SLOP {{}}",
                           vals=vals.Enum("POS", "NEG"))

        self.add_parameter("source",
                           get_cmd=f":SOUR{channel}:BURS:TRIG:SOUR?",
                           set_cmd=f":SOUR{channel}:BURS:TRIG:SOUR {{}}",
                           vals=vals.Enum("INT", "EXT", "MAN"))

        self.add_parameter(
            "idle",
            get_cmd=f":SOUR{channel}:BURST:IDLE?",
            set_cmd=f":SOUR{channel}:BURST:IDLE {{}}",
            vals=vals.MultiType(
                vals.Enum("FPT", "TOP", "BOTTOM", "CENTER"),
                vals.Numbers()  # DIY
            ))
Esempio n. 2
0
    def __init__(self, parent: 'DG1062', name: str, channel: int) -> None:
        """
        Args:
            parent: The instrument this channel belongs to
            name (str)
            channel (int)
        """

        super().__init__(parent, name)
        self.channel = channel

        for param, unit in [("freq", "Hz"), ("ampl", "V"), ("offset", "V"),
                            ("phase", "deg"), ("sample_rate", "1/s")]:
            self.add_parameter(
                param,
                unit=unit,
                get_cmd=partial(self._get_waveform_param, param),
                set_cmd=partial(self._set_waveform_param, param),
            )

        self.add_parameter("waveform",
                           get_cmd=partial(self._get_waveform_param,
                                           "waveform"))

        self.add_parameter(
            "impedance",
            get_cmd=f":OUTPUT{channel}:IMP?",
            set_cmd=f":OUTPUT{channel}:IMP {{}}",
            unit="Ohm",
            vals=vals.MultiType(
                vals.Ints(min_value=DG1062Channel.min_impedance,
                          max_value=DG1062Channel.max_impedance),
                vals.Enum("INF", "MIN", "MAX", "HighZ")),
            get_parser=(lambda value: "HighZ" if float(value) > DG1062Channel.
                        max_impedance else float(value)),
            set_parser=lambda value: "INF" if value == "HighZ" else value)

        self.add_parameter(
            "sync",
            get_cmd=f":OUTPUT{channel}:SYNC?",
            set_cmd=f"OUTPUT{channel}:SYNC {{}}",
            vals=vals.Enum(0, 1, "ON", "OFF"),
        )

        self.add_parameter(
            "polarity",
            get_cmd=f":OUTPUT{channel}:GAT:POL?",
            set_cmd=f":OUTPUT{channel}:GAT:POL {{}}",
            vals=vals.OnOff(),
            val_mapping={
                1: 'POSITIVE',
                0: 'NEGATIVE'
            },
        )

        self.add_parameter(
            "state",
            get_cmd=f"OUTPUT{channel}:STATE?",
            set_cmd=f"OUTPUT{channel}:STATE {{}}",
        )

        self.add_parameter("duty_cycle",
                           get_cmd=self._get_duty_cycle,
                           set_cmd=self._set_duty_cycle,
                           unit="%",
                           vals=vals.Numbers(min_value=1, max_value=99),
                           docstring=('This functions reads/sets the duty '
                                      'cycle for a square and pulse wave '
                                      'since these inheret a duty cycle.\n'
                                      'For other waveforms it will give '
                                      'the user an error'))

        burst = DG1062Burst(cast(DG1062, self.parent), "burst", self.channel)
        self.add_submodule("burst", burst)

        # We want to be able to do the following:
        # >>> help(gd.channels[0].sin)
        # >>> gd.channels[0].sin(freq=2E3, ampl=1.0, offset=0, phase=0)
        # We do not use add_function as it is more cumbersome to use.
        for waveform in self.waveforms:
            f = partial_with_docstring(
                self.apply,
                docstring="Args: " + ", ".join(self.waveform_params[waveform]),
                waveform=waveform)
            setattr(self, waveform.lower(), f)

        # Retreive current waveform from device
        self.waveform()
Esempio n. 3
0
    def __init__(self, name, address, silent=False, **kwargs):
        """
        Args:
            name (string): The name of the instrument used internally
                by QCoDeS. Must be unique.
            address (string): The VISA resource name.
            silent (Optional[bool]): If True, no connect message is printed.
        """

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

        # convenient little helper functions
        def setcmd(channel, setting):
            return 'SOURce{}:'.format(channel) + setting + ' {}'

        def getcmd(channel, setting):
            return 'SOURce{}:'.format(channel) + setting + '?'

        def errorparser(rawmssg):
            """
            Parses the error message.

            Args:
                rawmssg (str): The raw return value of 'SYSTem:ERRor?'

            Returns:
                tuple (int, str): The error code and the error message.
            """
            code = int(rawmssg.split(',')[0])
            mssg = rawmssg.split(',')[1].strip().replace('"', '')

            return code, mssg

        def val_parser(parser, inputstring):
            """
            Parses return values from instrument. Meant to be used when a query
            can return a meaningful finite number or a numeric representation
            of infinity

            Args:
                inputstring (str): The raw return value
                parser (type): Either int or float, what to return in finite
                    cases
            """

            inputstring = inputstring.strip()

            if float(inputstring) == 9.9e37:
                output = float('inf')
            else:
                output = float(inputstring)
                if parser == int:
                    output = parser(output)

            return output

        for chan in [1, 2]:

            self.add_parameter('ch{}_function_type'.format(chan),
                               label='Channel {} function type'.format(chan),
                               set_cmd=setcmd(chan, 'FUNCtion'),
                               get_cmd=getcmd(chan, 'FUNCtion'),
                               vals=vals.Enum('SIN', 'SQU', 'TRI', 'RAMP',
                                              'PULS', 'PRBS', 'NOIS', 'ARB',
                                              'DC'))

            self.add_parameter('ch{}_frequency_mode'.format(chan),
                               label='Channel {} frequency mode'.format(chan),
                               set_cmd=setcmd(chan, 'FREQuency:MODE'),
                               get_cmd=getcmd(chan, 'FREQuency:MODE'),
                               vals=vals.Enum('CW', 'LIST', 'SWEEP', 'FIXED'))

            self.add_parameter(
                'ch{}_frequency'.format(chan),
                label='Channel {} frequency'.format(chan),
                set_cmd=setcmd(chan, 'FREQuency'),
                get_cmd=getcmd(chan, 'FREQUency'),
                get_parser=float,
                unit='Hz',
                # TODO: max. freq. actually really tricky
                vals=vals.Numbers(1e-6, 30e6))

            self.add_parameter('ch{}_phase'.format(chan),
                               label='Channel {} phase'.format(chan),
                               set_cmd=setcmd(chan, 'PHASe'),
                               get_cmd=getcmd(chan, 'PHASe'),
                               get_parser=float,
                               unit='deg',
                               vals=vals.Numbers(0, 360))
            self.add_parameter('ch{}_amplitude_unit'.format(chan),
                               label='Channel {} amplitude unit'.format(chan),
                               set_cmd=setcmd(chan, 'VOLTage:UNIT'),
                               get_cmd=getcmd(chan, 'VOLTage:UNIT'),
                               vals=vals.Enum('VPP', 'VRMS', 'DBM'))

            self.add_parameter(
                'ch{}_amplitude'.format(chan),
                label='Channel {} amplitude'.format(chan),
                set_cmd=setcmd(chan, 'VOLTage'),
                get_cmd=getcmd(chan, 'VOLTage'),
                unit='',  # see amplitude_unit
                get_parser=float)

            self.add_parameter('ch{}_offset'.format(chan),
                               label='Channel {} voltage offset'.format(chan),
                               set_cmd=setcmd(chan, 'VOLTage:OFFSet'),
                               get_cmd=getcmd(chan, 'VOLTage:OFFSet'),
                               unit='V',
                               get_parser=float)
            self.add_parameter('ch{}_output'.format(chan),
                               label='Channel {} output state'.format(chan),
                               set_cmd='OUTPut{}'.format(chan) + ' {}',
                               get_cmd='OUTPut{}?'.format(chan),
                               val_mapping={
                                   'ON': 1,
                                   'OFF': 0
                               })

            self.add_parameter('ch{}_ramp_symmetry'.format(chan),
                               label='Channel {} ramp symmetry'.format(chan),
                               set_cmd=setcmd(chan, 'FUNCtion:RAMP:SYMMetry'),
                               get_cmd=getcmd(chan, 'FUNCtion:RAMP:SYMMetry'),
                               get_parser=float,
                               vals=vals.Numbers(0, 100))

            # TRIGGER MENU
            self.add_parameter('ch{}_trigger_source'.format(chan),
                               label='Channel {} trigger source'.format(chan),
                               set_cmd='TRIGger{}:SOURce {}'.format(
                                   chan, '{}'),
                               get_cmd='TRIGger{}:SOURce?'.format(chan),
                               vals=vals.Enum('IMM', 'EXT', 'TIM', 'BUS'))

            self.add_parameter('ch{}_trigger_count'.format(chan),
                               label='Channel {} trigger count'.format(chan),
                               set_cmd='TRIGger{}:COUNt {}'.format(chan, '{}'),
                               get_cmd='TRIGger{}:COUNt?'.format(chan),
                               vals=vals.Ints(1, 1000000),
                               get_parser=partial(val_parser, int))

            self.add_parameter('ch{}_trigger_delay'.format(chan),
                               label='Channel {} trigger delay'.format(chan),
                               set_cmd='TRIGger{}:DELay {}'.format(chan, '{}'),
                               get_cmd='TRIGger{}:DELay?'.format(chan),
                               vals=vals.Numbers(0, 1000),
                               get_parser=float,
                               unit='s')

            # TODO: trigger level doesn't work remotely. Why?

            self.add_parameter('ch{}_trigger_slope'.format(chan),
                               label='Channel {} trigger slope'.format(chan),
                               set_cmd='TRIGger{}:SLOPe {}'.format(chan, '{}'),
                               get_cmd='TRIGger{}:SLOPe?'.format(chan),
                               vals=vals.Enum('POS', 'NEG'))

            self.add_parameter('ch{}_trigger_timer'.format(chan),
                               label='Channel {} trigger timer'.format(chan),
                               set_cmd='TRIGger{}:TIMer {}'.format(chan, '{}'),
                               get_cmd='TRIGger{}:TIMer?'.format(chan),
                               vals=vals.Numbers(1e-6, 8000),
                               get_parser=float)

            # BURST MENU
            self.add_parameter('ch{}_burst_state'.format(chan),
                               label='Channel {} burst state'.format(chan),
                               set_cmd=setcmd(chan, 'BURSt:STATe'),
                               get_cmd=getcmd(chan, 'BURSt:STATe'),
                               val_mapping={
                                   'ON': 1,
                                   'OFF': 0
                               },
                               vals=vals.Enum('ON', 'OFF'))

            self.add_parameter('ch{}_burst_mode'.format(chan),
                               label='Channel {} burst mode'.format(chan),
                               set_cmd=setcmd(chan, 'BURSt:MODE'),
                               get_cmd=getcmd(chan, 'BURSt:MODE'),
                               val_mapping={
                                   'N Cycle': 'TRIG',
                                   'Gated': 'GAT'
                               },
                               vals=vals.Enum('N Cycle', 'Gated'))

            self.add_parameter(
                'ch{}_burst_ncycles'.format(chan),
                label='Channel {} burst no. of cycles'.format(chan),
                set_cmd=setcmd(chan, 'BURSt:NCYCles'),
                get_cmd=getcmd(chan, 'BURSt:NCYCLes'),
                get_parser=partial(val_parser, int),
                vals=vals.MultiType(vals.Ints(1),
                                    vals.Enum('MIN', 'MAX', 'INF')))

            self.add_parameter(
                'ch{}_burst_phase'.format(chan),
                label='Channel {} burst start phase'.format(chan),
                set_cmd=setcmd(chan, 'BURSt:PHASe'),
                get_cmd=getcmd(chan, 'BURSt:PHASe'),
                vals=vals.Numbers(-360, 360),
                unit='degrees',
                get_parser=float)

            self.add_parameter(
                'ch{}_burst_polarity'.format(chan),
                label='Channel {} burst gated polarity'.format(chan),
                set_cmd=setcmd(chan, 'BURSt:GATE:POLarity'),
                get_cmd=getcmd(chan, 'BURSt:GATE:POLarity'),
                vals=vals.Enum('NORM', 'INV'))

            self.add_parameter('ch{}_burst_int_period'.format(chan),
                               label=('Channel {}'.format(chan) +
                                      ' burst internal period'),
                               set_cmd=setcmd(chan, 'BURSt:INTernal:PERiod'),
                               get_cmd=getcmd(chan, 'BURSt:INTernal:PERiod'),
                               unit='s',
                               vals=vals.Numbers(1e-6, 8e3),
                               get_parser=float,
                               docstring=('The burst period is the time '
                                          'between the starts of consecutive '
                                          'bursts when trigger is immediate.'))

        self.add_parameter('sync_source',
                           label='Source of sync function',
                           set_cmd='OUTPut:SYNC:SOURce {}',
                           get_cmd='OUTPut:SYNC:SOURce?',
                           val_mapping={
                               1: 'CH1',
                               2: 'CH2'
                           },
                           vals=vals.Enum(1, 2))

        self.add_parameter('sync_output',
                           label='Sync output state',
                           set_cmd='OUTPut:SYNC {}',
                           get_cmd='OUTPut:SYNC?',
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           vals=vals.Enum('ON', 'OFF'))

        self.add_parameter('error',
                           label='Error message',
                           get_cmd='SYSTem:ERRor?',
                           get_parser=errorparser)

        self.add_function('force_trigger', call_cmd='*TRG')

        if not silent:
            self.connect_message()
Esempio n. 4
0
    def __init__(self, parent, name, channum):
        """
        Args:
            parent (Instrument): The instrument to which the channel is
                attached.
            name (str): The name of the channel
            channum (int): The number of the channel in question (1-2)
        """
        super().__init__(parent, name)

        def val_parser(parser, inputstring):
            """
            Parses return values from instrument. Meant to be used when a query
            can return a meaningful finite number or a numeric representation
            of infinity

            Args:
                inputstring (str): The raw return value
                parser (type): Either int or float, what to return in finite
                    cases
            """

            inputstring = inputstring.strip()

            if float(inputstring) == 9.9e37:
                output = float('inf')
            else:
                output = float(inputstring)
                if parser == int:
                    output = parser(output)

            return output

        self.add_parameter('function_type',
                           label='Channel {} function type'.format(channum),
                           set_cmd='SOURce{}:FUNCtion {{}}'.format(channum),
                           get_cmd='SOURce{}:FUNCtion?'.format(channum),
                           get_parser=str.rstrip,
                           vals=vals.Enum('SIN', 'SQU', 'TRI', 'RAMP', 'PULS',
                                          'PRBS', 'NOIS', 'ARB', 'DC'))

        self.add_parameter(
            'frequency_mode',
            label='Channel {} frequency mode'.format(channum),
            set_cmd='SOURce{}:FREQuency:MODE {{}}'.format(channum),
            get_cmd='SOURce{}:FREQuency:MODE?'.format(channum),
            get_parser=str.rstrip,
            vals=vals.Enum('CW', 'LIST', 'SWEEP', 'FIXED'))

        self.add_parameter(
            'frequency',
            label='Channel {} frequency'.format(channum),
            set_cmd='SOURce{}:FREQuency {{}}'.format(channum),
            get_cmd='SOURce{}:FREQuency?'.format(channum),
            get_parser=float,
            unit='Hz',
            # TODO: max. freq. actually really tricky
            vals=vals.Numbers(1e-6, 30e6))

        self.add_parameter('phase',
                           label='Channel {} phase'.format(channum),
                           set_cmd='SOURce{}:PHASe {{}}'.format(channum),
                           get_cmd='SOURce{}:PHASe?'.format(channum),
                           get_parser=float,
                           unit='deg',
                           vals=vals.Numbers(0, 360))
        self.add_parameter(
            'amplitude_unit',
            label='Channel {} amplitude unit'.format(channum),
            set_cmd='SOURce{}:VOLTage:UNIT {{}}'.format(channum),
            get_cmd='SOURce{}:VOLTage:UNIT?'.format(channum),
            vals=vals.Enum('VPP', 'VRMS', 'DBM'),
            get_parser=str.rstrip)

        self.add_parameter(
            'amplitude',
            label='Channel {} amplitude'.format(channum),
            set_cmd='SOURce{}:VOLTage {{}}'.format(channum),
            get_cmd='SOURce{}:VOLTage?'.format(channum),
            unit='',  # see amplitude_unit
            get_parser=float)

        self.add_parameter(
            'offset',
            label='Channel {} voltage offset'.format(channum),
            set_cmd='SOURce{}:VOLTage:OFFSet {{}}'.format(channum),
            get_cmd='SOURce{}:VOLTage:OFFSet?'.format(channum),
            unit='V',
            get_parser=float)
        self.add_parameter('output',
                           label='Channel {} output state'.format(channum),
                           set_cmd='OUTPut{} {{}}'.format(channum),
                           get_cmd='OUTPut{}?'.format(channum),
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           })

        self.add_parameter(
            'ramp_symmetry',
            label='Channel {} ramp symmetry'.format(channum),
            set_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry {{}}'.format(channum),
            get_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry?'.format(channum),
            get_parser=float,
            unit='%',
            vals=vals.Numbers(0, 100))

        # TRIGGER MENU
        self.add_parameter(
            'trigger_source',
            label='Channel {} trigger source'.format(channum),
            set_cmd='TRIGger{}:SOURce {{}}'.format(channum),
            get_cmd='TRIGger{}:SOURce?'.format(channum),
            vals=vals.Enum('IMM', 'EXT', 'TIM', 'BUS'),
            get_parser=str.rstrip,
        )

        self.add_parameter('trigger_count',
                           label='Channel {} trigger count'.format(channum),
                           set_cmd='TRIGger{}:COUNt {{}}'.format(channum),
                           get_cmd='TRIGger{}:COUNt?'.format(channum),
                           vals=vals.Ints(1, 1000000),
                           get_parser=partial(val_parser, int))

        self.add_parameter('trigger_delay',
                           label='Channel {} trigger delay'.format(channum),
                           set_cmd='TRIGger{}:DELay {{}}'.format(channum),
                           get_cmd='TRIGger{}:DELay?'.format(channum),
                           vals=vals.Numbers(0, 1000),
                           get_parser=float,
                           unit='s')

        # TODO: trigger level doesn't work remotely. Why?

        self.add_parameter('trigger_slope',
                           label='Channel {} trigger slope'.format(channum),
                           set_cmd='TRIGger{}:SLOPe {{}}'.format(channum),
                           get_cmd='TRIGger{}:SLOPe?'.format(channum),
                           vals=vals.Enum('POS', 'NEG'),
                           get_parser=str.rstrip)

        self.add_parameter('trigger_timer',
                           label='Channel {} trigger timer'.format(channum),
                           set_cmd='TRIGger{}:TIMer {{}}'.format(channum),
                           get_cmd='TRIGger{}:TIMer?'.format(channum),
                           vals=vals.Numbers(1e-6, 8000),
                           get_parser=float)

        # output menu
        self.add_parameter('output_polarity',
                           label='Channel {} output polarity'.format(channum),
                           set_cmd='OUTPut{}:POLarity {{}}'.format(channum),
                           get_cmd='OUTPut{}:POLarity?'.format(channum),
                           get_parser=str.rstrip,
                           vals=vals.Enum('NORM', 'INV'))
        # BURST MENU
        self.add_parameter('burst_state',
                           label='Channel {} burst state'.format(channum),
                           set_cmd='SOURce{}:BURSt:STATe {{}}'.format(channum),
                           get_cmd='SOURce{}:BURSt:STATe?'.format(channum),
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           vals=vals.Enum('ON', 'OFF'))

        self.add_parameter('burst_mode',
                           label='Channel {} burst mode'.format(channum),
                           set_cmd='SOURce{}:BURSt:MODE {{}}'.format(channum),
                           get_cmd='SOURce{}:BURSt:MODE?'.format(channum),
                           get_parser=str.rstrip,
                           val_mapping={
                               'N Cycle': 'TRIG',
                               'Gated': 'GAT'
                           },
                           vals=vals.Enum('N Cycle', 'Gated'))

        self.add_parameter(
            'burst_ncycles',
            label='Channel {} burst no. of cycles'.format(channum),
            set_cmd='SOURce{}:BURSt:NCYCles {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:NCYCLes?'.format(channum),
            get_parser=partial(val_parser, int),
            vals=vals.MultiType(vals.Ints(1), vals.Enum('MIN', 'MAX', 'INF')))

        self.add_parameter(
            'burst_phase',
            label='Channel {} burst start phase'.format(channum),
            set_cmd='SOURce{}:BURSt:PHASe {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:PHASe?'.format(channum),
            vals=vals.Numbers(-360, 360),
            unit='degrees',
            get_parser=float)

        self.add_parameter(
            'burst_polarity',
            label='Channel {} burst gated polarity'.format(channum),
            set_cmd='SOURce{}:BURSt:GATE:POLarity {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:GATE:POLarity?'.format(channum),
            vals=vals.Enum('NORM', 'INV'))

        self.add_parameter(
            'burst_int_period',
            label=('Channel {}'.format(channum) + ' burst internal period'),
            set_cmd='SOURce{}:BURSt:INTernal:PERiod {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:INTernal:PERiod'.format(channum),
            unit='s',
            vals=vals.Numbers(1e-6, 8e3),
            get_parser=float,
            docstring=('The burst period is the time '
                       'between the starts of consecutive '
                       'bursts when trigger is immediate.'))
Esempio n. 5
0
    def __init__(self, instrument_name, **kwargs):
        super().__init__(instrument_name, **kwargs)

        self._input_channels = {
            "I": Channel(instrument_name=self.instrument_name(), name="I", input=True),
            "Q": Channel(instrument_name=self.instrument_name(), name="Q", input=True),
            "pulse_mod": Channel(
                instrument_name=self.instrument_name(), name="pulse_mod", input=True
            ),
        }

        self._output_channels = {
            "RF_out": Channel(
                instrument_name=self.instrument_name(), name="RF_out", output=True
            )
        }

        self._channels = {
            **self._input_channels,
            **self._output_channels,
            "sync": Channel(
                instrument_name=self.instrument_name(), name="sync", output=True
            ),
        }

        self.pulse_implementations = [
            SinePulseImplementation(
                pulse_requirements=[
                    ("frequency", {"min": 1e6, "max": 40e9}),
                    ("power", {"min": -120, "max": 25}),
                    ("duration", {"min": 100e-9}),
                ]
            ),
            FrequencyRampPulseImplementation(
                pulse_requirements=[
                    ("frequency_start", {"min": 1e6, "max": 40e9}),
                    ("frequency_stop", {"min": 1e6, "max": 40e9}),
                    ("power", {"min": -120, "max": 25}),
                    ("duration", {"min": 100e-9}),
                ]
            ),
        ]

        self.envelope_padding = Parameter(
            "envelope_padding",
            unit="s",
            set_cmd=None,
            initial_value=0,
            vals=vals.Numbers(min_value=0, max_value=10e-3),
            docstring="Padding for any pulses that use IQ modulation. "
            "This is to ensure that any IQ pulses such as sine waves "
            "are applied a bit before the pulse starts. The marker pulse "
            "used for pulse modulation does not use any envelope padding.",
        )
        self.marker_amplitude = Parameter(
            unit="V",
            set_cmd=None,
            initial_value=1.5,
            docstring="Amplitude of marker pulse used for gating",
        )
        self.fix_frequency = Parameter(
            set_cmd=None,
            initial_value=False,
            vals=vals.Bool(),
            docstring="Whether to fix frequency to current value, or to "
            "dynamically choose frequency during setup",
        )
        self.frequency_carrier_choice = Parameter(
            set_cmd=None,
            initial_value="center",
            vals=vals.MultiType(vals.Enum("min", "center", "max"), vals.Numbers()),
            docstring="The choice for the microwave frequency, This is used if "
            "pulses with multiple frequencies are used, or if frequency "
            "modulation is needed. Ignored if fix_frequency = True. "
            'Can be either "max", "min", or "center", or a '
            "number which is the offset from the center",
        )
        self.frequency = Parameter(
            unit="Hz", set_cmd=None, initial_value=self.instrument.frequency()
        )
        self.power = Parameter(
            unit="dBm",
            set_cmd=None,
            initial_value=self.instrument.power(),
            docstring="Power that the microwave source will be set to. "
            "Set to equal the maximum power of the pulses",
        )
        self.IQ_modulation = Parameter(
            initial_value=None,
            vals=vals.Bool(),
            docstring="Whether to use IQ modulation. Cannot be directly set, but "
            "is set internally if there are pulses with multiple "
            "frequencies, self.fix_frequency() is True, or "
            "self.force_IQ_modulation() is True.",
        )
        self.IQ_channels = Parameter(
            initial_value='IQ',
            vals=vals.Enum('IQ', 'I', 'Q'),
            set_cmd=None,
            docstring="Which channels to use for IQ modulation."
                      "Double-sideband modulation is used if only 'I' or 'Q' "
                      "is chosen, while single-sideband modulation is used when"
                      "'IQ' is chosen."
        )
        self.force_IQ_modulation = Parameter(
            initial_value=False,
            vals=vals.Bool(),
            set_cmd=None,
            docstring="Whether to force IQ modulation.",
        )

        self.marker_per_pulse = Parameter(
            initial_value=True,
            vals=vals.Bool(),
            set_cmd=None,
            docstring='Use a separate marker per pulse. If False, a single '
                      'marker pulse is requested for the first pulse to the last '
                      'pulse. In this case, envelope padding will be added to '
                      'either side of the single marker pulse.'
        )

        # Add parameters that are not set via setup
        self.additional_settings = ParameterNode()
        for parameter_name in [
            "phase",
            "maximum_power",
            "IQ_impairment",
            "I_leakage",
            "Q_leakage",
            "Q_offset",
            "IQ_ratio",
            "IQ_wideband",
            "IQ_crestfactor",
            "reference_oscillator_source",
            "reference_oscillator_output_frequency",
            "reference_oscillator_external_frequency",
        ]:
            parameter = getattr(self.instrument, parameter_name)
            setattr(self.additional_settings, parameter_name, parameter)
Esempio n. 6
0
    def __init__(self, parent: Instrument, name: str, channum: int) -> None:
        """
        Args:
            parent: The instrument to which the channel is
                attached.
            name: The name of the channel
            channum: The number of the channel in question (1-2)
        """
        super().__init__(parent, name)

        self._channum = channum

        def val_parser(parser: type, inputstring: str) -> Union[float, int]:
            """
            Parses return values from instrument. Meant to be used when a query
            can return a meaningful finite number or a numeric representation
            of infinity

            Args:
                parser: Either int or float, what to return in finite
                    cases
                inputstring: The raw return value
            """

            inputstring = inputstring.strip()

            if float(inputstring) == 9.9e37:
                output = float('inf')
            else:
                output = float(inputstring)
                if parser == int:
                    output = parser(output)

            return output

        self.model = self._parent.model

        self.add_parameter('function_type',
                           label='Channel {} function type'.format(channum),
                           set_cmd='SOURce{}:FUNCtion {{}}'.format(channum),
                           get_cmd='SOURce{}:FUNCtion?'.format(channum),
                           get_parser=str.rstrip,
                           vals=vals.Enum('SIN', 'SQU', 'TRI', 'RAMP', 'PULS',
                                          'PRBS', 'NOIS', 'ARB', 'DC'))

        max_freq = self._parent._max_freqs[self.model]

        if self._parent.model in ['33511B', '33512B', '33522B', '33622A']:
            # FUNC ARB
            self.add_parameter(
                'arb_waveform_fname',
                label='Channel {} arb waveform filename'.format(channum),
                set_cmd='SOURce{}:FUNC:ARB {{}}'.format(channum),
                get_cmd='SOURce{}:FUNC:ARB?'.format(channum),
                get_parser=str.rstrip,
                vals=vals.Strings())

            self.add_parameter(
                'arb_waveform_adv',
                label='Channel {} arb waveform advance mode'.format(channum),
                set_cmd='SOURce{}:FUNCtion:ARBitrary:ADVance {{}}'.format(
                    channum),
                get_cmd='SOURce{}:FUNCtion:ARBitrary:ADVance?'.format(channum),
                get_parser=str.rstrip,
                vals=vals.Enum('TRIG', 'SRAT'))

            self.add_parameter(
                'arb_waveform_filter',
                label='Channel {} arb waveform filter'.format(channum),
                set_cmd='SOURce{}:FUNCtion:ARBitrary:FILTer {{}}'.format(
                    channum),
                get_cmd='SOURce{}:FUNCtion:ARBitrary:FILTer?'.format(channum),
                get_parser=str.rstrip,
                vals=vals.Enum('NORM', 'STEP', 'OFF'))

            self.add_parameter(
                'arb_waveform_frequency',
                label='Channel {} arb waveform frequency'.format(channum),
                set_cmd='SOURce{}:FUNCtion:ARBitrary:FREQuency {{}}'.format(
                    channum),
                get_cmd='SOURce{}:FUNCtion:ARBitrary:FREQuency?'.format(
                    channum),
                get_parser=float,
                unit='Hz',
                # TODO: max. freq. actually really tricky
                vals=vals.Numbers(1e-6, max_freq))

            self.add_parameter(
                'arb_waveform_period',
                label='Channel {} arb waveform period'.format(channum),
                set_cmd='SOURce{}:FUNCtion:ARBitrary:PERiod {{}}'.format(
                    channum),
                get_cmd='SOURce{}:FUNCtion:ARBitrary:PERiod?'.format(channum),
                get_parser=float,
                unit='s',
                vals=vals.Numbers(0))

            self.add_parameter(
                'arb_waveform_points',
                label='Channel {} arb waveform number of points'.format(
                    channum),
                get_cmd='SOURce{}:FUNCtion:ARBitrary:POINts?'.format(channum),
                get_parser=int)

            max_rate = self._parent._max_rates[self.model]

            self.add_parameter(
                'arb_waveform_srate',
                label='Channel {} arb waveform sampling rate'.format(channum),
                set_cmd='SOURce{}:FUNCtion:ARBitrary:SRATe {{}}'.format(
                    channum),
                get_cmd='SOURce{}:FUNCtion:ARBitrary:SRATe?'.format(channum),
                get_parser=float,
                unit='Sa/s',
                # TODO: max. rate. actually really tricky
                vals=vals.Numbers(1e-6, max_rate))

        self.add_parameter(
            'frequency_mode',
            label='Channel {} frequency mode'.format(channum),
            set_cmd='SOURce{}:FREQuency:MODE {{}}'.format(channum),
            get_cmd='SOURce{}:FREQuency:MODE?'.format(channum),
            get_parser=str.rstrip,
            vals=vals.Enum('CW', 'LIST', 'SWEEP', 'FIXED'))

        self.add_parameter(
            'frequency',
            label='Channel {} frequency'.format(channum),
            set_cmd='SOURce{}:FREQuency {{}}'.format(channum),
            get_cmd='SOURce{}:FREQuency?'.format(channum),
            get_parser=float,
            unit='Hz',
            # TODO: max. freq. actually really tricky
            vals=vals.Numbers(1e-6, max_freq))

        self.add_parameter('phase',
                           label='Channel {} phase'.format(channum),
                           set_cmd='SOURce{}:PHASe {{}}'.format(channum),
                           get_cmd='SOURce{}:PHASe?'.format(channum),
                           get_parser=float,
                           unit='deg',
                           vals=vals.Numbers(0, 360))

        self.add_parameter(
            'amplitude_unit',
            label='Channel {} amplitude unit'.format(channum),
            set_cmd='SOURce{}:VOLTage:UNIT {{}}'.format(channum),
            get_cmd='SOURce{}:VOLTage:UNIT?'.format(channum),
            vals=vals.Enum('VPP', 'VRMS', 'DBM'),
            get_parser=str.rstrip)

        self.add_parameter(
            'amplitude',
            label='Channel {} amplitude'.format(channum),
            set_cmd='SOURce{}:VOLTage {{}}'.format(channum),
            get_cmd='SOURce{}:VOLTage?'.format(channum),
            unit='',  # see amplitude_unit
            get_parser=float)

        self.add_parameter(
            'offset',
            label='Channel {} voltage offset'.format(channum),
            set_cmd='SOURce{}:VOLTage:OFFSet {{}}'.format(channum),
            get_cmd='SOURce{}:VOLTage:OFFSet?'.format(channum),
            unit='V',
            get_parser=float)
        self.add_parameter('output',
                           label='Channel {} output state'.format(channum),
                           set_cmd='OUTPut{} {{}}'.format(channum),
                           get_cmd='OUTPut{}?'.format(channum),
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           })

        self.add_parameter(
            'ramp_symmetry',
            label='Channel {} ramp symmetry'.format(channum),
            set_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry {{}}'.format(channum),
            get_cmd='SOURce{}:FUNCtion:RAMP:SYMMetry?'.format(channum),
            get_parser=float,
            unit='%',
            vals=vals.Numbers(0, 100))

        self.add_parameter(
            'pulse_width',
            label="Channel {} pulse width".format(channum),
            set_cmd='SOURce{}:FUNCtion:PULSE:WIDTh {{}}'.format(channum),
            get_cmd='SOURce{}:FUNCtion:PULSE:WIDTh?'.format(channum),
            get_parser=float,
            unit='S')

        # TRIGGER MENU
        self.add_parameter(
            'trigger_source',
            label='Channel {} trigger source'.format(channum),
            set_cmd='TRIGger{}:SOURce {{}}'.format(channum),
            get_cmd='TRIGger{}:SOURce?'.format(channum),
            vals=vals.Enum('IMM', 'EXT', 'TIM', 'BUS'),
            get_parser=str.rstrip,
        )

        self.add_parameter('trigger_slope',
                           label='Channel {} trigger slope'.format(channum),
                           set_cmd='TRIGger{}:SLOPe {{}}'.format(channum),
                           get_cmd='TRIGger{}:SLOPe?'.format(channum),
                           vals=vals.Enum('POS', 'NEG'),
                           get_parser=str.rstrip)

        # Older models do not have all the fancy trigger options
        if self._parent.model[2] in ['5', '6']:
            self.add_parameter(
                'trigger_count',
                label='Channel {} trigger count'.format(channum),
                set_cmd='TRIGger{}:COUNt {{}}'.format(channum),
                get_cmd='TRIGger{}:COUNt?'.format(channum),
                vals=vals.Ints(1, 1000000),
                get_parser=partial(val_parser, int))

            self.add_parameter(
                'trigger_delay',
                label='Channel {} trigger delay'.format(channum),
                set_cmd='TRIGger{}:DELay {{}}'.format(channum),
                get_cmd='TRIGger{}:DELay?'.format(channum),
                vals=vals.Numbers(0, 1000),
                get_parser=float,
                unit='s')

            self.add_parameter(
                'trigger_timer',
                label='Channel {} trigger timer'.format(channum),
                set_cmd='TRIGger{}:TIMer {{}}'.format(channum),
                get_cmd='TRIGger{}:TIMer?'.format(channum),
                vals=vals.Numbers(1e-6, 8000),
                get_parser=float)

        # TODO: trigger level doesn't work remotely. Why?

        # output menu
        self.add_parameter('output_polarity',
                           label='Channel {} output polarity'.format(channum),
                           set_cmd='OUTPut{}:POLarity {{}}'.format(channum),
                           get_cmd='OUTPut{}:POLarity?'.format(channum),
                           get_parser=str.rstrip,
                           vals=vals.Enum('NORM', 'INV'))
        # BURST MENU
        self.add_parameter('burst_state',
                           label='Channel {} burst state'.format(channum),
                           set_cmd='SOURce{}:BURSt:STATe {{}}'.format(channum),
                           get_cmd='SOURce{}:BURSt:STATe?'.format(channum),
                           val_mapping={
                               'ON': 1,
                               'OFF': 0
                           },
                           vals=vals.Enum('ON', 'OFF'))

        self.add_parameter('burst_mode',
                           label='Channel {} burst mode'.format(channum),
                           set_cmd='SOURce{}:BURSt:MODE {{}}'.format(channum),
                           get_cmd='SOURce{}:BURSt:MODE?'.format(channum),
                           get_parser=str.rstrip,
                           val_mapping={
                               'N Cycle': 'TRIG',
                               'Gated': 'GAT'
                           },
                           vals=vals.Enum('N Cycle', 'Gated'))

        self.add_parameter(
            'burst_ncycles',
            label='Channel {} burst no. of cycles'.format(channum),
            set_cmd='SOURce{}:BURSt:NCYCles {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:NCYCLes?'.format(channum),
            get_parser=partial(val_parser, int),
            vals=vals.MultiType(vals.Ints(1), vals.Enum('MIN', 'MAX', 'INF')))

        self.add_parameter(
            'burst_phase',
            label='Channel {} burst start phase'.format(channum),
            set_cmd='SOURce{}:BURSt:PHASe {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:PHASe?'.format(channum),
            vals=vals.Numbers(-360, 360),
            unit='degrees',
            get_parser=float)

        self.add_parameter(
            'burst_polarity',
            label='Channel {} burst gated polarity'.format(channum),
            set_cmd='SOURce{}:BURSt:GATE:POLarity {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:GATE:POLarity?'.format(channum),
            vals=vals.Enum('NORM', 'INV'))

        self.add_parameter(
            'burst_int_period',
            label=('Channel {}'.format(channum) + ' burst internal period'),
            set_cmd='SOURce{}:BURSt:INTernal:PERiod {{}}'.format(channum),
            get_cmd='SOURce{}:BURSt:INTernal:PERiod?'.format(channum),
            unit='s',
            vals=vals.Numbers(1e-6, 8e3),
            get_parser=float,
            docstring=('The burst period is the time '
                       'between the starts of consecutive '
                       'bursts when trigger is immediate.'))