Ejemplo n.º 1
0
    def _upload_awg_program(self, awg_program, core=0):
        # Transfer the AWG sequence program. Compilation starts automatically.
        # Create an instance of the AWG Module
        awgModule = self.daq.awgModule()
        awgModule.set('awgModule/device', self.device)
        awgModule.set('awgModule/index', int(core))
        awgModule.execute()
        awgModule.set('awgModule/compiler/sourcestring', awg_program)
        while awgModule.getInt('awgModule/compiler/status') == -1:
            time.sleep(0.1)
            if self.isStopped():
                return

        if awgModule.getInt('awgModule/compiler/status') == 1:
            # compilation failed, raise an exception
            raise Error('Upload failed:\n' +
                        awgModule.getString('awgModule/compiler/statusstring'))

        if awgModule.getInt('awgModule/compiler/status') == 2:
            self.log("Compiler warning: ",
                     awgModule.getString('awgModule/compiler/statusstring'))

        # Wait for the waveform upload to finish
        time.sleep(0.1)
        while ((awgModule.getDouble('awgModule/progress') < 1.0)
               and (awgModule.getInt('awgModule/elf/status') != 1)):
            time.sleep(0.1)
            if self.isStopped():
                return

        if awgModule.getInt('awgModule/elf/status') == 1:
            raise Error("Uploading the AWG program failed.")
Ejemplo n.º 2
0
    def _get_node_datatype(self, node):
        """Get datatype for object at node"""
        # used cached value, if available
        if node in self._node_datatypes:
            return self._node_datatypes[node]
        # find datatype from returned data
        d = self.daq.get(node, True)
        if len(d) == 0:
            raise Error('No value defined at node %s.' % node)

        data = next(iter(d.values()))
        # if returning dict, strip timing information (API level 6)
        if isinstance(data, dict) and 'value' in data:
            data = data['value']
        # get first item, if python list assume string
        if isinstance(data, list):
            dtype = str
        # not string, should be np array, check dtype
        elif data.dtype in (int, np.int_, np.int64, np.int32, np.int16):
            dtype = int
        elif data.dtype in (float, np.float_, np.float64, np.float32):
            dtype = float
        elif data.dtype in (complex, np.complex_, np.complex64, np.complex128):
            dtype = complex
        else:
            raise Error('Undefined datatype for node %s.' % node)

        # keep track of datatype for future use
        self._node_datatypes[node] = dtype
        self.log('Datatype:', node, dtype)
        return dtype
Ejemplo n.º 3
0
    def performOpen(self, options={}):
        """Perform the operation of opening the instrument connection"""
        # number of demod blocks in the FPGA
        self.num_of_demods = 5
        # self.demod_n_pts = self.num_of_demods * 15
        self.demod_n_pts = 80
        self.bit_stream_name = ''

        # set time step and resolution
        self.nBit = 16
        self.bitRange = float(2**(self.nBit - 1) - 1)
        # timeout
        self.timeout_ms = int(1000 * self.dComCfg['Timeout'])
        # get PXI chassis
        self.chassis = int(self.dComCfg.get('PXI chassis', 1))
        # create AWG instance
        self.dig = keysightSD1.SD_AIN()
        AWGPart = self.dig.getProductNameBySlot(
            self.chassis, int(self.comCfg.address))
        self.log('Serial:', self.dig.getSerialNumberBySlot(
            self.chassis, int(self.comCfg.address)))
        if not isinstance(AWGPart, str):
            raise Error('Unit not available')
        # check that model is supported
        dOptionCfg = self.dInstrCfg['options']
        for validId, validName in zip(
                dOptionCfg['model_id'], dOptionCfg['model_str']):
            if AWGPart.find(validId) >= 0:
                # id found, stop searching
                break
        else:
            # loop fell through, raise ID error
            raise IdError(AWGPart, dOptionCfg['model_id'])
        # set model
        self.setModel(validName)
        # sampling rate and number of channles is set by model
        if validName in ('M3102', 'M3302'):
            # 500 MHz models
            self.dt = 2E-9
            self.nCh = 4
        else:
            # assume 100 MHz for all other models
            self.dt = 10E-9
            self.nCh = 4
        # create list of sampled data
        self.lTrace = [np.array([])] * self.nCh
        self.demod_output_ssb = np.zeros((0,), dtype='complex')
        self.demod_buffer = np.zeros((0,), dtype=np.int16)

        self.dig.openWithSlot(AWGPart, self.chassis, int(self.comCfg.address))
        # get hardware version - changes numbering of channels
        hw_version = self.dig.getHardwareVersion()
        if hw_version >= 4:
            # KEYSIGHT - channel numbers start with 1
            self.ch_index_zero = 1
        else:
            # SIGNADYNE - channel numbers start with 0
            self.ch_index_zero = 0
        self.log('HW:', hw_version)
        self.configure_FPGA()
    def configure_FPGA(self, reset=False):
        """Load FPGA bitstream and setup triggers"""
        self.fpga_config = self.getValue('FPGA Hardware')

        if reset or self.fpga_config == 'Only signals':
            bitstream = os.path.join(
                os.path.dirname(__file__),
                'firmware_FPGAFlow_Clean_2018-05-31T22_22_11.sbp')
        elif self.fpga_config in ('FPGA I/Q and signals', 'Only FPGA I/Q'):
            bitstream = os.path.join(
                os.path.dirname(__file__),
                'firmware_FPGAFlow_Demod_v4_IQx5_2018-09-02T19_14_50.sbp')

        # don't reload if correct bitstream is already loaded
        if bitstream == self.bit_stream_name:
            return

        if (self.dig.FPGAload(bitstream)) < 0:
            if self.fpga_config != 'Only signals':
                raise Error('FPGA not loaded, check FPGA version...')
        self.bit_stream_name = bitstream

        if self.fpga_config != 'Only signals':
            for n in range(self.num_of_demods):
                LO_freq = self.getValue('LO freq %d' % (n + 1))
                self.setFPGALOfreq(n + 1, LO_freq)

            self.setFPGATrigger()
