Example #1
0
def compile_to_hardware(seqs, fileName=None, suffix='', alignMode="right", nbrRepeats=1):
    #Add the digitizer trigger to each sequence
    #TODO: Make this more sophisticated.
    PatternUtils.add_digitizer_trigger(seqs, channelLib['digitizerTrig'])
    
    # normalize sequences
    channels = set([])
    for seq in seqs:
        channels |= find_unique_channels(seq)
    seqs = [normalize(seq, channels) for seq in seqs]

    #Compile all the pulses/pulseblocks to linklists and waveform libraries
    linkLists, wfLib = compile_sequences(seqs)

    # align channels
    # this horrible line finds the longest miniLL across all channels
    longestLL = max([sum([entry.totLength for entry in miniLL]) for LL in linkLists.values() for miniLL in LL])
    
    for chan, LL in linkLists.items():
        PatternUtils.align(LL, alignMode, longestLL+SEQUENCE_PADDING)

    #Add the slave trigger
    #TODO: only add to slave devices
    linkLists[channelLib['slaveTrig']], wfLib[channelLib['slaveTrig']] = PatternUtils.slave_trigger(len(seqs))

    # map logical to physical channels
    awgData = map_logical_to_physical(linkLists, wfLib)

    # for each physical channel need to:
    # 1) delay
    # 2) apply SSB if necessary
    # 3) mixer correct
    for awgName, awg in awgData.items():
        for chanName, chanData in awg.items():
            if chanData:
                # construct IQkey using existing convention
                IQkey = awgName + '-' + chanName[2:]
                chanObj = channelLib[IQkey]
                #We handle marker and quadrature channels differently
                #For now that is all we handle
                if isinstance(chanObj, Channels.PhysicalQuadratureChannel):
                    #Apply mixer corrections and channel delay 
                    PatternUtils.delay(chanData['linkList'], chanObj.delay + chanObj.AWG.delay, chanObj.samplingRate)

                    #At this point we finally have the timing of all the pulses so we can apply SSB
                    if hasattr(chanObj, 'SSBFreq') and abs(chanObj.SSBFreq) > 0:
                        PatternUtils.apply_SSB(chanData['linkList'], chanData['wfLib'], chanObj.SSBFreq, chanObj.samplingRate)

                    PatternUtils.correctMixer(chanData['wfLib'], chanObj.correctionT)

                    # add gate pulses on the marker channel
                    # note that the marker may be on an entirely different AWG
                    markerAwgName, markerKey = chanObj.gateChan.label.split('-')
                    markerKey = 'ch' + markerKey
                    markerAwg = awgData[markerAwgName]
                    genObj = chanObj.generator
                    #TODO: check if this actually catches overwriting markers
                    if markerAwg[markerKey]:
                        warn('Reuse of marker gating channel: {0}'.format(markerKey))
                    markerAwg[markerKey] = {'linkList':None, 'wfLib':markerWFLib}
                    markerAwg[markerKey]['linkList'] = PatternUtils.create_gate_seqs(
                        chanData['linkList'], genObj.gateBuffer, genObj.gateMinWidth, chanObj.samplingRate)
                    markerDelay = genObj.gateDelay + chanObj.gateChan.delay + (chanObj.AWG.delay - chanObj.gateChan.AWG.delay)
                    PatternUtils.delay(markerAwg[markerKey]['linkList'], markerDelay, chanObj.gateChan.samplingRate )


                elif isinstance(chanObj, Channels.PhysicalMarkerChannel):
                    PatternUtils.delay(chanData['linkList'], chanObj.delay+chanObj.AWG.delay, chanObj.samplingRate)

                else:
                    raise NameError('Unable to handle channel type.')

                #Remove unused waveforms
                compress_wfLib(chanData['linkList'], chanData['wfLib'])

    #Loop back through to fill empty channels and write to file
    fileList = []
    for awgName, awg in awgData.items():
        #If all the channels are empty then do not bother writing the file
        if not all([chan is None for chan in awg.values()]):
            for chan in awg.keys():
                if not awg[chan]:
                    #"Seems hackish but check for marker
                    if chan[-2] == 'm':
                        awg[chan] = {'linkList': [[create_padding_LL(SEQUENCE_PADDING//2), create_padding_LL(SEQUENCE_PADDING//2)]],
                                 'wfLib': markerWFLib}
                    else:
                        awg[chan] = {'linkList': [[create_padding_LL(SEQUENCE_PADDING//2), create_padding_LL(SEQUENCE_PADDING//2)]],
                                 'wfLib': {TAZKey:np.zeros(1, dtype=np.complex)}}

            # convert to hardware formats
            # create the target folder if it does not exist
            targetFolder = os.path.split(os.path.normpath(os.path.join(config.AWGDir, fileName)))[0]
            if not os.path.exists(targetFolder):
                os.mkdir(targetFolder)
            fullFileName = os.path.normpath(os.path.join(config.AWGDir, fileName + '-' + awgName + suffix + instrumentLib[awgName].seqFileExt))
            if isinstance(instrumentLib[awgName], APS):
                write_APS_file(awg, fullFileName, nbrRepeats)
            elif isinstance(instrumentLib[awgName], Tek5014):
                assert nbrRepeats == 1, 'nbrRepeats > 1 not implemented for the Tek'
                write_Tek_file(awg, fullFileName, fileName)
            else:
                raise NameError('Unknown AWG type')
            fileList.append(fullFileName)

    #Return the filenames we wrote
    return fileList
Example #2
0
def compile_to_hardware(seqs,
                        fileName=None,
                        suffix='',
                        alignMode="right",
                        nbrRepeats=1):
    #Add the digitizer trigger to each sequence
    #TODO: Make this more sophisticated.
    PatternUtils.add_digitizer_trigger(seqs, channelLib['digitizerTrig'])

    # normalize sequences
    channels = set([])
    for seq in seqs:
        channels |= find_unique_channels(seq)
    seqs = [normalize(seq, channels) for seq in seqs]

    #Compile all the pulses/pulseblocks to linklists and waveform libraries
    linkLists, wfLib = compile_sequences(seqs)

    # align channels
    # this horrible line finds the longest miniLL across all channels
    longestLL = max([
        sum([entry.totLength for entry in miniLL])
        for LL in linkLists.values() for miniLL in LL
    ])

    for chan, LL in linkLists.items():
        PatternUtils.align(LL, alignMode, longestLL + SEQUENCE_PADDING)

    #Add the slave trigger
    #TODO: only add to slave devices
    linkLists[channelLib['slaveTrig']], wfLib[
        channelLib['slaveTrig']] = PatternUtils.slave_trigger(len(seqs))

    # map logical to physical channels
    awgData = map_logical_to_physical(linkLists, wfLib)

    # for each physical channel need to:
    # 1) delay
    # 2) apply SSB if necessary
    # 3) mixer correct
    for awgName, awg in awgData.items():
        for chanName, chanData in awg.items():
            if chanData:
                # construct IQkey using existing convention
                IQkey = awgName + '-' + chanName[2:]
                chanObj = channelLib[IQkey]
                #We handle marker and quadrature channels differently
                #For now that is all we handle
                if isinstance(chanObj, Channels.PhysicalQuadratureChannel):
                    #Apply mixer corrections and channel delay
                    PatternUtils.delay(chanData['linkList'],
                                       chanObj.delay + chanObj.AWG.delay,
                                       chanObj.samplingRate)

                    #At this point we finally have the timing of all the pulses so we can apply SSB
                    if hasattr(chanObj,
                               'SSBFreq') and abs(chanObj.SSBFreq) > 0:
                        PatternUtils.apply_SSB(chanData['linkList'],
                                               chanData['wfLib'],
                                               chanObj.SSBFreq,
                                               chanObj.samplingRate)

                    PatternUtils.correctMixer(chanData['wfLib'],
                                              chanObj.correctionT)

                    # add gate pulses on the marker channel
                    # note that the marker may be on an entirely different AWG
                    markerAwgName, markerKey = chanObj.gateChan.name.split('-')
                    markerKey = 'ch' + markerKey
                    markerAwg = awgData[markerAwgName]
                    genObj = chanObj.generator
                    #TODO: check if this actually catches overwriting markers
                    if markerAwg[markerKey]:
                        warn('Reuse of marker gating channel: {0}'.format(
                            markerKey))
                    markerAwg[markerKey] = {
                        'linkList': None,
                        'wfLib': markerWFLib
                    }
                    markerAwg[markerKey][
                        'linkList'] = PatternUtils.create_gate_seqs(
                            chanData['linkList'], genObj.gateBuffer,
                            genObj.gateMinWidth, chanObj.samplingRate)
                    markerDelay = genObj.gateDelay + chanObj.gateChan.delay + (
                        chanObj.AWG.delay - chanObj.gateChan.AWG.delay)
                    PatternUtils.delay(markerAwg[markerKey]['linkList'],
                                       markerDelay,
                                       chanObj.gateChan.samplingRate)

                elif isinstance(chanObj, Channels.PhysicalMarkerChannel):
                    PatternUtils.delay(chanData['linkList'],
                                       chanObj.delay + chanObj.AWG.delay,
                                       chanObj.samplingRate)

                else:
                    raise NameError('Unable to handle channel type.')

    #Loop back through to fill empty channels and write to file
    fileList = []
    for awgName, awg in awgData.items():
        #If all the channels are empty then do not bother writing the file
        if not all([chan is None for chan in awg.values()]):
            for chan in awg.keys():
                if not awg[chan]:
                    #"Seems hackish but check for marker
                    if chan[-2] == 'm':
                        awg[chan] = {
                            'linkList': [[
                                create_padding_LL(SEQUENCE_PADDING // 2),
                                create_padding_LL(SEQUENCE_PADDING // 2)
                            ]],
                            'wfLib':
                            markerWFLib
                        }
                    else:
                        awg[chan] = {
                            'linkList': [[
                                create_padding_LL(SEQUENCE_PADDING // 2),
                                create_padding_LL(SEQUENCE_PADDING // 2)
                            ]],
                            'wfLib': {
                                TAZKey: np.zeros(1, dtype=np.complex)
                            }
                        }

            # convert to hardware formats
            # create the target folder if it does not exist
            targetFolder = os.path.split(config.AWGDir + fileName)[0]
            if not os.path.exists(targetFolder):
                os.mkdir(targetFolder)
            fullFileName = config.AWGDir + fileName + '-' + awgName + suffix + instrumentLib[
                awgName].seqFileExt
            if isinstance(instrumentLib[awgName], APS):
                write_APS_file(awg, fullFileName, nbrRepeats)
            elif isinstance(instrumentLib[awgName], Tek5014):
                assert nbrRepeats == 1, 'nbrRepeats > 1 not implemented for the Tek'
                write_Tek_file(awg, fullFileName, fileName)
            else:
                raise NameError('Unknown AWG type')
            fileList.append(fullFileName)

    #Return the filenames we wrote
    return fileList
Example #3
0
def compile_to_hardware(seqs, fileName, suffix='', alignMode="right"):
    '''
    Compiles 'seqs' to a hardware description and saves it to 'fileName'. Other inputs:
        suffix : string to append to end of fileName (e.g. with fileNames = 'test' and suffix = 'foo' might save to test-APSfoo.h5)
        alignMode : 'left' or 'right' (default 'left')
    '''

    #Add the digitizer trigger to measurements
    PatternUtils.add_digitizer_trigger(seqs, channelLib['digitizerTrig'])

    # Add gating/blanking pulses
    PatternUtils.add_gate_pulses(seqs)

    # Add the slave trigger
    PatternUtils.add_slave_trigger(seqs, channelLib['slaveTrig'])

    # find channel set at top level to account for individual sequence channel variability
    channels = set([])
    for seq in seqs:
        channels |= find_unique_channels(seq)

    #Compile all the pulses/pulseblocks to linklists and waveform libraries
    linkLists, wfLib = compile_sequences(seqs, channels)

    if not validate_linklist_channels(linkLists.keys()):
        print "Compile to hardware failed"
        return        

    # apply gating constraints
    for chan, LL in linkLists.items():
        if isinstance(chan, Channels.LogicalMarkerChannel):
            linkLists[chan] = PatternUtils.apply_gating_constraints(chan.physChan, LL)
    # map logical to physical channels
    awgData = map_logical_to_physical(linkLists, wfLib)
    # construct channel delay map
    chanDelays = channel_delay_map(awgData)

    # for each physical channel need to:
    # 1) delay
    # 2) apply SSB if necessary
    # 3) mixer correct
    for awgName, data in awgData.items():
        for chanName, chanData in data.items():
            if chanData:
                # construct IQkey using existing convention
                IQkey = awgName + '-' + chanName[2:]
                chanObj = channelLib[IQkey]

                # apply channel delay
                PatternUtils.delay(chanData['linkList'], chanDelays[IQkey], chanObj.samplingRate)

                # For quadrature channels, apply SSB and mixer correction
                if isinstance(chanObj, Channels.PhysicalQuadratureChannel):

                    #At this point we finally have the timing of all the pulses so we can apply SSB
                    if hasattr(chanObj, 'SSBFreq') and abs(chanObj.SSBFreq) > 0:
                        PatternUtils.apply_SSB(chanData['linkList'], chanData['wfLib'], chanObj.SSBFreq, chanObj.samplingRate)

                    PatternUtils.correctMixer(chanData['wfLib'], chanObj.correctionT)

                #Remove unused waveforms
                compress_wfLib(chanData['linkList'], chanData['wfLib'])

    #Loop back through to fill empty channels and write to file
    fileList = []
    for awgName, data in awgData.items():
        #If all the channels are empty then do not bother writing the file
        if all([chan is None for chan in data.values()]):
            continue

        # convert to hardware formats
        # create the target folder if it does not exist
        targetFolder = os.path.split(os.path.normpath(os.path.join(config.AWGDir, fileName)))[0]
        if not os.path.exists(targetFolder):
            os.mkdir(targetFolder)
        fullFileName = os.path.normpath(os.path.join(config.AWGDir, fileName + '-' + awgName + suffix + instrumentLib[awgName].seqFileExt))
        write_sequence_file(instrumentLib[awgName], data, fullFileName)

        fileList.append(fullFileName)

    #Return the filenames we wrote
    return fileList
Example #4
0
def compile_to_hardware(seqs, fileName, suffix='', alignMode="right"):
    '''
    Compiles 'seqs' to a hardware description and saves it to 'fileName'. Other inputs:
        suffix : string to append to end of fileName (e.g. with fileNames = 'test' and suffix = 'foo' might save to test-APSfoo.h5)
        alignMode : 'left' or 'right' (default 'left')
    '''

    #Add the digitizer trigger to measurements
    PatternUtils.add_digitizer_trigger(seqs, channelLib['digitizerTrig'])

    # Add gating/blanking pulses
    PatternUtils.add_gate_pulses(seqs)

    # Add the slave trigger
    PatternUtils.add_slave_trigger(seqs, channelLib['slaveTrig'])

    # find channel set at top level to account for individual sequence channel variability
    channels = set([])
    for seq in seqs:
        channels |= find_unique_channels(seq)

    #Compile all the pulses/pulseblocks to linklists and waveform libraries
    linkLists, wfLib = compile_sequences(seqs, channels)

    if not validate_linklist_channels(linkLists.keys()):
        print "Compile to hardware failed"
        return

    # apply gating constraints
    for chan, LL in linkLists.items():
        if isinstance(chan, Channels.LogicalMarkerChannel):
            linkLists[chan] = PatternUtils.apply_gating_constraints(
                chan.physChan, LL)
    # map logical to physical channels
    awgData = map_logical_to_physical(linkLists, wfLib)
    # construct channel delay map
    chanDelays = channel_delay_map(awgData)

    # for each physical channel need to:
    # 1) delay
    # 2) apply SSB if necessary
    # 3) mixer correct
    for awgName, data in awgData.items():
        for chanName, chanData in data.items():
            if chanData:
                # construct IQkey using existing convention
                IQkey = awgName + '-' + chanName[2:]
                chanObj = channelLib[IQkey]

                # apply channel delay
                PatternUtils.delay(chanData['linkList'], chanDelays[IQkey],
                                   chanObj.samplingRate)

                # For quadrature channels, apply SSB and mixer correction
                if isinstance(chanObj, Channels.PhysicalQuadratureChannel):

                    #At this point we finally have the timing of all the pulses so we can apply SSB
                    if hasattr(chanObj,
                               'SSBFreq') and abs(chanObj.SSBFreq) > 0:
                        PatternUtils.apply_SSB(chanData['linkList'],
                                               chanData['wfLib'],
                                               chanObj.SSBFreq,
                                               chanObj.samplingRate)

                    PatternUtils.correctMixer(chanData['wfLib'],
                                              chanObj.correctionT)

                #Remove unused waveforms
                compress_wfLib(chanData['linkList'], chanData['wfLib'])

    #Loop back through to fill empty channels and write to file
    fileList = []
    for awgName, data in awgData.items():
        #If all the channels are empty then do not bother writing the file
        if all([chan is None for chan in data.values()]):
            continue

        # convert to hardware formats
        # create the target folder if it does not exist
        targetFolder = os.path.split(
            os.path.normpath(os.path.join(config.AWGDir, fileName)))[0]
        if not os.path.exists(targetFolder):
            os.mkdir(targetFolder)
        fullFileName = os.path.normpath(
            os.path.join(
                config.AWGDir, fileName + '-' + awgName + suffix +
                instrumentLib[awgName].seqFileExt))
        write_sequence_file(instrumentLib[awgName], data, fullFileName)

        fileList.append(fullFileName)

    #Return the filenames we wrote
    return fileList