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
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
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
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