Ejemplo n.º 5
0
 def performOpen(self, options={}):
     """Perform the operation of opening the instrument connection"""
     # set time step and resolution
     self.nBit = 16
     self.bitRange = float(2**(self.nBit-1)-1)
     # timeout
     self.timeout_ms = int(1000 * self.dComCfg['Timeout'])
     # create AWG instance
     self.dig = keysightSD1.SD_AIN()
     AWGPart = self.dig.getProductNameBySlot(1, int(self.comCfg.address))
     if not isinstance(AWGPart, str):
         raise Error('Unit not available')
     # check that model is supported
     dOptionCfg = self.dInstrCfg['options']
     for validId, validName in zip(dOptionCfg['model_id'], dOptionCfg['model_str']):
         if AWGPart.find(validId)>=0:
             # id found, stop searching
             break
     else:
         # loop fell through, raise ID error
         raise IdError(AWGPart, dOptionCfg['model_id'])
     # set model
     self.setModel(validName)
     # sampling rate and number of channles is set by model
     if validName in ('M3102', 'M3302'):
         # 500 MHz models
         self.dt = 2E-9
         self.nCh = 4
     else:
         # assume 100 MHz for all other models
         self.dt = 10E-9
         self.nCh = 4
     # create list of sampled data
     self.lTrace = [np.array([])] * self.nCh
     self.dig.openWithSlot(AWGPart, 1, int(self.comCfg.address))
Ejemplo n.º 6
0
    def performOpen(self, options={}):
        """Perform the operation of opening the instrument connection"""
        # add compatibility with pre-1.5.4 version of Labber
        if not hasattr(self, 'getTrigChannel'):
            self.getTrigChannel = self._getTrigChannel
        # timeout
        self.timeout_ms = int(1000 * self.dComCfg['Timeout'])
        # get PXI chassis
        self.chassis = int(self.dComCfg.get('PXI chassis', 1))
        # create AWG instance
        # get PXI chassis
        self.chassis = int(self.dComCfg.get('PXI chassis', 1))
        self.AWG = keysightSD1.SD_AOU()
        AWGPart = self.AWG.getProductNameBySlot(self.chassis,
                                                int(self.comCfg.address))
        if not isinstance(AWGPart, str):
            raise Error('Unit not available')
        # check that model is supported
        dOptionCfg = self.dInstrCfg['options']
        for validId, validName in zip(dOptionCfg['model_id'],
                                      dOptionCfg['model_str']):
            if AWGPart.find(validId) >= 0:
                # id found, stop searching
                break
        else:
            # loop fell through, raise ID error
            raise IdError(AWGPart, dOptionCfg['model_id'])
        # set model
        self.setModel(validName)
        self.AWG.openWithSlot(AWGPart, self.chassis, int(self.comCfg.address))
        # sampling rate and number of channles is set by model
        if validName in ('M3202', 'H3344'):
            # 1GS/s models
            self.dt = 1E-9
            self.nCh = 4
        elif validName == 'M3302':
            # two-channel, 500 MS/s model
            self.dt = 2E-9
            self.nCh = 2
        else:
            # assume 500 MS/s for all other models
            self.dt = 2E-9
            self.nCh = 4
        # keep track of if waveform was updated
        self.waveform_updated = [False] * self.nCh
        self.previous_upload = dict()
        self.waveform_sizes = dict()

        # get hardware version - changes numbering of channels
        hw_version = self.AWG.getHardwareVersion()
        if hw_version >= 4:
            # KEYSIGHT - channel numbers start with 1
            self.ch_index_zero = 1
        else:
            # SIGNADYNE - channel numbers start with 0
            self.ch_index_zero = 0

        # clear old waveforms
        self.clearOldWaveforms()
Ejemplo n.º 7
0
 def scaleWaveformToU16(self, vData, dVpp, ch):
     """Scales the waveform and returns data in a string of U16"""
     # make sure waveform data is within the voltage range
     if np.sum(vData > dVpp / 2) or np.sum(vData < -dVpp / 2):
         raise Error(('Waveform for channel %d contains values that are ' %
                      ch) + 'outside the channel voltage range.')
     # clip waveform and store in-place
     np.clip(vData, -dVpp / 2., dVpp / 2., vData)
     vU16 = np.array(4094 * (vData + dVpp / 2.) / dVpp, dtype=np.uint16)
     return vU16
Ejemplo n.º 8
0
    def open_modules(self, slots, type):
        ''' 
        slots = list of slot numbers of device
        type = string 'awg' to open awg modules, 'dig' to
        open digitizer modules
        open_modules creates and returns a list keysightSD1 module objects
        '''
        log_string = ""
        log_status = 20
        options = "channelNumbering=keysight"
        model = ""
        modules = []
        if slots:
            for slot in slots:
                if type == 'awg':
                    module = keysightSD1.SD_AOU()
                elif type == 'dig':
                    module = keysightSD1.SD_AIN()
                else:
                    raise Error('Only AWGs and digitizers are supported')

                # check that we haven't already assigned module to this slot
                if self.slot_free[slot - 1] == True:
                    id_num = module.openWithOptions(model, self.chassis, slot,
                                                    options)
                    if id_num < 0:
                        raise Error(
                            "Error opening module in chassis {}, slot {}, opened with ID: {}"
                            .format(self.chassis, slot, id_num))
                    if not module.hvi:
                        raise Error(
                            "Module in chassis {} and slot {} does not support HVI2.0... exiting"
                            .format(awgModule.getChassis(),
                                    awgModule.getSlot()))
                    modules.append(module)
                    self.slot_free[slot - 1] = False
                    log_string += 'slots status: ' + str(self.slot_free) + '\n'
                else:
                    log_string += 'slot taken, check behavior' + '\n'
                    log_status = 30
        return modules, log_string, log_status
Ejemplo n.º 9
0
    def sendWaveformToAWG(self, channel, vData, vMark1, vMark2):
        """Send waveform to Tek"""
        # turn off output and clear old traces
        self.writeAndLog(':INST %d;:OUTP 0' % channel)
        self.writeAndLog(':TRAC:DEL:ALL')
        # if output is disabled, stop here
        if not self.getValue('Ch%d - Enabled' % channel):
            return False

        # channels are named 1-2
        n = channel - 1
        if len(vData) == 0:
            if len(vMark1) == 0 and len(vMark2) == 0:
                # turn off, clear, go to next channel
                self.lInUse[n] = False
                return False
            else:
                # no data, but markers exist, output zeros for data
                nMark = max(len(vMark1), len(vMark2))
                vData = np.zeros((nMark, ), dtype=float)
        # make sure length of data is the same
        if (len(vMark1) > 0 and len(vData) != len(vMark1)) or \
           (len(vMark2) > 0 and len(vData) != len(vMark2)):
            raise Error(
                'All channels need to have the same number of elements')
        self.nPrevData = len(vData)
        # channel in use, mark
        self.lInUse[n] = True
        # get range and scale to U16
        Vpp = self.getValue('Ch%d - Range' % channel)
        vU16 = self.scaleWaveformToU16(vData, Vpp, channel)
        # check for marker traces
        for m, marker in enumerate([vMark1, vMark2]):
            if len(marker) == len(vU16):
                # get marker trace
                vMU16 = np.array(marker != 0, dtype=np.uint16)
                # add marker trace to data trace, with bit shift
                vU16 += 2**(12 + m) * vMU16
        # granularity of the awg is 32
        if len(vU16) % 32 > 0:
            vU16 = np.pad(vU16, (0, 32 - (len(vU16) % 32)),
                          'constant',
                          constant_values=2047)

        self.writeAndLog(':TRAC:DEF 1, %d' % len(vU16))
        self.writeAndLog(':TRAC:SEL 1')
        download_binary_data(self.com,
                             'TRAC:DATA',
                             vU16,
                             len(vU16) * 2,
                             paranoia_level=0)
        return True
Ejemplo n.º 10
0
 def performOpen(self, options={}):
     """Perform the operation of opening the instrument connection"""
     # timeout
     self.timeout_ms = int(1000 * self.dComCfg['Timeout'])
     # create AWG instance
     self.AWG = keysightSD1.SD_AOU()
     AWGPart = self.AWG.getProductNameBySlot(1, int(self.comCfg.address))
     if not isinstance(AWGPart, str):
         raise Error('Unit not available')
     # check that model is supported
     dOptionCfg = self.dInstrCfg['options']
     for validId, validName in zip(dOptionCfg['model_id'], dOptionCfg['model_str']):
         if AWGPart.find(validId)>=0:
             # id found, stop searching
             break
     else:
         # loop fell through, raise ID error
         raise IdError(AWGPart, dOptionCfg['model_id'])
     # set model
     self.setModel(validName)
     self.AWG.openWithSlot(AWGPart, 1, int(self.comCfg.address))
     # sampling rate and number of channles is set by model
     if validName in ('M3202', 'H3344'):
         # 1GS/s models
         self.dt = 1E-9
         self.nCh = 4
     elif validName in ('M3302',):
         # two-channel, 500 MS/s model
         self.dt = 2E-9
         self.nCh = 2
     else:
         # assume 500 MS/s for all other models
         self.dt = 2E-9
         self.nCh = 4
     # keep track of if waveform was updated
     self.lWaveUpdated = [False]*self.nCh
     # get hardware version - changes numbering of channels
     hw_version = self.AWG.getHardwareVersion()
     if hw_version >= 4:
         # KEYSIGHT - channel numbers start with 1
         self.ch_index_zero = 1
     else:
         # SIGNADYNE - channel numbers start with 0
         self.ch_index_zero = 0
     self.log('HW:', hw_version)
     # clear old waveforms
     self.AWG.waveformFlush()
     for ch in range(self.nCh):
         self.AWG.AWGflush(self.get_hw_ch(ch))
Ejemplo n.º 11
0
    def _get_node_value(self, quant):
        """Get instrument value using ZI node hierarchy"""
        # get node definition
        node = self._get_node(quant)
        dtype = self._get_node_datatype(node)
        # read data from ZI
        d = self.daq.get(node, True)
        if len(d) == 0:
            raise Error('No value defined at node %s.' % node)
        # extract and return data
        data = next(iter(d.values()))
        # if returning dict, strip timing information (API level 6)
        if isinstance(data, dict) and 'value' in data:
            data = data['value']
        value = dtype(data[0])

        # convert to index for combo datatypes
        if quant.datatype == quant.COMBO:
            # if no command options are given, use index
            if len(quant.cmd_def) == 0:
                cmd_options = list(range(len(quant.combo_defs)))
            else:
                # convert option list to correct datatype
                cmd_options = [dtype(x) for x in quant.cmd_def]

            # look for correct option
            try:
                index = cmd_options.index(value)
                value = quant.combo_defs[index]
            except Exception:
                raise Error(
                    'Invalid value %s for quantity %s, should be one of %s.' %
                    (str(value), quant.name, str(cmd_options)))

        self.log('Get value', quant.name, node, data, value)
        return value
Ejemplo n.º 12
0
    def queueWaveform(self, ch, waveform_id):
        """Queue waveform to AWG channel"""
        # get trig parameters
        trigMode = int(self.getChannelCmd(ch, 'Trig mode'))
        if self.getChannelValue(ch,
                                'Trig mode') in ('Software / HVI', 'External'):
            cycles = int(self.getChannelValue(ch, 'Cycles'))
        else:
            cycles = 1
        prescaler = 0
        delay = int(round(self.getValue('Trig delay') / 10E-9))
        # if aligning waveform to end of trig, adjust delay
        if self.getValue('Waveform alignment') == 'End at trig':
            delay -= round(self.waveform_sizes[waveform_id] * self.dt / 10E-9)
            # add extra after waveform ends
            delay -= int(round(self.getValue('Delay after end') / 10E-9))
            # raise error if delay is negative
            if delay < 0:
                raise Error('"Trig delay" must be larger than waveform length')
        if self.getChannelValue(
                ch, 'Trig mode') in ('Software / HVI',
                                     'External') and self.getChannelValue(
                                         ch, 'Immediate'):
            nbr_awg_channels = len(self.getAWGChannelsInUse())
            #if waveform_id > -1:
            if waveform_id > nbr_awg_channels:
                trigMode = 0
        # if delay is longer than 50 us, fix bug by using empty waveform
        if delay > 5000:
            # empty waveform is 10 us long, find number of empty waves needed
            (n_empty, final_delay) = divmod(delay, 5000)
            # queue empty waveforms
            s = self.AWG.AWGqueueWaveform(self.getHwCh(ch), 0, trigMode, 0,
                                          n_empty, prescaler)
            self.check_keysight_error(s)
            # queue the actual waveform
            s = self.AWG.AWGqueueWaveform(self.getHwCh(ch), waveform_id, 0,
                                          final_delay, cycles, prescaler)
            self.check_keysight_error(s)

        else:
            # queue waveform, inform user if an error happens
            s = self.AWG.AWGqueueWaveform(self.getHwCh(ch), waveform_id,
                                          trigMode, delay, cycles, prescaler)
            self.check_keysight_error(s)
Ejemplo n.º 13
0
    def __init__(self, chassis):
        '''
        set up chassis

        the main function connects to hardware, writes a trigger instruction sequence to all hardware,
        then runs triggering until user interrupt
        '''
        # modules chassis and slot numbers
        if self.__initialized: return

        self.__initialized = True
        self.awg_slots = []
        self.dig_slots = []
        self.slot_free = [True] * 18

        # Ext trigger module (TODO: not sure if these values might ever change)
        self.chassis = chassis
        slotNumber = 6
        partNumber = ""

        extTrigModule = keysightSD1.SD_AOU()
        status = extTrigModule.openWithSlot(partNumber, self.chassis,
                                            slotNumber)
        if (status < 0):
            raise Error(
                "Invalid external trigger module. Name, Chassis or Slot numbers might be invalid!"
            )

        # Create HVI instance
        moduleResourceName = "KtHvi"
        self.hvi = pyhvi.KtHvi(moduleResourceName)

        # Add chassis
        self.hvi.platform.chassis.add_auto_detect()

        # initialize lists for clarity
        self.awgs = []
        self.digs = []
        # ensure that when program quits, the hardware resources will be released
        atexit.register(self.close)
Ejemplo n.º 14
0
    def configure_hvi(self):
        """Configure and start/stop HVI depending on UI settings"""
        # get units
        units = self.get_pxi_config_from_ui()
        n_awg = len([x for x in units if x == 1])
        n_dig = len([x for x in units if x == 2])

        # if no units in use, just stop
        if (n_awg + n_dig) == 0:
            self.HVI.stop()
            return

        # check if unit configuration changed, if so reload HVI
        if units != self.units:
            # stop current HVI, may not even be running
            self.HVI.stop()
            self.HVI.close()
            self.units = units

            self.log('-----------')
            self.log('HVI CONFIGURE!')
            self.log('-----------')

            # we need at least one AWG
            if n_awg == 0:
                raise Error('This driver requires at least one AWG.')
            # currently only support 2 digitizers
            if n_dig > 2:
                raise Error('This driver only supports up to two digitizers.')

            # get HVI name and open
            hvi_name = 'InternalTrigger_%d_%d.HVI' % (n_awg, n_dig)
            dir_path = os.path.dirname(os.path.realpath(__file__))
            self.HVI.open(os.path.join(dir_path, 'HVI_Delay', hvi_name))

            # assign units, run twice to ignore errors before all units are set
            for m in range(2):
                awg_number = 0
                dig_number = 0
                for n, unit in enumerate(units):
                    # if unit in use, assign to module
                    if unit == 0:
                        continue
                    elif unit == 1:
                        # AWG
                        module_name = 'Module %d' % awg_number
                        awg_number += 1
                    elif unit == 2:
                        # digitizer
                        module_name = 'DAQ %d' % dig_number
                        dig_number += 1
                    r = self.HVI.assignHardwareWithUserNameAndSlot(
                        module_name, self.chassis, n + 1)
                    # only check for errors after second run
                    if m > 0:
                        self.check_keysight_error(r)
            # clear old trig period to force update
            self.old_trig_period = 0.0

        # only update trig period if necessary, takes time to re-compile
        if (self.getValue('Trig period') != self.old_trig_period
                or self.getValue('Digitizer delay') != self.old_dig_delay):
            self.old_trig_period = self.getValue('Trig period')
            self.old_dig_delay = self.getValue('Digitizer delay')
            # update trig period, include 460 ns delay in HVI
            wait = round(self.getValue('Trig period') / 10E-9) - 46
            digi_wait = round(self.getValue('Digitizer delay') / 10E-9)
            # special case if only one module: add 240 ns extra delay
            if (n_awg + n_dig) == 1:
                wait += 24
            # r = self.HVI.writeIntegerConstantWithIndex(0, 'Wait time', wait)
            r = self.HVI.writeIntegerConstantWithUserName(
                'Module 0', 'Wait time', wait)
            self.check_keysight_error(r)
            self.log('Number of modules', self.HVI.getNumberOfModules())
            for n in range(n_dig):
                r = self.HVI.writeIntegerConstantWithUserName(
                    'DAQ %d' % n, 'Digi wait', digi_wait)
                self.check_keysight_error(r)

            # need to recompile after setting wait time, not sure why
            self.check_keysight_error(self.HVI.compile())
            # try to load a few times, sometimes hangs on first try
            n_try = 5
            while True:
                try:
                    self.check_keysight_error(self.HVI.load())
                    break
                except Exception:
                    n_try -= 1
                    if n_try <= 0:
                        raise

        # start or stop the HVI, depending on output state
        if self.getValue('Output'):
            self.check_keysight_error(self.HVI.start())

        else:
            self.HVI.stop()
Ejemplo n.º 15
0
 def check_keysight_error(self, code):
     """Check and raise error"""
     if code >= 0:
         return
     # get error message
     raise Error(keysightSD1.SD_Error.getErrorMessage(code))
Ejemplo n.º 16
0
    def write_instructions(self, wait, dig_wait=0):
        ''' creates instruction sequences for all devices
        wait = global AWG wait time
        dig_wait = (optional) digitizer wait time

        both need to be multiples of 10 
        '''

        NANOSECONDS_PER_CYCLE = 10
        # Check experiment parameters values
        timeElapsedJumping = 170
        if wait % 10 != 0:  # Validate that we received values that are multiples of 10 ns.
            raise Error(
                'Invalid wait time. Value must be a multiple of 10 ns.')
        if wait < timeElapsedJumping:
            raise Error('Invalid wait time. The delay must be at least ' +
                        str(timeElapsedJumping + 900) + ' ns')
        if wait < 2000:
            raise Error(
                "warning: you might get unexpected behavior with wait times less than 2 us"
            )

        if dig_wait % 10 != 0:
            raise Error(
                'Invalid digitizer wait time. Value must be a multiple of 10 ns'
            )

        wait = wait - timeElapsedJumping - 900
        wait = int(wait / NANOSECONDS_PER_CYCLE)

        dig_wait = int(dig_wait / NANOSECONDS_PER_CYCLE)
        # Add registers
        self.awgs[0].add_register("wait", wait)
        self.awgs[0].add_register("true_reg", 1)
        self.awgs[0].add_register("loop", 0)

        if dig_wait > 0:
            self.digs[0].add_register("dig_wait", wait)
            self.digs[0].assign_register_value(self.hvi, "write dig wait",
                                               "dig_wait", dig_wait)

        # Write instruction sequences

        # Assign to register "wait" its initial value
        self.awgs[0].assign_register_value(self.hvi, "write wait", "wait",
                                           wait)

        # Add global synchronized junction
        junctionName = "SJunc1"
        junctionTime_ns = 100  #not sure how long this should be
        self.hvi.programming.add_junction(junctionName, junctionTime_ns)

        # Add triggers
        awg0 = True
        for awg in self.awgs:
            awg.trigger_all(self.hvi)
            if awg0:
                # adds Wait length contained in Wait register
                self.awgs[0].add_wait("wait for", "wait")
                self.awgs[0].increment_register_value(self.hvi, "loop inc",
                                                      "loop")
                awg0 = False

        dig0 = True
        for dig in self.digs:
            dig.trigger_all(self.hvi)
            if dig_wait > 0 and dig0:
                self.digs[0].add_wait("dig wait for", "dig_wait")
                dig0 = False

        # === Conditional jumps =====
        master_seq_name = self.awgs[0].return_sequence_name()
        timeElapsedBeforeJump = 200
        #Internal Loop - Conditional Jump
        jump_destination = "SJunc1"
        sync_conditional = self.hvi.programming.add_conditional_jump(
            "SCond1", timeElapsedBeforeJump, timeElapsedJumping,
            jump_destination, master_seq_name)
        # Set up the condition:
        condition = sync_conditional.conditions.add_register_condition("")
        comparison_operator = pyhvi.ComparisonMode.SMALLER
        condition.register_evaluations.add(
            "true", self.awgs[0].return_register("true_reg"), 10,
            comparison_operator)

        # === END =====
        # Add global synchronized end to close HVI execution (close all sequences - using hvi-programming interface)
        self.hvi.programming.add_end("EndOfSequence", 100)
Ejemplo n.º 17
0
    def _configure_sequencer(self, group=1, buffer_size=None):
        """Configure sequencer and upload program for given group"""
        # currently only supports one AWG group
        if self.getValue('Channel grouping') != '1 x 8':
            raise Error('Driver currently only support 1x8 channel group mode')

        self._map_awg_to_channel()
        # create waveforms, one per channel
        awg_program = ''.join(
            ['wave w%d = zeros(_n_);\n' % (n + 1) for n in range(self.n_ch)])

        # create list of link between AWGs and channel outputs
        x = []
        for awg, in_use in enumerate(self.awg_in_use):
            if in_use:
                # awg in use, create string for playing wave
                y = ','.join([('%d' % (ch + 1)) for ch in self.awg_to_ch[awg]])
                y += ', w%d' % (awg + 1)
                x.append(y)
            else:
                # not in use, still add to corresponding channel, will be empty
                x.append('%d, w%d' % (awg + 1, awg + 1))
        channels = ', '.join(x)
        self.log(channels)

        # check version of API
        new_style = hasattr(self.daq, 'setVector')
        # proceed depending on run mode
        run_mode = self.getValue('Run mode, group %d' % group)
        # in internal trigger mode, make buffer as long as trig interval
        if run_mode == 'Internal trigger':
            trig_period = self.getValue('Trig period, group %d' % group)
            sampling_rate = 2.4E9 / (2**self.getValueIndex(
                'Sampling rate, group %d' % group))
            # timing changed for new API version
            if new_style:
                # new style - large delays
                buffer_size = int(
                    round((trig_period - 30E-9 - 3.9E-6) * sampling_rate))
                # wait time is in units of 10/3 ns
                wait_time = int(round(3 * (30E-9 / 10E-9)))
                # remove a few clock cycles to account for while/wait time
                wait_time -= 7
                awg_program += textwrap.dedent("""\
                    setUserReg(0, 0);
                    while(true){
                        while(getUserReg(0) == 0){
                            playWave(%s);
                            waitWave();
                            wait(%d);
                        }
                    }""") % (channels, wait_time)
            else:
                buffer_size = int(round(trig_period * sampling_rate))
                # wait time is in units of 10/3 ns
                wait_time = int(round(3 * (trig_period / 10E-9)))
                # remove a few clock cycles to account for while/wait time
                wait_time -= 7
                awg_program += textwrap.dedent("""\
                    setUserReg(0, 0);
                    while(true){
                        while(getUserReg(0) == 0){
                            playWave(%s);
                            wait(%d);
                        }
                    }""") % (channels, wait_time)

            # limit to max memory of unit
            buffer_size = min(buffer_size, 64E6)
            awg_program = awg_program.replace('_n_', ('%d' % buffer_size))

        elif run_mode == 'External trigger':
            buffer_length = self.getValue('Buffer length, group %d' % group)
            sampling_rate = 2.4E9 / (2**self.getValueIndex(
                'Sampling rate, group %d' % group))
            buffer_size = int(round(buffer_length * sampling_rate))
            # limit to max memory of unit
            buffer_size = min(buffer_size, 64E6)

            awg_program += textwrap.dedent("""\
                setUserReg(0, 0);
                while(true){
                    waitDigTrigger(1);
                    playWave(%s);
                }""") % (channels)
            # the code below trigs faster, but only works for <400 ns waveforms
            # setUserReg(0, 0);
            # while(true){
            #     playWaveDigTrigger(1, %s);

            awg_program = awg_program.replace('_n_', ('%d' % buffer_size))

        # keep track of buffer size
        self.buffer_sizes[group - 1] = buffer_size
        # stop current AWG
        base = '/%s/awgs/0/' % self.device
        self.daq.setInt(base + 'enable', 0)
        # compile and upload
        self._upload_awg_program(awg_program)

        # set to single-shot mode and enable
        self.daq.setInt(base + 'single', 1)
        self.daq.setInt(base + 'enable', 1)
Ejemplo n.º 18
0
    def configure_hvi(self):
        """Configure and start/stop HVI depending on UI settings"""
        # get units
        units = self.get_pxi_config_from_ui()
        n_awg = len([x for x in units if x == 1])
        n_dig = len([x for x in units if x == 2])

        # if no units in use, just stop
        if (n_awg + n_dig) == 0:
            return

        # check if unit configuration changed, if so reload HVI
        if units != self.units:
            # stop current HVI, may not even be running
            self.units = units

            # we need at least one AWG
            if n_awg == 0:
                raise Error('This driver requires at least one AWG.')

            # assign units, run twice to ignore errors before all units are set
            awg_slots = []
            dig_slots = []
            for m in range(2):
                for n, unit in enumerate(units):
                    # if unit in use, assign to module
                    if unit == 0:
                        continue
                    elif unit == 1:
                        # AWG
                        awg_slots.append(n + 1)
                    elif unit == 2:
                        # digitizer
                        dig_slots.append(n + 1)

        # only update trig period or slots if necessary, takes time to re-compile
        if (awg_slots != self.awg_slots or dig_slots != self.dig_slots):
            # hardcoding chassis number = 1 because pyhvi won't work
            # with multiple chassis
            self.awg_slots = awg_slots
            self.dig_slots = dig_slots
            #awgModules = self.open_modules(1, awg_slots, 'awg')
            #digModules = self.open_modules(1, dig_slots, 'dig')
            #close_log, awg_info, dig_info = self.trigger_loop.set_slots(self.awg_slots, self.dig_slots, slot_free)

            close_log = self.trigger_loop.close_modules()

            self.log('closed: ' + close_log)

            self.trigger_loop.awg_slots = awg_slots
            self.trigger_loop.dig_slots = dig_slots

            awg_info, dig_info = self.trigger_loop.init_hw()

            self.log('awg: ' + awg_info[0], awg_info[1])
            self.log('dig: ' + dig_info[0], dig_info[1])

            # always check trig period now because we have to recompile anyway
            self.old_trig_period = self.getValue('Trig period')
            self.old_dig_delay = self.getValue('Digitizer delay')

            wait = round(self.getValue('Trig period') / 10E-9) - 46
            digi_wait = round(self.getValue('Digitizer delay') / 10E-9)
            # special case if only one module: add 240 ns extra delay
            if (n_awg + n_dig) == 1:
                wait += 24

            self.trigger_loop.write_instructions(wait * 10, digi_wait)
            self.trigger_loop.prepare_hw()

        if (self.getValue('Trig period') != self.old_trig_period
                or self.getValue('Digitizer delay') != self.old_dig_delay):

            self.old_trig_period = self.getValue('Trig period')
            self.old_dig_delay = self.getValue('Digitizer delay')
            # update trig period, include 460 ns delay in HVI
            wait = round(self.getValue('Trig period') / 10E-9) - 46
            digi_wait = round(self.getValue('Digitizer delay') / 10E-9)
            # special case if only one module: add 240 ns extra delay
            if (n_awg + n_dig) == 1:
                wait += 24

            self.trigger_loop.write_instructions(wait, digi_wait)
            self.trigger_loop.prepare_hw()

        # start or stop the HVI, depending on output state
        if self.getValue('Output'):
            self.trigger_loop.run()

        else:
            self.trigger_loop.close()
Ejemplo n.º 19
0
    def configure_hvi(self):
        """Configure and start/stop HVI depending on UI settings"""
        # get units
        units = self.get_pxi_config_from_ui()
        n_awg = len([x for x in units if x == 1])
        n_dig = len([x for x in units if x == 2])

        # if no units in use, just stop
        if (n_awg + n_dig) == 0:
            self.HVI.stop()
            return

        # check if unit configuration changed, if so reload HVI
        if units != self.units:
            # stop current HVI, may not even be running
            self.HVI.stop()
            self.HVI.close()
            self.units = units

            # we need at least one AWG
            if n_awg == 0:
                raise Error('This driver requires at least one AWG.')
            # currently only support 1 digitizer
            if n_dig > 1:
                raise Error('This driver only supports one digitizer.')

            # get HVI name and open
            hvi_name = 'InternalTrigger_%d_%d.HVI' % (n_awg, n_dig)
            dir_path = os.path.dirname(os.path.realpath(__file__))
            self.HVI.open(os.path.join(dir_path, 'HVI', hvi_name))

            # assign hardware
            awg_number = 0
            dig_number = 0
            for n, unit in enumerate(units):
                # if unit in use, assign to module
                if unit == 0:
                    continue
                elif unit == 1:
                    # AWG
                    module_name = 'Module %d' % awg_number
                    awg_number += 1
                elif unit == 2:
                    # digitizer
                    module_name = 'DAQ %d' % dig_number
                    dig_number += 1
                r = self.HVI.assignHardwareWithUserNameAndSlot(
                    module_name, self.chassis, n + 1)
                self.check_keysight_error(r)
            # clear old trig period to force update
            self.old_trig_period = 0.0

        # only update trig period if necessary, takes time to re-compile
        if self.getValue('Trig period') != self.old_trig_period:
            self.old_trig_period = self.getValue('Trig period')
            # update trig period, include 460 ns delay in HVI
            wait = round(self.getValue('Trig period') / 10E-9) - 46
            # special case if only one module: add 240 ns extra delay
            if (n_awg + n_dig) == 1:
                wait += 24
            r = self.HVI.writeIntegerConstantWithIndex(0, 'Wait time', wait)
            self.check_keysight_error(r)
            # need to recompile after setting wait time, not sure why
            self.check_keysight_error(self.HVI.compile())
            self.check_keysight_error(self.HVI.load())

        # start or stop the HVI, depending on output state
        if self.getValue('Output'):
            self.check_keysight_error(self.HVI.start())

        else:
            self.HVI.stop()