pyMez.Code.InstrumentControl.Instruments module
The Module Instruments Contains Classes and functions to control instruments; GPIB,RS232 and other visa instruments
#----------------------------------------------------------------------------- # Name: Instruments.py # Purpose: To deal with controlling instruments # Author: Aric Sanders # Created: 2016/06/23 #----------------------------------------------------------------------------- """ The Module Instruments Contains Classes and functions to control instruments; GPIB,RS232 and other visa instruments """ # TODO:Fix Save State, and importing from DataHandlers #------------------------------------------------------------------------------- # Standard Imports-- All in the python standard library import os import re from types import * from ctypes import * import datetime,time import sys #------------------------------------------------------------------------------- # Third Party Imports sys.path.append(os.path.join(os.path.dirname( __file__ ), '..','..')) try: from PIL import Image PIL_AVAILABLE=1 except: print 'PIL is required for some camera operations' PIL_AVAILABLE=0 try: import visa,pyvisa except: print "To control comm and gpib instruments this module requires the package PyVisa" print " Please download it at http://pyvisa.sourceforge.net/ " print " Or add it to the Python Path" pass try: #raise import Code.DataHandlers.XMLModels InstrumentSheet=Code.DataHandlers.XMLModels.InstrumentSheet InstrumentState=Code.DataHandlers.XMLModels.InstrumentState DATA_SHEETS=1 #print dir(pyMez) except: # If the import of DataHandlers Does not work class InstrumentSheet():pass DATA_SHEETS=0 print "Can't Find MySelf" pass try: from Code.Utils.Alias import * METHOD_ALIASES=1 except: METHOD_ALIASES=0 pass try: from Code.Utils.Names import * except: print("Could not load pyMez.Code.Utils.Names") pass try: from Code.DataHandlers.TouchstoneModels import * except: print("Could not load Code.DataHandlers.TouchstoneModels") pass try: import numpy as np except: print("Could not load numpy") pass #------------------------------------------------------------------------------- # Module Constants ACTIVE_COMPONENTS=[PIL_AVAILABLE,DATA_SHEETS,METHOD_ALIASES] INSTRUMENT_TYPES=['GPIB','COMM','OCEAN_OPTICS','MIGHTEX','LABJACK'] INSTRUMENTS_DEFINED=[] #TODO Make PYMEASURE_ROOT be read from the settings folder PYMEASURE_ROOT=os.path.join(os.path.dirname( __file__ ), '..','..') VNA_FREQUENCY_UNIT_MULTIPLIERS={"Hz":1.,"kHz":10.**3,"MHz":10.**6,"GHz":10.**9,"THz":10.**12} #------------------------------------------------------------------------------- # Module Functions #TODO: Move these functions to DataHandlers.Instruments instead def determine_instrument_type_from_string(string): """ Given a string returns the instrument type""" if type(string) in StringTypes: # Start with the easy ones for instrument_type in INSTRUMENT_TYPES: match= re.compile(instrument_type,re.IGNORECASE) if re.search(match,string): return instrument_type # Now read in all the Instrument sheets and look for a match # Returning the Name in the Instrument_Type Tag instrument_folder=os.path.join(PYMEASURE_ROOT,'Instruments') for instrument_sheet in os.listdir(instrument_folder): path=os.path.join(PYMEASURE_ROOT,'Instruments',instrument_sheet) if os.path.isfile(path): f=open(path,'r') text=f.read() if re.search(string,text): tag_match=re.search( '<Instrument_Type>(?P<instrument_type>\w+)</Instrument_Type>', text) try: return tag_match.group('instrument_type') except:pass else: return None def determine_instrument_type(object): """Tries to return an instrument type given an address, name, serial # or class instance""" # attributes that normally have the type hidden in there # should be in the order of likelyhood attritbute_names=['instrument_type','address','serial','Id'] # Check to see if it is a string and then go through the possibilities if type(object) in StringTypes: return determine_instrument_type_from_string(object) # If it is a object or class look around in normal names looking for a string # to process elif type(object)==InstanceType or ClassType: for attribute in attritbute_names: try: if attribute in dir(object): string=eval('object.%s'%attribute) answer=determine_instrument_type_from_string(string) if answer is None:pass else: return answer except AttributeError: try: string=object.__class__.__name__ return determine_instrument_type_from_string(string) except: pass def find_description(identifier,output='path',directory=None): """ Finds an instrument description in pyMez/Instruments given an identifier, outputs a path or the file. Right now this outputs the first sheet that matches the identifier""" if type(identifier) in StringTypes: # Now read in all the Instrument sheets and look for a match if directory is None: instrument_folder=os.path.join(PYMEASURE_ROOT,'Instruments') else: instrument_folder=directory for instrument_sheet in os.listdir(instrument_folder): path=os.path.join(PYMEASURE_ROOT,'Instruments',instrument_sheet) if os.path.isfile(path): f=open(path,'r') text=f.read() if re.search(identifier,text): path_out=re.compile('name|path',re.IGNORECASE) file_contents=re.compile('file|xml|node|contents',re.IGNORECASE) if re.search(path_out,output): return path elif re.search(file_contents,output): return text else: return None def fix_segment_table(segment_table): """Given a list of dictionaries in the form [{"start":start_frequency, "stop":stop_frequency,"number_points":number_points,"step":frequency_step}...] returns a table that is ordered by start frequency and has no overlapping points""" segment_table = sorted(segment_table, key=lambda x: x["start"]) i = 0 while (i + 1 < len(segment_table)): if segment_table[i]["stop"] == segment_table[i + 1]["start"]: segment_table[i + 1]["start"] = segment_table[i + 1]["start"] + segment_table[i + 1]["step"] segment_table[i + 1]["number_points"] -= 1 i += 1 return segment_table #------------------------------------------------------------------------------- # Class Definitions class VisaInstrumentError(Exception): def __init__(self,*args): Exception.__init__(self,*args) class FakeInstrument(InstrumentSheet): """ General Class to communicate with COMM and GPIB instruments This is a blend of the pyvisa resource and an xml description. """ def __init__(self, resource_name=None, **options): """ Intializes the VisaInstrument Class""" defaults = {"state_directory": os.getcwd(), "instrument_description_directory": os.path.join(PYMEASURE_ROOT, 'Instruments')} self.options = {} for key, value in defaults.iteritems(): self.options[key] = value for key, value in options.iteritems(): self.options[key] = value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path = find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self, self.info_path, **self.options) self.info_found = True self.DEFAULT_STATE_QUERY_DICTIONARY = self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY = {} self.info_found = False self.instrument_address = resource_name self.name = resource_name.replace(":", "_") pass else: self.info_found = False self.DEFAULT_STATE_QUERY_DICTIONARY = {} self.instrument_address = resource_name # Create a description for state saving if self.info_found: self.description = {'Instrument_Description': self.path} else: self.description = {'Instrument_Description': self.instrument_address} self.state_buffer = [] self.STATE_BUFFER_MAX_LENGTH = 10 self.write_buffer=[] self.read_buffer=[] self.history=[] #self.resource_manager = visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read #self.resource = self.resource_manager.open_resource(self.instrument_address) self.current_state = self.get_state() def write(self, command): "Writes command to instrument" now=datetime.datetime.utcnow().isoformat() self.write_buffer.append(command) self.history.append({"Timestamp":now,"Action":"self.write", "Argument":command,"Response":None}) def read(self): "Reads from the instrument" now=datetime.datetime.utcnow().isoformat() out="Buffer Read at {0}".format(now) self.read_buffer.append(out) time.sleep(.001) self.history.append({"Timestamp":now,"Action":"self.read", "Argument":None,"Response":out}) return out def query(self, command): "Writes command and then reads a response" self.write(command) return self.read() def ask(self, command): "Writes command and then reads a response" return self.query(command) def set_state(self, state_dictionary=None, state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer) + 1 < self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1, self.get_state()) for state_command, value in state_dictionary.iteritems(): self.write(state_command + ' ' + str(value)) self.current_state = self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table = sorted(state_table, key=lambda x: x["Index"]) if len(self.state_buffer) + 1 < self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1, self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command = state_row["Set"] value = state_row["Value"] self.write(state_command + ' ' + str(value)) def get_state(self, state_query_dictionary=None, state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary) == 0: state_query_dictionary = self.DEFAULT_STATE_QUERY_DICTIONARY state = dict([(state_command, self.query(str(query)).replace("\n", "")) for state_command, query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table = sorted(state_query_table, key=lambda x: int(x["Index"])) state = [] for state_row in state_query_table: set = state_row["Set"] query = state_row["Query"] index = state_row["Index"] state.append({"Set": set, "Value": self.query(query).replace("\n", ""), "Index": index}) return state else: state = [] for state_row in state_query_table: set = state_row["Set"] query = state_row["Query"] state.append({"Set": set, "Value": self.query(query).replace("\n", "")}) return state def update_current_state(self): self.current_state = self.get_state() def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state = self.get_state() self.save_state(None, state_dictionary=self.current_state) def save_state(self, state_path=None, state_dictionary=None, state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path = auto_name(specific_descriptor=self.name, general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state = InstrumentState(None, **{"state_dictionary": state_dictionary, "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state = InstrumentState(None, **{"state_table": state_table, "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) else: new_state = InstrumentState(None, **{"state_dictionary": self.get_state(), "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise # pass new_state.save(state_path) return state_path def load_state(self, file_path): """Loads a state from a file.""" # TODO put a UDT to state_table state_model = InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary()) def close(self): """Closes the VISA session""" print("Fake Instrument has been closed") class VisaInstrument(InstrumentSheet): """ General Class to communicate with COMM and GPIB instruments This is a blend of the pyvisa resource and an xml description. """ def __init__(self,resource_name=None,**options): """ Initializes the VisaInstrument Class""" defaults={"state_directory":os.getcwd(), "instrument_description_directory":os.path.join(PYMEASURE_ROOT,'Instruments')} self.options={} for key,value in defaults.iteritems(): self.options[key]=value for key,value in options.iteritems(): self.options[key]=value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path=find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self,self.info_path,**self.options) self.info_found=True self.DEFAULT_STATE_QUERY_DICTIONARY=self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY={} self.info_found=False self.instrument_address=resource_name self.name=resource_name.replace(":","_") pass else: self.info_found=False self.DEFAULT_STATE_QUERY_DICTIONARY={} self.instrument_address=resource_name # Create a description for state saving if self.info_found: self.description={'Instrument_Description':self.path} else: self.description={'Instrument_Description':self.instrument_address} self.state_buffer=[] self.STATE_BUFFER_MAX_LENGTH=10 self.resource_manager=visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read self.resource=self.resource_manager.open_resource(self.instrument_address) self.current_state=self.get_state() def write(self,command): "Writes command to instrument" return self.resource.write(command) def read(self): "Reads from the instrument" return self.resource.read() def query(self,command): "Writes command and then reads a response" return self.resource.query(command) def ask(self,command): "Writes command and then reads a response" return self.resource.query(command) def set_state(self,state_dictionary=None,state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) for state_command,value in state_dictionary.iteritems(): self.write(state_command+' '+str(value)) self.current_state=self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table=sorted(state_table,key=lambda x:x["Index"]) if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command=state_row["Set"] value=state_row["Value"] self.write(state_command+' '+str(value)) def get_state(self,state_query_dictionary=None,state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary)==0 : state_query_dictionary=self.DEFAULT_STATE_QUERY_DICTIONARY state=dict([(state_command,self.query(str(query)).replace("\n","")) for state_command,query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table=sorted(state_query_table,key=lambda x:int(x["Index"])) state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] index=state_row["Index"] state.append({"Set":set,"Value":self.query(query).replace("\n",""),"Index":index}) return state else: state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] state.append({"Set":set,"Value":self.query(query).replace("\n","")}) return state def update_current_state(self): self.current_state=self.get_state() def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state=self.get_state() self.save_state(None,state_dictionary=self.current_state) def save_state(self,state_path=None,state_dictionary=None,state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path=auto_name(specific_descriptor=self.name,general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state=InstrumentState(None,**{"state_dictionary":state_dictionary, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state=InstrumentState(None,**{"state_table":state_table, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) else: new_state=InstrumentState(None,**{"state_dictionary":self.get_state(), "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise #pass new_state.save(state_path) return state_path def load_state(self,file_path): """Loads a state from a file.""" #TODO put a UDT to state_table state_model=InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary()) def close(self): """Closes the VISA session""" self.resource_manager.close() class VNA(VisaInstrument): """Control class for a linear VNA. The .measure_sparameters ans .measure_switch_terms return a S2PV1 class that can be saved, printed or have a simple plot using show(). The attribute frequency_list stores the frequency points as Hz.""" def __init__(self, resource_name=None, **options): """Initializes the E8631A control class""" defaults = {"state_directory": os.getcwd(), "frequency_units": "Hz"} self.options = {} for key, value in defaults.iteritems(): self.options[key] = value for key, value in options.iteritems(): self.options[key] = value VisaInstrument.__init__(self, resource_name, **self.options) self.power = self.get_power() self.IFBW = self.get_IFBW() self.frequency_units = self.options["frequency_units"] self.frequency_table = [] # this should be if SENS:SWE:TYPE? is LIN or LOG self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] def initialize(self, **options): """Intializes the system""" defaults = {"reset": True} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options: initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'S11',S11") self.write("DISPlay:WINDow1:TRACe1:FEED 'S11'") self.write("CALCulate:PARameter:DEFine 'S12',S12") self.write("DISPlay:WINDow1:TRACe2:FEED 'S12'") self.write("CALCulate:PARameter:DEFine 'S21',S21") self.write("DISPlay:WINDow1:TRACe3:FEED 'S21'") self.write("CALCulate:PARameter:DEFine 'S22',S22") self.write("DISPlay:WINDow1:TRACe4:FEED 'S22'") self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] def set_power(self, power): """Sets the power of the Instrument in dbm""" self.write('SOUR:POW {0}'.format(power)) def get_power(self): "Returns the power of the instrument in dbm" return self.query('SOUR:POW?') def get_sweep_type(self): "Returns the current sweep type. It can be LIN, LOG, or SEG" return self.query("SENS:SWE:TYPE?") def set_IFBW(self, ifbw): """Sets the IF Bandwidth of the instrument in Hz""" self.write('SENS:BAND {0}'.format(ifbw)) self.write('SENS:BAND:TRAC OFF') self.IFBW = ifbw def get_IFBW(self): """Returns the IFBW of the instrument in Hz""" ifbw = float(self.query('SENS:BAND?')) self.IFBW = ifbw return ifbw def set_frequency_units(self, frequency_units="Hz"): """Sets the frequency units of the class, all values are still written to the VNA as Hz and the attrbiute frequncy_list is in Hz, however all commands that deal with sweeps and measurements will be in units""" for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): self.frequency_units = unit def add_segment(self, start, stop=None, number_points=None, step=None, frequency_units="Hz"): """Sets the VNA to a segment mode and appends a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz. """ # first handle the start only case if stop is None and number_points is None: stop = start number_points = 1 # fix the frequency units for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): start = start * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] stop = stop * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] if step: step = step * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] self.frequency_units = unit # handle creating step and number of points if number_points is None and not step is None: number_points = round((stop - start) / step) + 1 elif number_points is None: number_points = 201 # I don't like the default for n_points this far down in the code step = (stop - start) / (number_points - 1) else: step = (stop - start) / (number_points - 1) # append the new segment to self.frequency_table and fix any strangeness self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table[:]) # update the frequency_list frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list # now we write the segment to the instrument if not re.search("SEG", self.get_sweep_type(), re.IGNORECASE): self.write('SENS:SWE:TYPE SEGM') # now get the number of segments and add or delete the right amount to make it line up with self.frequency_table # This routine is broken number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) print("{0} is {1}".format("number_segments", number_segments)) if len(self.frequency_table) < number_segments: difference = number_segments - len(self.frequency_table) max_segment = number_segments while (difference != 0): self.write("SENS:SEGM{0}:DEL".format(max_segment)) max_segment -= 1 difference -= 1 elif len(self.frequency_table) > number_segments: difference = len(self.frequency_table) - number_segments max_segment = number_segments + 1 print("{0} is {1}".format("difference", difference)) while (difference != 0): self.write("SENS:SEGM{0}:ADD".format(max_segment)) max_segment += 1 difference -= 1 print("{0} is {1}".format("difference", difference)) else: pass for row_index, row in enumerate(self.frequency_table[:]): [start, stop, number_points] = [row["start"], row["stop"], row["number_points"]] # SENSe<cnum>:SEGMent<snum>:SWEep:POINts <num> self.write("SENS:SEGM{0}:FREQ:START {1}".format(row_index + 1, start)) self.write("SENS:SEGM{0}:FREQ:STOP {1}".format(row_index + 1, stop)) self.write("SENS:SEGM{0}:SWE:POIN {1}".format(row_index + 1, number_points)) self.write("SENS:SEGM{0}:STAT ON".format(row_index + 1)) def write_frequency_table(self, frequency_table=None): """Writes frequency_table to the instrument, the frequency table should be in the form [{start:,stop:,number_points:}..] or None""" if frequency_table is None: frequency_table = self.frequency_table[:] for row_index, row in enumerate(frequency_table[:]): [start, stop, number_points] = [row["start"], row["stop"], row["number_points"]] # SENSe<cnum>:SEGMent<snum>:SWEep:POINts <num> self.write("SENS:SEGM{0}:FREQ:START {1}".format(row_index + 1, start)) self.write("SENS:SEGM{0}:FREQ:STOP {1}".format(row_index + 1, stop)) self.write("SENS:SEGM{0}:SWE:POIN {1}".format(row_index + 1, number_points)) self.write("SENS:SEGM{0}:STAT ON".format(row_index + 1)) def set_frequency(self, start, stop=None, number_points=None, step=None, type='LIN', frequency_units="Hz"): """Sets the VNA to a linear mode and creates a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz. """ if stop is None and number_points is None: stop = start number_points = 1 for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): start = start * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] stop = stop * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] if step: step = step * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] self.frequency_units = unit if number_points is None and not step is None: number_points = round((stop - start) / step) + 1 if re.search("LIN", type, re.IGNORECASE): self.write('SENS:SWE:TYPE LIN') self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LOG", type, re.IGNORECASE): self.write('SENS:SWE:TYPE LOG') logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) else: self.write('SENS:SWE:TYPE LIN') self.frequency_list = map(lambda x: round(x, ndigits=3), np.linspace(start, stop, number_points).tolist()) self.write("SENS:FREQ:START {0}".format(start)) self.write("SENS:FREQ:STOP {0}".format(stop)) self.write("SENS:SWE:POIN {0}".format(number_points)) def get_frequency(self): "Returns the frequency in python list format" return self.frequency_list def is_busy(self): """Checks if the instrument is currently doing something and returns a boolean value""" opc = bool(self.resource.query("*OPC?")) return not opc def clear_window(self, window=1): """Clears the window of traces. Does not delete the variables""" string_response = self.query("DISPlay:WINDow{0}:CATalog?".format(window)) traces = string_response.split(",") for trace in traces: self.write("DISP:WIND{0}:TRAC{1}:DEL".format(window, trace)) def measure_switch_terms(self, **options): """Measures switch terms and returns a s2p table in forward and reverse format""" defaults = {"view_trace": True} self.measure_switch_term_options = {} for key, value in defaults.iteritems(): self.measure_switch_term_options[key] = value for key, value in options: self.measure_switch_term_options[key] = value # this resets the traces to be based on swith terms # Set VS to be remotely triggered by GPIB self.write("SENS:HOLD:FUNC HOLD") self.write("TRIG:REM:TYP CHAN") # Set the Channel to have 2 Traces self.write("CALC1:PAR:COUN 2") # Trace 1 This is port 2 or Forward Switch Terms self.write("CALC1:PAR:DEF 'FWD',R2,1") # note this command is different for vector star A2,B2 if self.measure_switch_term_options["view_trace"]: self.write("DISPlay:WINDow1:TRACe5:FEED 'FWD'") # Trace 2 This is port 1 or Reverse Switch Terms self.write("CALC1:PAR:DEF 'REV',R1,2") if self.measure_switch_term_options["view_trace"]: self.write("DISPlay:WINDow1:TRACe6:FEED 'REV'") # Select Channel self.write("CALC1:SEL;") self.write("ABORT;TRIG:SING;") # Sleep for the duration of the scan time.sleep(len(self.frequency_list) * 2.5 / float(self.IFBW)) # wait for other functions to be completed # while self.is_busy(): # time.sleep(.01) # Set the read format self.write("FORM:ASC,0") # Read in the data self.write("CALC:PAR:SEL FWD;") foward_switch_string = self.query("CALC:DATA? SDATA") while self.is_busy(): time.sleep(.01) self.write("CALC:PAR:SEL REV;") reverse_switch_string = self.query("CALC:DATA? SDATA") # Now parse the string foward_switch_list = foward_switch_string.replace("\n", "").split(",") reverse_switch_list = reverse_switch_string.replace("\n", "").split(",") real_foward = foward_switch_list[0::2] imaginary_forward = foward_switch_list[1::2] real_reverse = reverse_switch_list[0::2] imaginary_reverse = reverse_switch_list[1::2] switch_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency, real_foward[index], imaginary_forward[index], real_reverse[index], imaginary_reverse[index], 0, 0, 0, 0] new_row = map(lambda x: float(x), new_row) switch_data.append(new_row) option_line = "# Hz S RI R 50" # add some options here about auto saving # do we want comment options? s2p = S2PV1(None, option_line=option_line, data=switch_data) s2p.change_frequency_units(self.frequency_units) return s2p def measure_sparameters(self, **options): """Triggers a single sparameter measurement for all 4 parameters and returns a SP2V1 object""" defaults = {"trigger": "single"} self.measure_sparameter_options = {} for key, value in defaults.iteritems(): self.measure_sparameter_options[key] = value for key, value in options: self.measure_sparameter_options[key] = value if self.measure_sparameter_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the Sparameter lists self.write('CALC:PAR:SEL S11') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s11_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S12') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s12_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S21') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s21_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S22') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s22_string = self.query('CALC:DATA? SDATA') # String Parsing s11_list = s11_string.replace("\n", "").split(",") s12_list = s12_string.replace("\n", "").split(",") s21_list = s21_string.replace("\n", "").split(",") s22_list = s22_string.replace("\n", "").split(",") # Construct a list of lists that is data in RI format reS11 = s11_list[0::2] imS11 = s11_list[1::2] reS12 = s12_list[0::2] imS12 = s12_list[1::2] reS21 = s21_list[0::2] imS21 = s21_list[1::2] reS22 = s22_list[0::2] imS22 = s22_list[1::2] sparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency, reS11[index], imS11[index], reS21[index], imS21[index], reS12[index], imS12[index], reS22[index], imS22[index]] new_row = map(lambda x: float(x), new_row) sparameter_data.append(new_row) option_line = "# Hz S RI R 50" # add some options here about auto saving # do we want comment options? s2p = S2PV1(None, option_line=option_line, data=sparameter_data) s2p.change_frequency_units(self.frequency_units) return s2p def initialize_w2p(self,**options): """Initializes the system for w2p acquisition""" defaults = {"reset": True, "port1": 1,"port2":2, "b_name_list": ["A", "B", "C", "D"]} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") b1_name = initialize_options["b_name_list"][initialize_options["port1"] - 1] b2_name= initialize_options["b_name_list"][initialize_options["port2"] - 1] # Initialize Port 1 traces A1_D1,B1_D1,B2_D1 self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'A{0}_D{0}',R{0},{0}".format(initialize_options["port1"])) self.write("DISPlay:WINDow1:TRACe1:FEED 'A{0}_D{0}'".format(initialize_options["port1"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{0}',{1},{0}".format(initialize_options["port1"],b1_name)) self.write("DISPlay:WINDow1:TRACe2:FEED 'B{0}_D{0}'".format(initialize_options["port1"])) self.write("CALCulate:PARameter:DEFine 'A{1}_D{0}',R{1},{0}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe3:FEED 'A{1}_D{0}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{1}_D{0}',{2},{0}".format(initialize_options["port1"], initialize_options["port2"], b2_name)) self.write("DISPlay:WINDow1:TRACe4:FEED 'B{1}_D{0}'".format(initialize_options["port1"], initialize_options["port2"])) # Initialize Port 2 Traces A1_D2,B1_D2, self.write("CALCulate:PARameter:DEFine 'A{0}_D{1}',R{0},{1}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe5:FEED 'A{0}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{1}',{2},{1}".format(initialize_options["port1"], initialize_options["port2"], b1_name)) self.write("DISPlay:WINDow1:TRACe6:FEED 'B{0}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'A{1}_D{1}',R{1},{1}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe7:FEED 'A{1}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{1}_D{1}',{2},{1}".format(initialize_options["port1"], initialize_options["port2"], b2_name)) self.write("DISPlay:WINDow1:TRACe8:FEED 'B{1}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.sweep_type = self.get_sweep_type() self.frequency_list=self.get_frequency_list() def initialize_w1p(self, **options): """Initializes the system for w1p acquisition, default works for ZVA""" defaults = {"reset": True, "port": 1, "b_name_list": ["A", "B", "C", "D"],"source_port":1} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") b_name = initialize_options["b_name_list"][initialize_options["port"] - 1] self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'A{0}_D{0}',R{0}".format(initialize_options["port"])) self.write("DISPlay:WINDow1:TRACe1:FEED 'A{0}_D{0}'".format(initialize_options["port"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{0}',{1}".format(initialize_options["port"], b_name)) self.write("DISPlay:WINDow1:TRACe2:FEED 'B{0}_D{0}'".format(initialize_options["port"])) self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] def get_frequency_list(self): "Returns the frequency list as read from the VNA" self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] return self.frequency_list[:] def measure_w1p(self, **options): """Triggers a single w1p measurement for a specified port and returns a w1p object.""" defaults = {"trigger": "single", "port": 1, "b_name_list": ["A", "B", "C", "D"], "w1p_options": None} self.measure_w1p_options = {} for key, value in defaults.iteritems(): self.measure_w1p_options[key] = value for key, value in options.iteritems(): self.measure_w1p_options[key] = value if self.measure_w1p_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the A and Blists self.write('CALC:PAR:SEL A{0}_D{0}'.format(self.measure_w1p_options["port"])) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) a_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL B{0}_D{0}'.format(self.measure_w1p_options["port"])) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) b_string = self.query('CALC:DATA? SDATA') # String Parsing a_list = a_string.replace("\n", "").split(",") b_list = b_string.replace("\n", "").split(",") # Construct a list of lists that is data in RI format re_a = a_list[0::2] im_a = a_list[1::2] re_b = b_list[0::2] im_b = b_list[1::2] wparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency / 10. ** 9, re_a[index], im_a[index], re_b[index], im_b[index]] new_row = map(lambda x: float(x), new_row) wparameter_data.append(new_row) column_names = ["Frequency", "reA1_D1", "imA1_D1", "reB1_D1", "imB1_D1"] # add some options here about auto saving # do we want comment options? options = {"column_names_begin_token": "!", "data_delimiter": " ", "column_names": column_names, "data": wparameter_data, "specific_descriptor": "Wave_Parameters", "general_descriptor": "One_Port", "extension": "w1p"} if self.measure_w1p_options["w1p_options"]: for key,value in self.measure_w1p_options["w1p_options"].iteritems(): options[key]=value w1p = AsciiDataTable(None, **options) return w1p def measure_w2p(self, **options): """Triggers a single w2p measurement for a specified port and returns a w2p object.""" defaults = {"trigger": "single", "port1": 1,"port2":2, "b_name_list": ["A", "B", "C", "D"], "w2p_options": None} self.measure_w2p_options = {} for key, value in defaults.iteritems(): self.measure_w2p_options[key] = value for key, value in options.iteritems(): self.measure_w2p_options[key] = value if self.measure_w2p_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the A and B lists drive port 1 # Note this could be a loop over the list = [a1_d1,b1_d1,b2_d1...,b2_d2] waveparameter_names=[] for drive_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for detect_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for receiver in ["A","B"]: waveparameter_names.append("{0}{1}_D{2}".format(receiver,detect_port,drive_port)) # now get data for all of them all_wave_raw_string=[] for waveparameter in waveparameter_names: self.write('CALC:PAR:SEL {0}'.format(waveparameter)) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) all_wave_raw_string .append(self.query('CALC:DATA? SDATA')) # String Parsing all_wave_list=map(lambda x:x.replace("\n","").split(","),all_wave_raw_string) # Construct a list of lists that is data in RI format re_all_wave_list = [a_list[0::2] for a_list in all_wave_list] im_all_wave_list = [a_list[1::2] for a_list in all_wave_list] wparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): re_row=[re[index] for re in re_all_wave_list ] im_row=[im[index] for im in im_all_wave_list] wave_row=[] for index,value in enumerate(re_row): wave_row.append(value) wave_row.append(im_row[index]) new_row = [frequency / 10. ** 9]+wave_row new_row = map(lambda x: float(x), new_row) wparameter_data.append(new_row) waveparameter_column_names=[] for drive_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for detect_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for receiver in ["A","B"]: for complex_type in ["re","im"]: waveparameter_column_names.append("{3}{0}{1}_D{2}".format(receiver, detect_port, drive_port, complex_type)) column_names = ["Frequency"]+waveparameter_column_names # add some options here about auto saving # do we want comment options? options = {"column_names_begin_token": "!", "data_delimiter": " ", "column_names": column_names, "data": wparameter_data, "specific_descriptor": "Wave_Parameters", "general_descriptor": "Two_Port", "extension": "w2p"} if self.measure_w2p_options["w2p_options"]: for key,value in self.measure_w2p_options["w2p_options"].iteritems(): options[key]=value w2p = AsciiDataTable(None, **options) return w2p class NRPPowerMeter(VisaInstrument): """Controls RS power meters""" def initialize(self): """Initializes the power meter to a state with W units, 10ms aperture and Avgerage power readings""" self.write("*RST") self.write("UNIT:POW W") self.write("SENS:FUNC POW:AVG") self.write("SENS:APER 10 MS") self.write("INIT") def get_reading(self): """Intializes and fetches a reading""" self.write("INIT") return float(self.query("FETCh?").replace("\n","")) def set_units(self,unit): """Sets the power meters units, aceptable units are W or adBM""" # Todo put an input checker on this to only allow desired commands self.write("UNIT:POW {0}".format(unit)) class HighSpeedOscope(VisaInstrument): """Control Class for high speed oscilloscopes. Based on code from Diogo """ def initialize(self, **options): """Initializes the oscilloscope for data collection""" defaults = {"reset": True} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value pass def measure_waves(self, **options): """Returns data for a measurement in an AsciiDataTable""" defaults = {"number_frames": 1, "number_points": self.get_number_points(), "timebase_scale": self.get_timebase_scale(), "channels": [1, 2, 3, 4], "initial_time_offset": self.get_time_position(), "timeout_measurement": 10000, "save_data": False, "data_format": "dat", "directory": os.getcwd(), "specific_descriptor": "Scope", "general_descriptor": "Measurement", "add_header": False, "output_table_options": {"data_delimiter": " ", "treat_header_as_comment": True} } self.measure_options = {} for key, value in defaults.iteritems(): self.measure_options[key] = value for key, value in options.iteritems(): self.measure_options[key] = value self.set_number_points(self.measure_options["number_points"]) channel_string_list = ["CHAN1", "CHAN2", "CHAN3", "CHAN4"] # begin by setting timeout to timeout_measurement timeout = self.resource.timeout self.resource.timeout = self.measure_options["timeout_measurement"] # now calculate timestep self.measure_options["timestep"] = self.measure_options["timebase_scale"] / self.measure_options[ "number_points"] time_step = self.measure_options["timestep"] # now configure the scope for data transfer # define the way the data is transmitted from the instrument to the PC self.write(':WAV:FORM ASCII') # Word -> 16bit signed integer #self.write(':WAV:FORM WORD') # little-endian #self.write(':WAV:BYT LSBF') number_rows = self.measure_options["number_points"] * self.measure_options["number_frames"] # this is the way diogo did it # number of points number_points = self.measure_options["number_points"] frames_data = [] for frame_index in range(self.measure_options["number_frames"]): new_frame = [] # calculate time position for this frame time_position = frame_index * self.measure_options["timebase_scale"] + self.measure_options[ "initial_time_offset"] # define postion to start the acquisition self.write(':TIM:POS {0}ns'.format(time_position)) # acquire channels desired channel_string = "" for channel_index, channel in enumerate(self.measure_options["channels"]): if channel_index == len(self.measure_options["channels"]) - 1: channel_string = channel_string + "{0}".format(channel_string_list[channel - 1]) else: channel_string = channel_string + "{0},".format(channel_string_list[channel - 1]) channel_command = ":DIG {0}".format(channel_string) self.write(channel_command) # trigger reading and wait self.write("*OPC?") # get data from the necessary channels for channel_read_index, channel_read in enumerate(self.measure_options["channels"]): # get data for channel 1 self.write(':WAV:SOUR CHAN{0}'.format(channel_read)) # get data #data_column = self.resource.query_binary_values(':WAV:DATA?', datatype='h') data_column = self.resource.query(':WAV:DATA?') new_frame.append(data_column) # print("{0} is {1}".format("data_column",data_column)) frames_data.append(new_frame) # reshape measurement data measurement_data = [range(len(frames_data[0])) for x in range(number_points * len(frames_data))] # print(len(measurement_data)) # print(len(measurement_data[0])) # print("{0} is{1}".format("len(frames_data)",len(frames_data))) # print("{0} is{1}".format("len(frames_data[0])",len(frames_data[0]))) # print("{0} is{1}".format("len(frames_data[0][0])",len(frames_data[0][0]))) for frame_index, frame in enumerate(frames_data): for column_index, column in enumerate(frame): for row_index, row in enumerate(column): number_rows = len(column) # print("{0} is {1}".format("([row_index+frame_index*number_rows],[column_index],[frame_index])", # ([row_index + frame_index * number_rows], [column_index], [frame_index]))) measurement_data[row_index + frame_index * number_rows][column_index] = \ frames_data[frame_index][column_index][row_index] # reset timeout self.resource.timeout = timeout data_out = [] time_start = self.measure_options["initial_time_offset"] for row_index, data_row in enumerate(measurement_data): new_row = [time_start + row_index * time_step] + data_row data_out.append(new_row) if self.measure_options["add_header"]: header = [] for key, value in self.measure_options.iteritems(): header.append("{0} = {1}".format(key, value)) else: header = None column_names = ["Time"] for channel in self.measure_options["channels"]: column_names.append(channel_string_list[channel - 1]) table_options = {"data": data_out, "header": header, "specific_descriptor": self.measure_options["specific_descriptor"], "general_descriptor": self.measure_options["general_descriptor"], "extension": "dat", "directory": self.measure_options["directory"], "column_names": column_names} for key, value in self.measure_options["output_table_options"].iteritems(): table_options[key] = value output_table = AsciiDataTable(None, **table_options) if self.measure_options["save_data"]: data_save_path = auto_name(specific_descriptor=self.measure_options["specific_descriptor"], general_descriptor=self.measure_options["general_descriptor"], directory=self.measure_options["directory"], extension='dat' , padding=3) output_table.path = data_save_path output_table.save() return output_table def get_error_state(self): """Returns the error state of the oscope""" state = self.query(':SYSTEM:ERROR? STRING') self.error_state = state return state def set_number_points(self, number_points=16384): """Sets the number of points for the acquisition""" self.write(':ACQ:POINTS {0}'.format(number_points)) def get_number_points(self): """Returns the number of points in the waveform""" number_points = int(self.query(':ACQ:POINTS?')) return number_points def set_time_position(self, time=50): """Sets the time in ns to start the acquisition""" self.write(':TIM:POS {0}ns'.format(time)) def get_time_position(self): """Returns the time position in ns""" position = float(self.query(":TIM:POS?")) return position * 10 ** 9 def set_timebase_scale(self, time_scale=40.96): """Sets the timebase scale in ns""" self.write(':TIM:SCAL {0}ns'.format(time_scale)) def get_timebase_scale(self): """Returns the timebase scale in ns""" time_scale = float(self.query(':TIM:SCAL?')) return time_scale * 10 ** 9 def set_trigger_source(self, source="FPAN"): """Sets the tigger source, 'FPAN' Frontpanel or 'FRUN' freerun""" self.write(':TRIG:SOUR {0}'.format(source)) def get_trigger_source(self): """Returns the trigger source FPAN for FrontPanel or FRUN for free run""" source = self.query(':TRIG:SOUR?') def set_trigger_level(self, level=10): """Sets the trigger level in mv""" self.write(':TRIG:LEV {0}m'.format(level)) def get_trigger_level(self): """Returns the trigger level""" level = self.query(':TRIG:LEV?') def set_channel_scale(self, scale=10, channel=1): """Sets the scale in mv of channel. Default is 10mv/division on channel 1""" self.write(':CHAN{0}:SCAL {1}m'.format(channel, scale)) def get_channel_scale(self, channel=1): "Returns the scale for a specified channel, the default is channel 1" scale = self.query(':CHAN{0}:SCAL?'.format(channel)) return scale def set_channel_bandwidth(self, bandwidth="LOW", channel=1): """Sets the specified channel's bandwith to LOW, MED or HIGH, default is to set channel 1 to LOW""" self.write(':CHAN{0}:BAND {1}'.format(channel, bandwidth)) def get_channel_bandwidth(self, channel=1): """Returns the selected channels bandwidth""" bandwidth = self.query(':CHAN{0}:BAND?'.format(channel)) return bandwidth def set_trigger_slope(self, slope="POS"): """Sets the trigger slope on the oscope choose from POS or NEG""" self.write(':TRIG:SLOP {0}'.format(slope)) def get_trigger_slope(self): """Returns the trigger slope either POS or NEG""" slope = self.query(":TRIG:SLOP?") return slope #------------------------------------------------------------------------------- # Module Scripts def test_determine_instrument_type(): print 'Type is %s'%determine_instrument_type('GPIB::22') print 'Type is %s'%determine_instrument_type('COMM::1') print 'Type is %s'%determine_instrument_type('CoMm::1') print 'Type is %s'%determine_instrument_type('SRS830') print 'Type is %s'%determine_instrument_type('36111') class blank():pass new=blank() print type(new) print 'Type is %s'%determine_instrument_type(new) new.instrument_type='Ocean_Optics' print new.instrument_type print 'Type is %s'%determine_instrument_type(new) TF=(type(new)==InstanceType or ClassType) print TF print dir(new) print 'instrument_type' in dir(new) def test_find_description(): """Tests the function find description""" print "The path of the description of %s is %s"%('Lockin2',find_description('Lockin2')) print "The File Contents are:" print find_description('Lockin2','file') def test_VisaInstrument(address="GPIB::21"): """ Simple test of the VisaInstrument class""" instrument=VisaInstrument(address) #print instrument.ask('*IDN?') print dir(instrument) print instrument.idn print instrument.DEFAULT_STATE_QUERY_DICTIONARY print instrument.current_state print 'Writing 0 volts to AUX4' instrument.set_state(**{'AUXV 4,':0}) print instrument.current_state print instrument.state_buffer print instrument.commands #------------------------------------------------------------------------------- # Module Runner if __name__ == '__main__': #test_IV() #test_find_description() test_VisaInstrument() #user_terminate=raw_input("Please Press Any key To Finish:")
Functions
def determine_instrument_type(
object)
Tries to return an instrument type given an address, name, serial # or class instance
def determine_instrument_type(object): """Tries to return an instrument type given an address, name, serial # or class instance""" # attributes that normally have the type hidden in there # should be in the order of likelyhood attritbute_names=['instrument_type','address','serial','Id'] # Check to see if it is a string and then go through the possibilities if type(object) in StringTypes: return determine_instrument_type_from_string(object) # If it is a object or class look around in normal names looking for a string # to process elif type(object)==InstanceType or ClassType: for attribute in attritbute_names: try: if attribute in dir(object): string=eval('object.%s'%attribute) answer=determine_instrument_type_from_string(string) if answer is None:pass else: return answer except AttributeError: try: string=object.__class__.__name__ return determine_instrument_type_from_string(string) except: pass
def determine_instrument_type_from_string(
string)
Given a string returns the instrument type
def determine_instrument_type_from_string(string): """ Given a string returns the instrument type""" if type(string) in StringTypes: # Start with the easy ones for instrument_type in INSTRUMENT_TYPES: match= re.compile(instrument_type,re.IGNORECASE) if re.search(match,string): return instrument_type # Now read in all the Instrument sheets and look for a match # Returning the Name in the Instrument_Type Tag instrument_folder=os.path.join(PYMEASURE_ROOT,'Instruments') for instrument_sheet in os.listdir(instrument_folder): path=os.path.join(PYMEASURE_ROOT,'Instruments',instrument_sheet) if os.path.isfile(path): f=open(path,'r') text=f.read() if re.search(string,text): tag_match=re.search( '<Instrument_Type>(?P<instrument_type>\w+)</Instrument_Type>', text) try: return tag_match.group('instrument_type') except:pass else: return None
def find_description(
identifier, output='path', directory=None)
Finds an instrument description in pyMez/Instruments given an identifier, outputs a path or the file. Right now this outputs the first sheet that matches the identifier
def find_description(identifier,output='path',directory=None): """ Finds an instrument description in pyMez/Instruments given an identifier, outputs a path or the file. Right now this outputs the first sheet that matches the identifier""" if type(identifier) in StringTypes: # Now read in all the Instrument sheets and look for a match if directory is None: instrument_folder=os.path.join(PYMEASURE_ROOT,'Instruments') else: instrument_folder=directory for instrument_sheet in os.listdir(instrument_folder): path=os.path.join(PYMEASURE_ROOT,'Instruments',instrument_sheet) if os.path.isfile(path): f=open(path,'r') text=f.read() if re.search(identifier,text): path_out=re.compile('name|path',re.IGNORECASE) file_contents=re.compile('file|xml|node|contents',re.IGNORECASE) if re.search(path_out,output): return path elif re.search(file_contents,output): return text else: return None
def fix_segment_table(
segment_table)
Given a list of dictionaries in the form [{"start":start_frequency, "stop":stop_frequency,"number_points":number_points,"step":frequency_step}...] returns a table that is ordered by start frequency and has no overlapping points
def fix_segment_table(segment_table): """Given a list of dictionaries in the form [{"start":start_frequency, "stop":stop_frequency,"number_points":number_points,"step":frequency_step}...] returns a table that is ordered by start frequency and has no overlapping points""" segment_table = sorted(segment_table, key=lambda x: x["start"]) i = 0 while (i + 1 < len(segment_table)): if segment_table[i]["stop"] == segment_table[i + 1]["start"]: segment_table[i + 1]["start"] = segment_table[i + 1]["start"] + segment_table[i + 1]["step"] segment_table[i + 1]["number_points"] -= 1 i += 1 return segment_table
def test_VisaInstrument(
address='GPIB::21')
Simple test of the VisaInstrument class
def test_VisaInstrument(address="GPIB::21"): """ Simple test of the VisaInstrument class""" instrument=VisaInstrument(address) #print instrument.ask('*IDN?') print dir(instrument) print instrument.idn print instrument.DEFAULT_STATE_QUERY_DICTIONARY print instrument.current_state print 'Writing 0 volts to AUX4' instrument.set_state(**{'AUXV 4,':0}) print instrument.current_state print instrument.state_buffer print instrument.commands
def test_determine_instrument_type(
)
def test_determine_instrument_type(): print 'Type is %s'%determine_instrument_type('GPIB::22') print 'Type is %s'%determine_instrument_type('COMM::1') print 'Type is %s'%determine_instrument_type('CoMm::1') print 'Type is %s'%determine_instrument_type('SRS830') print 'Type is %s'%determine_instrument_type('36111') class blank():pass new=blank() print type(new) print 'Type is %s'%determine_instrument_type(new) new.instrument_type='Ocean_Optics' print new.instrument_type print 'Type is %s'%determine_instrument_type(new) TF=(type(new)==InstanceType or ClassType) print TF print dir(new) print 'instrument_type' in dir(new)
def test_find_description(
)
Tests the function find description
def test_find_description(): """Tests the function find description""" print "The path of the description of %s is %s"%('Lockin2',find_description('Lockin2')) print "The File Contents are:" print find_description('Lockin2','file')
Classes
class FakeInstrument
General Class to communicate with COMM and GPIB instruments This is a blend of the pyvisa resource and an xml description.
class FakeInstrument(InstrumentSheet): """ General Class to communicate with COMM and GPIB instruments This is a blend of the pyvisa resource and an xml description. """ def __init__(self, resource_name=None, **options): """ Intializes the VisaInstrument Class""" defaults = {"state_directory": os.getcwd(), "instrument_description_directory": os.path.join(PYMEASURE_ROOT, 'Instruments')} self.options = {} for key, value in defaults.iteritems(): self.options[key] = value for key, value in options.iteritems(): self.options[key] = value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path = find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self, self.info_path, **self.options) self.info_found = True self.DEFAULT_STATE_QUERY_DICTIONARY = self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY = {} self.info_found = False self.instrument_address = resource_name self.name = resource_name.replace(":", "_") pass else: self.info_found = False self.DEFAULT_STATE_QUERY_DICTIONARY = {} self.instrument_address = resource_name # Create a description for state saving if self.info_found: self.description = {'Instrument_Description': self.path} else: self.description = {'Instrument_Description': self.instrument_address} self.state_buffer = [] self.STATE_BUFFER_MAX_LENGTH = 10 self.write_buffer=[] self.read_buffer=[] self.history=[] #self.resource_manager = visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read #self.resource = self.resource_manager.open_resource(self.instrument_address) self.current_state = self.get_state() def write(self, command): "Writes command to instrument" now=datetime.datetime.utcnow().isoformat() self.write_buffer.append(command) self.history.append({"Timestamp":now,"Action":"self.write", "Argument":command,"Response":None}) def read(self): "Reads from the instrument" now=datetime.datetime.utcnow().isoformat() out="Buffer Read at {0}".format(now) self.read_buffer.append(out) time.sleep(.001) self.history.append({"Timestamp":now,"Action":"self.read", "Argument":None,"Response":out}) return out def query(self, command): "Writes command and then reads a response" self.write(command) return self.read() def ask(self, command): "Writes command and then reads a response" return self.query(command) def set_state(self, state_dictionary=None, state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer) + 1 < self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1, self.get_state()) for state_command, value in state_dictionary.iteritems(): self.write(state_command + ' ' + str(value)) self.current_state = self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table = sorted(state_table, key=lambda x: x["Index"]) if len(self.state_buffer) + 1 < self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1, self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command = state_row["Set"] value = state_row["Value"] self.write(state_command + ' ' + str(value)) def get_state(self, state_query_dictionary=None, state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary) == 0: state_query_dictionary = self.DEFAULT_STATE_QUERY_DICTIONARY state = dict([(state_command, self.query(str(query)).replace("\n", "")) for state_command, query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table = sorted(state_query_table, key=lambda x: int(x["Index"])) state = [] for state_row in state_query_table: set = state_row["Set"] query = state_row["Query"] index = state_row["Index"] state.append({"Set": set, "Value": self.query(query).replace("\n", ""), "Index": index}) return state else: state = [] for state_row in state_query_table: set = state_row["Set"] query = state_row["Query"] state.append({"Set": set, "Value": self.query(query).replace("\n", "")}) return state def update_current_state(self): self.current_state = self.get_state() def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state = self.get_state() self.save_state(None, state_dictionary=self.current_state) def save_state(self, state_path=None, state_dictionary=None, state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path = auto_name(specific_descriptor=self.name, general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state = InstrumentState(None, **{"state_dictionary": state_dictionary, "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state = InstrumentState(None, **{"state_table": state_table, "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) else: new_state = InstrumentState(None, **{"state_dictionary": self.get_state(), "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise # pass new_state.save(state_path) return state_path def load_state(self, file_path): """Loads a state from a file.""" # TODO put a UDT to state_table state_model = InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary()) def close(self): """Closes the VISA session""" print("Fake Instrument has been closed")
Ancestors (in MRO)
- FakeInstrument
- Code.DataHandlers.XMLModels.InstrumentSheet
- Code.DataHandlers.XMLModels.XMLBase
Instance variables
var STATE_BUFFER_MAX_LENGTH
var current_state
var history
var options
var read_buffer
var state_buffer
var write_buffer
Methods
def __init__(
self, resource_name=None, **options)
Intializes the VisaInstrument Class
def __init__(self, resource_name=None, **options): """ Intializes the VisaInstrument Class""" defaults = {"state_directory": os.getcwd(), "instrument_description_directory": os.path.join(PYMEASURE_ROOT, 'Instruments')} self.options = {} for key, value in defaults.iteritems(): self.options[key] = value for key, value in options.iteritems(): self.options[key] = value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path = find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self, self.info_path, **self.options) self.info_found = True self.DEFAULT_STATE_QUERY_DICTIONARY = self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY = {} self.info_found = False self.instrument_address = resource_name self.name = resource_name.replace(":", "_") pass else: self.info_found = False self.DEFAULT_STATE_QUERY_DICTIONARY = {} self.instrument_address = resource_name # Create a description for state saving if self.info_found: self.description = {'Instrument_Description': self.path} else: self.description = {'Instrument_Description': self.instrument_address} self.state_buffer = [] self.STATE_BUFFER_MAX_LENGTH = 10 self.write_buffer=[] self.read_buffer=[] self.history=[] #self.resource_manager = visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read #self.resource = self.resource_manager.open_resource(self.instrument_address) self.current_state = self.get_state()
def add_entry(
self, tag_name, text=None, description='Specific', **attribute_dictionary)
Adds an entry to the instrument sheet.
def add_entry(self,tag_name,text=None,description='Specific',**attribute_dictionary): """ Adds an entry to the instrument sheet.""" specific_match=re.compile('Specific',re.IGNORECASE) general_match=re.compile('General',re.IGNORECASE) if re.search(specific_match,description): description_node=self.document.getElementsByTagName('Specific_Information')[0] elif re.search(general_match,description): description_node=self.document.getElementsByTagName('General_Information')[0] new_entry=self.document.createElement(tag_name) if not text is None: text_node=self.document.createTextNode(tag_name) new_entry.appendChild(text_node) for key,value in attribute_dictionary.iteritems(): new_attribute=self.document.creatAttribute(key) new_entry.setAttributeNode(new_attribute) new_entry.setAttribute(key,str(value)) description_node.appendChild(new_entry)
def ask(
self, command)
Writes command and then reads a response
def ask(self, command): "Writes command and then reads a response" return self.query(command)
def close(
self)
Closes the VISA session
def close(self): """Closes the VISA session""" print("Fake Instrument has been closed")
def get_image_path(
self)
Tries to return the image path, requires image to be in
def get_image_path(self): """Tries to return the image path, requires image to be in <Image href="http://132.163.53.152:8080/home_media/img/Fischione_1040.jpg"/> format""" # Take the first thing called Image image_node=self.document.getElementsByTagName('Image')[0] image_path=image_node.getAttribute('href') return image_path
def get_query_dictionary(
self)
Returns a set:query dictionary if there is a State_Commands element
def get_query_dictionary(self): """ Returns a set:query dictionary if there is a State_Commands element""" try: state_commands=self.document.getElementsByTagName('State_Commands')[0] state_query_dictionary=dict([(str(node.getAttribute('Set') ),str(node.getAttribute('Query'))) for node in state_commands.childNodes if node.nodeType is \ NODE_TYPE_DICTIONARY['ELEMENT_NODE']]) return state_query_dictionary except: raise
def get_state(
self, state_query_dictionary=None, state_query_table=None)
Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet
def get_state(self, state_query_dictionary=None, state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary) == 0: state_query_dictionary = self.DEFAULT_STATE_QUERY_DICTIONARY state = dict([(state_command, self.query(str(query)).replace("\n", "")) for state_command, query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table = sorted(state_query_table, key=lambda x: int(x["Index"])) state = [] for state_row in state_query_table: set = state_row["Set"] query = state_row["Query"] index = state_row["Index"] state.append({"Set": set, "Value": self.query(query).replace("\n", ""), "Index": index}) return state else: state = [] for state_row in state_query_table: set = state_row["Set"] query = state_row["Query"] state.append({"Set": set, "Value": self.query(query).replace("\n", "")}) return state
def load_state(
self, file_path)
Loads a state from a file.
def load_state(self, file_path): """Loads a state from a file.""" # TODO put a UDT to state_table state_model = InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary())
def query(
self, command)
Writes command and then reads a response
def query(self, command): "Writes command and then reads a response" self.write(command) return self.read()
def read(
self)
Reads from the instrument
def read(self): "Reads from the instrument" now=datetime.datetime.utcnow().isoformat() out="Buffer Read at {0}".format(now) self.read_buffer.append(out) time.sleep(.001) self.history.append({"Timestamp":now,"Action":"self.read", "Argument":None,"Response":out}) return out
def save(
self, path=None)
" Saves as an XML file
def save(self,path=None): """" Saves as an XML file""" if path is None: path=self.path file_out=open(path,'w') file_out.write(str(self)) file_out.close()
def save_HTML(
self, file_path=None, XSLT=None)
Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')
def save_HTML(self,file_path=None,XSLT=None): """Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] HTML=self.to_HTML(XSLT=XSLT) #print type(HTML) if file_path is None: file_path=self.path.replace('.xml','.html') out_file=open(file_path,'w') out_file.write(HTML) out_file.close()
def save_current_state(
self)
Saves the state in self.current_state attribute
def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state = self.get_state() self.save_state(None, state_dictionary=self.current_state)
def save_state(
self, state_path=None, state_dictionary=None, state_table=None)
Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state
def save_state(self, state_path=None, state_dictionary=None, state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path = auto_name(specific_descriptor=self.name, general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state = InstrumentState(None, **{"state_dictionary": state_dictionary, "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state = InstrumentState(None, **{"state_table": state_table, "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) else: new_state = InstrumentState(None, **{"state_dictionary": self.get_state(), "style_sheet": "./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise # pass new_state.save(state_path) return state_path
def set_state(
self, state_dictionary=None, state_table=None)
Sets the instrument to the state specified by Command:Value pairs
def set_state(self, state_dictionary=None, state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer) + 1 < self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1, self.get_state()) for state_command, value in state_dictionary.iteritems(): self.write(state_command + ' ' + str(value)) self.current_state = self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table = sorted(state_table, key=lambda x: x["Index"]) if len(self.state_buffer) + 1 < self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1, self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command = state_row["Set"] value = state_row["Value"] self.write(state_command + ' ' + str(value))
def show(
self, mode='Window')
Displays a XML Document either as formatted text in the command line or in a window (using wx)
def show(self,mode='Window'): """ Displays a XML Document either as formatted text in the command line or in a window (using wx)""" def tag_to_tagName(tag): tagName=tag.replace('<','') tagName=tagName.replace('/','') tagName=tagName.replace('>','') return tagName if mode in ['text','txt','cmd line','cmd']: for node in self.document.getElementsByTagName('Entry'): print 'Entry Index: %s \tDate: %s'%(node.getAttribute('Index'), node.getAttribute('Date')) print node.firstChild.nodeValue elif re.search('xml',mode,re.IGNORECASE): for node in self.document.getElementsByTagName('Entry'): print node.toprettyxml() elif re.search('Window|wx',mode,re.IGNORECASE): try: import wx import wx.html except: print 'Cannot locate wx, please add to sys.path' app = wx.App(False) frame=wx.Frame(None) html_window=wx.html.HtmlWindow(frame) html_window.SetPage(str(self.to_HTML())) frame.Show() app.MainLoop()
def to_HTML(
self, XSLT=None)
Returns HTML string by applying a XSL to the XML document
def to_HTML(self,XSLT=None): """ Returns HTML string by applying a XSL to the XML document""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] XSL_data=etree.parse(XSLT) XSL_transform=etree.XSLT(XSL_data) HTML=XSL_transform(etree.XML(self.document.toxml())) return str(HTML)
def update_current_state(
self)
def update_current_state(self): self.current_state = self.get_state()
def update_document(
self)
Updates the attribute document from the self.etree.
def update_document(self): """Updates the attribute document from the self.etree. """ self.document=xml.dom.minidom.parseString(etree.tostring(self.etree))
def update_etree(
self)
Updates the attribute etree. Should be called anytime the xml content is changed
def update_etree(self): "Updates the attribute etree. Should be called anytime the xml content is changed" self.etree = etree.fromstring(self.document.toxml())
def write(
self, command)
Writes command to instrument
def write(self, command): "Writes command to instrument" now=datetime.datetime.utcnow().isoformat() self.write_buffer.append(command) self.history.append({"Timestamp":now,"Action":"self.write", "Argument":command,"Response":None})
class HighSpeedOscope
Control Class for high speed oscilloscopes. Based on code from Diogo
class HighSpeedOscope(VisaInstrument): """Control Class for high speed oscilloscopes. Based on code from Diogo """ def initialize(self, **options): """Initializes the oscilloscope for data collection""" defaults = {"reset": True} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value pass def measure_waves(self, **options): """Returns data for a measurement in an AsciiDataTable""" defaults = {"number_frames": 1, "number_points": self.get_number_points(), "timebase_scale": self.get_timebase_scale(), "channels": [1, 2, 3, 4], "initial_time_offset": self.get_time_position(), "timeout_measurement": 10000, "save_data": False, "data_format": "dat", "directory": os.getcwd(), "specific_descriptor": "Scope", "general_descriptor": "Measurement", "add_header": False, "output_table_options": {"data_delimiter": " ", "treat_header_as_comment": True} } self.measure_options = {} for key, value in defaults.iteritems(): self.measure_options[key] = value for key, value in options.iteritems(): self.measure_options[key] = value self.set_number_points(self.measure_options["number_points"]) channel_string_list = ["CHAN1", "CHAN2", "CHAN3", "CHAN4"] # begin by setting timeout to timeout_measurement timeout = self.resource.timeout self.resource.timeout = self.measure_options["timeout_measurement"] # now calculate timestep self.measure_options["timestep"] = self.measure_options["timebase_scale"] / self.measure_options[ "number_points"] time_step = self.measure_options["timestep"] # now configure the scope for data transfer # define the way the data is transmitted from the instrument to the PC self.write(':WAV:FORM ASCII') # Word -> 16bit signed integer #self.write(':WAV:FORM WORD') # little-endian #self.write(':WAV:BYT LSBF') number_rows = self.measure_options["number_points"] * self.measure_options["number_frames"] # this is the way diogo did it # number of points number_points = self.measure_options["number_points"] frames_data = [] for frame_index in range(self.measure_options["number_frames"]): new_frame = [] # calculate time position for this frame time_position = frame_index * self.measure_options["timebase_scale"] + self.measure_options[ "initial_time_offset"] # define postion to start the acquisition self.write(':TIM:POS {0}ns'.format(time_position)) # acquire channels desired channel_string = "" for channel_index, channel in enumerate(self.measure_options["channels"]): if channel_index == len(self.measure_options["channels"]) - 1: channel_string = channel_string + "{0}".format(channel_string_list[channel - 1]) else: channel_string = channel_string + "{0},".format(channel_string_list[channel - 1]) channel_command = ":DIG {0}".format(channel_string) self.write(channel_command) # trigger reading and wait self.write("*OPC?") # get data from the necessary channels for channel_read_index, channel_read in enumerate(self.measure_options["channels"]): # get data for channel 1 self.write(':WAV:SOUR CHAN{0}'.format(channel_read)) # get data #data_column = self.resource.query_binary_values(':WAV:DATA?', datatype='h') data_column = self.resource.query(':WAV:DATA?') new_frame.append(data_column) # print("{0} is {1}".format("data_column",data_column)) frames_data.append(new_frame) # reshape measurement data measurement_data = [range(len(frames_data[0])) for x in range(number_points * len(frames_data))] # print(len(measurement_data)) # print(len(measurement_data[0])) # print("{0} is{1}".format("len(frames_data)",len(frames_data))) # print("{0} is{1}".format("len(frames_data[0])",len(frames_data[0]))) # print("{0} is{1}".format("len(frames_data[0][0])",len(frames_data[0][0]))) for frame_index, frame in enumerate(frames_data): for column_index, column in enumerate(frame): for row_index, row in enumerate(column): number_rows = len(column) # print("{0} is {1}".format("([row_index+frame_index*number_rows],[column_index],[frame_index])", # ([row_index + frame_index * number_rows], [column_index], [frame_index]))) measurement_data[row_index + frame_index * number_rows][column_index] = \ frames_data[frame_index][column_index][row_index] # reset timeout self.resource.timeout = timeout data_out = [] time_start = self.measure_options["initial_time_offset"] for row_index, data_row in enumerate(measurement_data): new_row = [time_start + row_index * time_step] + data_row data_out.append(new_row) if self.measure_options["add_header"]: header = [] for key, value in self.measure_options.iteritems(): header.append("{0} = {1}".format(key, value)) else: header = None column_names = ["Time"] for channel in self.measure_options["channels"]: column_names.append(channel_string_list[channel - 1]) table_options = {"data": data_out, "header": header, "specific_descriptor": self.measure_options["specific_descriptor"], "general_descriptor": self.measure_options["general_descriptor"], "extension": "dat", "directory": self.measure_options["directory"], "column_names": column_names} for key, value in self.measure_options["output_table_options"].iteritems(): table_options[key] = value output_table = AsciiDataTable(None, **table_options) if self.measure_options["save_data"]: data_save_path = auto_name(specific_descriptor=self.measure_options["specific_descriptor"], general_descriptor=self.measure_options["general_descriptor"], directory=self.measure_options["directory"], extension='dat' , padding=3) output_table.path = data_save_path output_table.save() return output_table def get_error_state(self): """Returns the error state of the oscope""" state = self.query(':SYSTEM:ERROR? STRING') self.error_state = state return state def set_number_points(self, number_points=16384): """Sets the number of points for the acquisition""" self.write(':ACQ:POINTS {0}'.format(number_points)) def get_number_points(self): """Returns the number of points in the waveform""" number_points = int(self.query(':ACQ:POINTS?')) return number_points def set_time_position(self, time=50): """Sets the time in ns to start the acquisition""" self.write(':TIM:POS {0}ns'.format(time)) def get_time_position(self): """Returns the time position in ns""" position = float(self.query(":TIM:POS?")) return position * 10 ** 9 def set_timebase_scale(self, time_scale=40.96): """Sets the timebase scale in ns""" self.write(':TIM:SCAL {0}ns'.format(time_scale)) def get_timebase_scale(self): """Returns the timebase scale in ns""" time_scale = float(self.query(':TIM:SCAL?')) return time_scale * 10 ** 9 def set_trigger_source(self, source="FPAN"): """Sets the tigger source, 'FPAN' Frontpanel or 'FRUN' freerun""" self.write(':TRIG:SOUR {0}'.format(source)) def get_trigger_source(self): """Returns the trigger source FPAN for FrontPanel or FRUN for free run""" source = self.query(':TRIG:SOUR?') def set_trigger_level(self, level=10): """Sets the trigger level in mv""" self.write(':TRIG:LEV {0}m'.format(level)) def get_trigger_level(self): """Returns the trigger level""" level = self.query(':TRIG:LEV?') def set_channel_scale(self, scale=10, channel=1): """Sets the scale in mv of channel. Default is 10mv/division on channel 1""" self.write(':CHAN{0}:SCAL {1}m'.format(channel, scale)) def get_channel_scale(self, channel=1): "Returns the scale for a specified channel, the default is channel 1" scale = self.query(':CHAN{0}:SCAL?'.format(channel)) return scale def set_channel_bandwidth(self, bandwidth="LOW", channel=1): """Sets the specified channel's bandwith to LOW, MED or HIGH, default is to set channel 1 to LOW""" self.write(':CHAN{0}:BAND {1}'.format(channel, bandwidth)) def get_channel_bandwidth(self, channel=1): """Returns the selected channels bandwidth""" bandwidth = self.query(':CHAN{0}:BAND?'.format(channel)) return bandwidth def set_trigger_slope(self, slope="POS"): """Sets the trigger slope on the oscope choose from POS or NEG""" self.write(':TRIG:SLOP {0}'.format(slope)) def get_trigger_slope(self): """Returns the trigger slope either POS or NEG""" slope = self.query(":TRIG:SLOP?") return slope
Ancestors (in MRO)
- HighSpeedOscope
- VisaInstrument
- Code.DataHandlers.XMLModels.InstrumentSheet
- Code.DataHandlers.XMLModels.XMLBase
Instance variables
Methods
def __init__(
self, resource_name=None, **options)
Inheritance:
VisaInstrument
.__init__
Initializes the VisaInstrument Class
def __init__(self,resource_name=None,**options): """ Initializes the VisaInstrument Class""" defaults={"state_directory":os.getcwd(), "instrument_description_directory":os.path.join(PYMEASURE_ROOT,'Instruments')} self.options={} for key,value in defaults.iteritems(): self.options[key]=value for key,value in options.iteritems(): self.options[key]=value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path=find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self,self.info_path,**self.options) self.info_found=True self.DEFAULT_STATE_QUERY_DICTIONARY=self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY={} self.info_found=False self.instrument_address=resource_name self.name=resource_name.replace(":","_") pass else: self.info_found=False self.DEFAULT_STATE_QUERY_DICTIONARY={} self.instrument_address=resource_name # Create a description for state saving if self.info_found: self.description={'Instrument_Description':self.path} else: self.description={'Instrument_Description':self.instrument_address} self.state_buffer=[] self.STATE_BUFFER_MAX_LENGTH=10 self.resource_manager=visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read self.resource=self.resource_manager.open_resource(self.instrument_address) self.current_state=self.get_state()
def add_entry(
self, tag_name, text=None, description='Specific', **attribute_dictionary)
Inheritance:
VisaInstrument
.add_entry
Adds an entry to the instrument sheet.
def add_entry(self,tag_name,text=None,description='Specific',**attribute_dictionary): """ Adds an entry to the instrument sheet.""" specific_match=re.compile('Specific',re.IGNORECASE) general_match=re.compile('General',re.IGNORECASE) if re.search(specific_match,description): description_node=self.document.getElementsByTagName('Specific_Information')[0] elif re.search(general_match,description): description_node=self.document.getElementsByTagName('General_Information')[0] new_entry=self.document.createElement(tag_name) if not text is None: text_node=self.document.createTextNode(tag_name) new_entry.appendChild(text_node) for key,value in attribute_dictionary.iteritems(): new_attribute=self.document.creatAttribute(key) new_entry.setAttributeNode(new_attribute) new_entry.setAttribute(key,str(value)) description_node.appendChild(new_entry)
def ask(
self, command)
Inheritance:
VisaInstrument
.ask
Writes command and then reads a response
def ask(self,command): "Writes command and then reads a response" return self.resource.query(command)
def close(
self)
Inheritance:
VisaInstrument
.close
Closes the VISA session
def close(self): """Closes the VISA session""" self.resource_manager.close()
def get_channel_bandwidth(
self, channel=1)
Returns the selected channels bandwidth
def get_channel_bandwidth(self, channel=1): """Returns the selected channels bandwidth""" bandwidth = self.query(':CHAN{0}:BAND?'.format(channel)) return bandwidth
def get_channel_scale(
self, channel=1)
Returns the scale for a specified channel, the default is channel 1
def get_channel_scale(self, channel=1): "Returns the scale for a specified channel, the default is channel 1" scale = self.query(':CHAN{0}:SCAL?'.format(channel)) return scale
def get_error_state(
self)
Returns the error state of the oscope
def get_error_state(self): """Returns the error state of the oscope""" state = self.query(':SYSTEM:ERROR? STRING') self.error_state = state return state
def get_image_path(
self)
Inheritance:
VisaInstrument
.get_image_path
Tries to return the image path, requires image to be in
def get_image_path(self): """Tries to return the image path, requires image to be in <Image href="http://132.163.53.152:8080/home_media/img/Fischione_1040.jpg"/> format""" # Take the first thing called Image image_node=self.document.getElementsByTagName('Image')[0] image_path=image_node.getAttribute('href') return image_path
def get_number_points(
self)
Returns the number of points in the waveform
def get_number_points(self): """Returns the number of points in the waveform""" number_points = int(self.query(':ACQ:POINTS?')) return number_points
def get_query_dictionary(
self)
Inheritance:
VisaInstrument
.get_query_dictionary
Returns a set:query dictionary if there is a State_Commands element
def get_query_dictionary(self): """ Returns a set:query dictionary if there is a State_Commands element""" try: state_commands=self.document.getElementsByTagName('State_Commands')[0] state_query_dictionary=dict([(str(node.getAttribute('Set') ),str(node.getAttribute('Query'))) for node in state_commands.childNodes if node.nodeType is \ NODE_TYPE_DICTIONARY['ELEMENT_NODE']]) return state_query_dictionary except: raise
def get_state(
self, state_query_dictionary=None, state_query_table=None)
Inheritance:
VisaInstrument
.get_state
Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet
def get_state(self,state_query_dictionary=None,state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary)==0 : state_query_dictionary=self.DEFAULT_STATE_QUERY_DICTIONARY state=dict([(state_command,self.query(str(query)).replace("\n","")) for state_command,query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table=sorted(state_query_table,key=lambda x:int(x["Index"])) state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] index=state_row["Index"] state.append({"Set":set,"Value":self.query(query).replace("\n",""),"Index":index}) return state else: state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] state.append({"Set":set,"Value":self.query(query).replace("\n","")}) return state
def get_time_position(
self)
Returns the time position in ns
def get_time_position(self): """Returns the time position in ns""" position = float(self.query(":TIM:POS?")) return position * 10 ** 9
def get_timebase_scale(
self)
Returns the timebase scale in ns
def get_timebase_scale(self): """Returns the timebase scale in ns""" time_scale = float(self.query(':TIM:SCAL?')) return time_scale * 10 ** 9
def get_trigger_level(
self)
Returns the trigger level
def get_trigger_level(self): """Returns the trigger level""" level = self.query(':TRIG:LEV?')
def get_trigger_slope(
self)
Returns the trigger slope either POS or NEG
def get_trigger_slope(self): """Returns the trigger slope either POS or NEG""" slope = self.query(":TRIG:SLOP?") return slope
def get_trigger_source(
self)
Returns the trigger source FPAN for FrontPanel or FRUN for free run
def get_trigger_source(self): """Returns the trigger source FPAN for FrontPanel or FRUN for free run""" source = self.query(':TRIG:SOUR?')
def initialize(
self, **options)
Initializes the oscilloscope for data collection
def initialize(self, **options): """Initializes the oscilloscope for data collection""" defaults = {"reset": True} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value pass
def load_state(
self, file_path)
Inheritance:
VisaInstrument
.load_state
Loads a state from a file.
def load_state(self,file_path): """Loads a state from a file.""" #TODO put a UDT to state_table state_model=InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary())
def measure_waves(
self, **options)
Returns data for a measurement in an AsciiDataTable
def measure_waves(self, **options): """Returns data for a measurement in an AsciiDataTable""" defaults = {"number_frames": 1, "number_points": self.get_number_points(), "timebase_scale": self.get_timebase_scale(), "channels": [1, 2, 3, 4], "initial_time_offset": self.get_time_position(), "timeout_measurement": 10000, "save_data": False, "data_format": "dat", "directory": os.getcwd(), "specific_descriptor": "Scope", "general_descriptor": "Measurement", "add_header": False, "output_table_options": {"data_delimiter": " ", "treat_header_as_comment": True} } self.measure_options = {} for key, value in defaults.iteritems(): self.measure_options[key] = value for key, value in options.iteritems(): self.measure_options[key] = value self.set_number_points(self.measure_options["number_points"]) channel_string_list = ["CHAN1", "CHAN2", "CHAN3", "CHAN4"] # begin by setting timeout to timeout_measurement timeout = self.resource.timeout self.resource.timeout = self.measure_options["timeout_measurement"] # now calculate timestep self.measure_options["timestep"] = self.measure_options["timebase_scale"] / self.measure_options[ "number_points"] time_step = self.measure_options["timestep"] # now configure the scope for data transfer # define the way the data is transmitted from the instrument to the PC self.write(':WAV:FORM ASCII') # Word -> 16bit signed integer #self.write(':WAV:FORM WORD') # little-endian #self.write(':WAV:BYT LSBF') number_rows = self.measure_options["number_points"] * self.measure_options["number_frames"] # this is the way diogo did it # number of points number_points = self.measure_options["number_points"] frames_data = [] for frame_index in range(self.measure_options["number_frames"]): new_frame = [] # calculate time position for this frame time_position = frame_index * self.measure_options["timebase_scale"] + self.measure_options[ "initial_time_offset"] # define postion to start the acquisition self.write(':TIM:POS {0}ns'.format(time_position)) # acquire channels desired channel_string = "" for channel_index, channel in enumerate(self.measure_options["channels"]): if channel_index == len(self.measure_options["channels"]) - 1: channel_string = channel_string + "{0}".format(channel_string_list[channel - 1]) else: channel_string = channel_string + "{0},".format(channel_string_list[channel - 1]) channel_command = ":DIG {0}".format(channel_string) self.write(channel_command) # trigger reading and wait self.write("*OPC?") # get data from the necessary channels for channel_read_index, channel_read in enumerate(self.measure_options["channels"]): # get data for channel 1 self.write(':WAV:SOUR CHAN{0}'.format(channel_read)) # get data #data_column = self.resource.query_binary_values(':WAV:DATA?', datatype='h') data_column = self.resource.query(':WAV:DATA?') new_frame.append(data_column) # print("{0} is {1}".format("data_column",data_column)) frames_data.append(new_frame) # reshape measurement data measurement_data = [range(len(frames_data[0])) for x in range(number_points * len(frames_data))] # print(len(measurement_data)) # print(len(measurement_data[0])) # print("{0} is{1}".format("len(frames_data)",len(frames_data))) # print("{0} is{1}".format("len(frames_data[0])",len(frames_data[0]))) # print("{0} is{1}".format("len(frames_data[0][0])",len(frames_data[0][0]))) for frame_index, frame in enumerate(frames_data): for column_index, column in enumerate(frame): for row_index, row in enumerate(column): number_rows = len(column) # print("{0} is {1}".format("([row_index+frame_index*number_rows],[column_index],[frame_index])", # ([row_index + frame_index * number_rows], [column_index], [frame_index]))) measurement_data[row_index + frame_index * number_rows][column_index] = \ frames_data[frame_index][column_index][row_index] # reset timeout self.resource.timeout = timeout data_out = [] time_start = self.measure_options["initial_time_offset"] for row_index, data_row in enumerate(measurement_data): new_row = [time_start + row_index * time_step] + data_row data_out.append(new_row) if self.measure_options["add_header"]: header = [] for key, value in self.measure_options.iteritems(): header.append("{0} = {1}".format(key, value)) else: header = None column_names = ["Time"] for channel in self.measure_options["channels"]: column_names.append(channel_string_list[channel - 1]) table_options = {"data": data_out, "header": header, "specific_descriptor": self.measure_options["specific_descriptor"], "general_descriptor": self.measure_options["general_descriptor"], "extension": "dat", "directory": self.measure_options["directory"], "column_names": column_names} for key, value in self.measure_options["output_table_options"].iteritems(): table_options[key] = value output_table = AsciiDataTable(None, **table_options) if self.measure_options["save_data"]: data_save_path = auto_name(specific_descriptor=self.measure_options["specific_descriptor"], general_descriptor=self.measure_options["general_descriptor"], directory=self.measure_options["directory"], extension='dat' , padding=3) output_table.path = data_save_path output_table.save() return output_table
def query(
self, command)
Inheritance:
VisaInstrument
.query
Writes command and then reads a response
def query(self,command): "Writes command and then reads a response" return self.resource.query(command)
def read(
self)
Inheritance:
VisaInstrument
.read
Reads from the instrument
def read(self): "Reads from the instrument" return self.resource.read()
def save(
self, path=None)
Inheritance:
VisaInstrument
.save
" Saves as an XML file
def save(self,path=None): """" Saves as an XML file""" if path is None: path=self.path file_out=open(path,'w') file_out.write(str(self)) file_out.close()
def save_HTML(
self, file_path=None, XSLT=None)
Inheritance:
VisaInstrument
.save_HTML
Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')
def save_HTML(self,file_path=None,XSLT=None): """Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] HTML=self.to_HTML(XSLT=XSLT) #print type(HTML) if file_path is None: file_path=self.path.replace('.xml','.html') out_file=open(file_path,'w') out_file.write(HTML) out_file.close()
def save_current_state(
self)
Inheritance:
VisaInstrument
.save_current_state
Saves the state in self.current_state attribute
def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state=self.get_state() self.save_state(None,state_dictionary=self.current_state)
def save_state(
self, state_path=None, state_dictionary=None, state_table=None)
Inheritance:
VisaInstrument
.save_state
Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state
def save_state(self,state_path=None,state_dictionary=None,state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path=auto_name(specific_descriptor=self.name,general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state=InstrumentState(None,**{"state_dictionary":state_dictionary, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state=InstrumentState(None,**{"state_table":state_table, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) else: new_state=InstrumentState(None,**{"state_dictionary":self.get_state(), "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise #pass new_state.save(state_path) return state_path
def set_channel_bandwidth(
self, bandwidth='LOW', channel=1)
Sets the specified channel's bandwith to LOW, MED or HIGH, default is to set channel 1 to LOW
def set_channel_bandwidth(self, bandwidth="LOW", channel=1): """Sets the specified channel's bandwith to LOW, MED or HIGH, default is to set channel 1 to LOW""" self.write(':CHAN{0}:BAND {1}'.format(channel, bandwidth))
def set_channel_scale(
self, scale=10, channel=1)
Sets the scale in mv of channel. Default is 10mv/division on channel 1
def set_channel_scale(self, scale=10, channel=1): """Sets the scale in mv of channel. Default is 10mv/division on channel 1""" self.write(':CHAN{0}:SCAL {1}m'.format(channel, scale))
def set_number_points(
self, number_points=16384)
Sets the number of points for the acquisition
def set_number_points(self, number_points=16384): """Sets the number of points for the acquisition""" self.write(':ACQ:POINTS {0}'.format(number_points))
def set_state(
self, state_dictionary=None, state_table=None)
Inheritance:
VisaInstrument
.set_state
Sets the instrument to the state specified by Command:Value pairs
def set_state(self,state_dictionary=None,state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) for state_command,value in state_dictionary.iteritems(): self.write(state_command+' '+str(value)) self.current_state=self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table=sorted(state_table,key=lambda x:x["Index"]) if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command=state_row["Set"] value=state_row["Value"] self.write(state_command+' '+str(value))
def set_time_position(
self, time=50)
Sets the time in ns to start the acquisition
def set_time_position(self, time=50): """Sets the time in ns to start the acquisition""" self.write(':TIM:POS {0}ns'.format(time))
def set_timebase_scale(
self, time_scale=40.96)
Sets the timebase scale in ns
def set_timebase_scale(self, time_scale=40.96): """Sets the timebase scale in ns""" self.write(':TIM:SCAL {0}ns'.format(time_scale))
def set_trigger_level(
self, level=10)
Sets the trigger level in mv
def set_trigger_level(self, level=10): """Sets the trigger level in mv""" self.write(':TRIG:LEV {0}m'.format(level))
def set_trigger_slope(
self, slope='POS')
Sets the trigger slope on the oscope choose from POS or NEG
def set_trigger_slope(self, slope="POS"): """Sets the trigger slope on the oscope choose from POS or NEG""" self.write(':TRIG:SLOP {0}'.format(slope))
def set_trigger_source(
self, source='FPAN')
Sets the tigger source, 'FPAN' Frontpanel or 'FRUN' freerun
def set_trigger_source(self, source="FPAN"): """Sets the tigger source, 'FPAN' Frontpanel or 'FRUN' freerun""" self.write(':TRIG:SOUR {0}'.format(source))
def show(
self, mode='Window')
Inheritance:
VisaInstrument
.show
Displays a XML Document either as formatted text in the command line or in a window (using wx)
def show(self,mode='Window'): """ Displays a XML Document either as formatted text in the command line or in a window (using wx)""" def tag_to_tagName(tag): tagName=tag.replace('<','') tagName=tagName.replace('/','') tagName=tagName.replace('>','') return tagName if mode in ['text','txt','cmd line','cmd']: for node in self.document.getElementsByTagName('Entry'): print 'Entry Index: %s \tDate: %s'%(node.getAttribute('Index'), node.getAttribute('Date')) print node.firstChild.nodeValue elif re.search('xml',mode,re.IGNORECASE): for node in self.document.getElementsByTagName('Entry'): print node.toprettyxml() elif re.search('Window|wx',mode,re.IGNORECASE): try: import wx import wx.html except: print 'Cannot locate wx, please add to sys.path' app = wx.App(False) frame=wx.Frame(None) html_window=wx.html.HtmlWindow(frame) html_window.SetPage(str(self.to_HTML())) frame.Show() app.MainLoop()
def to_HTML(
self, XSLT=None)
Inheritance:
VisaInstrument
.to_HTML
Returns HTML string by applying a XSL to the XML document
def to_HTML(self,XSLT=None): """ Returns HTML string by applying a XSL to the XML document""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] XSL_data=etree.parse(XSLT) XSL_transform=etree.XSLT(XSL_data) HTML=XSL_transform(etree.XML(self.document.toxml())) return str(HTML)
def update_current_state(
self)
Inheritance:
VisaInstrument
.update_current_state
def update_current_state(self): self.current_state=self.get_state()
def update_document(
self)
Inheritance:
VisaInstrument
.update_document
Updates the attribute document from the self.etree.
def update_document(self): """Updates the attribute document from the self.etree. """ self.document=xml.dom.minidom.parseString(etree.tostring(self.etree))
def update_etree(
self)
Inheritance:
VisaInstrument
.update_etree
Updates the attribute etree. Should be called anytime the xml content is changed
def update_etree(self): "Updates the attribute etree. Should be called anytime the xml content is changed" self.etree = etree.fromstring(self.document.toxml())
def write(
self, command)
Inheritance:
VisaInstrument
.write
Writes command to instrument
def write(self,command): "Writes command to instrument" return self.resource.write(command)
class NRPPowerMeter
Controls RS power meters
class NRPPowerMeter(VisaInstrument): """Controls RS power meters""" def initialize(self): """Initializes the power meter to a state with W units, 10ms aperture and Avgerage power readings""" self.write("*RST") self.write("UNIT:POW W") self.write("SENS:FUNC POW:AVG") self.write("SENS:APER 10 MS") self.write("INIT") def get_reading(self): """Intializes and fetches a reading""" self.write("INIT") return float(self.query("FETCh?").replace("\n","")) def set_units(self,unit): """Sets the power meters units, aceptable units are W or adBM""" # Todo put an input checker on this to only allow desired commands self.write("UNIT:POW {0}".format(unit))
Ancestors (in MRO)
- NRPPowerMeter
- VisaInstrument
- Code.DataHandlers.XMLModels.InstrumentSheet
- Code.DataHandlers.XMLModels.XMLBase
Instance variables
Methods
def __init__(
self, resource_name=None, **options)
Inheritance:
VisaInstrument
.__init__
Initializes the VisaInstrument Class
def __init__(self,resource_name=None,**options): """ Initializes the VisaInstrument Class""" defaults={"state_directory":os.getcwd(), "instrument_description_directory":os.path.join(PYMEASURE_ROOT,'Instruments')} self.options={} for key,value in defaults.iteritems(): self.options[key]=value for key,value in options.iteritems(): self.options[key]=value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path=find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self,self.info_path,**self.options) self.info_found=True self.DEFAULT_STATE_QUERY_DICTIONARY=self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY={} self.info_found=False self.instrument_address=resource_name self.name=resource_name.replace(":","_") pass else: self.info_found=False self.DEFAULT_STATE_QUERY_DICTIONARY={} self.instrument_address=resource_name # Create a description for state saving if self.info_found: self.description={'Instrument_Description':self.path} else: self.description={'Instrument_Description':self.instrument_address} self.state_buffer=[] self.STATE_BUFFER_MAX_LENGTH=10 self.resource_manager=visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read self.resource=self.resource_manager.open_resource(self.instrument_address) self.current_state=self.get_state()
def add_entry(
self, tag_name, text=None, description='Specific', **attribute_dictionary)
Inheritance:
VisaInstrument
.add_entry
Adds an entry to the instrument sheet.
def add_entry(self,tag_name,text=None,description='Specific',**attribute_dictionary): """ Adds an entry to the instrument sheet.""" specific_match=re.compile('Specific',re.IGNORECASE) general_match=re.compile('General',re.IGNORECASE) if re.search(specific_match,description): description_node=self.document.getElementsByTagName('Specific_Information')[0] elif re.search(general_match,description): description_node=self.document.getElementsByTagName('General_Information')[0] new_entry=self.document.createElement(tag_name) if not text is None: text_node=self.document.createTextNode(tag_name) new_entry.appendChild(text_node) for key,value in attribute_dictionary.iteritems(): new_attribute=self.document.creatAttribute(key) new_entry.setAttributeNode(new_attribute) new_entry.setAttribute(key,str(value)) description_node.appendChild(new_entry)
def ask(
self, command)
Inheritance:
VisaInstrument
.ask
Writes command and then reads a response
def ask(self,command): "Writes command and then reads a response" return self.resource.query(command)
def close(
self)
Inheritance:
VisaInstrument
.close
Closes the VISA session
def close(self): """Closes the VISA session""" self.resource_manager.close()
def get_image_path(
self)
Inheritance:
VisaInstrument
.get_image_path
Tries to return the image path, requires image to be in
def get_image_path(self): """Tries to return the image path, requires image to be in <Image href="http://132.163.53.152:8080/home_media/img/Fischione_1040.jpg"/> format""" # Take the first thing called Image image_node=self.document.getElementsByTagName('Image')[0] image_path=image_node.getAttribute('href') return image_path
def get_query_dictionary(
self)
Inheritance:
VisaInstrument
.get_query_dictionary
Returns a set:query dictionary if there is a State_Commands element
def get_query_dictionary(self): """ Returns a set:query dictionary if there is a State_Commands element""" try: state_commands=self.document.getElementsByTagName('State_Commands')[0] state_query_dictionary=dict([(str(node.getAttribute('Set') ),str(node.getAttribute('Query'))) for node in state_commands.childNodes if node.nodeType is \ NODE_TYPE_DICTIONARY['ELEMENT_NODE']]) return state_query_dictionary except: raise
def get_reading(
self)
Intializes and fetches a reading
def get_reading(self): """Intializes and fetches a reading""" self.write("INIT") return float(self.query("FETCh?").replace("\n",""))
def get_state(
self, state_query_dictionary=None, state_query_table=None)
Inheritance:
VisaInstrument
.get_state
Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet
def get_state(self,state_query_dictionary=None,state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary)==0 : state_query_dictionary=self.DEFAULT_STATE_QUERY_DICTIONARY state=dict([(state_command,self.query(str(query)).replace("\n","")) for state_command,query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table=sorted(state_query_table,key=lambda x:int(x["Index"])) state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] index=state_row["Index"] state.append({"Set":set,"Value":self.query(query).replace("\n",""),"Index":index}) return state else: state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] state.append({"Set":set,"Value":self.query(query).replace("\n","")}) return state
def initialize(
self)
Initializes the power meter to a state with W units, 10ms aperture and Avgerage power readings
def initialize(self): """Initializes the power meter to a state with W units, 10ms aperture and Avgerage power readings""" self.write("*RST") self.write("UNIT:POW W") self.write("SENS:FUNC POW:AVG") self.write("SENS:APER 10 MS") self.write("INIT")
def load_state(
self, file_path)
Inheritance:
VisaInstrument
.load_state
Loads a state from a file.
def load_state(self,file_path): """Loads a state from a file.""" #TODO put a UDT to state_table state_model=InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary())
def query(
self, command)
Inheritance:
VisaInstrument
.query
Writes command and then reads a response
def query(self,command): "Writes command and then reads a response" return self.resource.query(command)
def read(
self)
Inheritance:
VisaInstrument
.read
Reads from the instrument
def read(self): "Reads from the instrument" return self.resource.read()
def save(
self, path=None)
Inheritance:
VisaInstrument
.save
" Saves as an XML file
def save(self,path=None): """" Saves as an XML file""" if path is None: path=self.path file_out=open(path,'w') file_out.write(str(self)) file_out.close()
def save_HTML(
self, file_path=None, XSLT=None)
Inheritance:
VisaInstrument
.save_HTML
Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')
def save_HTML(self,file_path=None,XSLT=None): """Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] HTML=self.to_HTML(XSLT=XSLT) #print type(HTML) if file_path is None: file_path=self.path.replace('.xml','.html') out_file=open(file_path,'w') out_file.write(HTML) out_file.close()
def save_current_state(
self)
Inheritance:
VisaInstrument
.save_current_state
Saves the state in self.current_state attribute
def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state=self.get_state() self.save_state(None,state_dictionary=self.current_state)
def save_state(
self, state_path=None, state_dictionary=None, state_table=None)
Inheritance:
VisaInstrument
.save_state
Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state
def save_state(self,state_path=None,state_dictionary=None,state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path=auto_name(specific_descriptor=self.name,general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state=InstrumentState(None,**{"state_dictionary":state_dictionary, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state=InstrumentState(None,**{"state_table":state_table, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) else: new_state=InstrumentState(None,**{"state_dictionary":self.get_state(), "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise #pass new_state.save(state_path) return state_path
def set_state(
self, state_dictionary=None, state_table=None)
Inheritance:
VisaInstrument
.set_state
Sets the instrument to the state specified by Command:Value pairs
def set_state(self,state_dictionary=None,state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) for state_command,value in state_dictionary.iteritems(): self.write(state_command+' '+str(value)) self.current_state=self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table=sorted(state_table,key=lambda x:x["Index"]) if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command=state_row["Set"] value=state_row["Value"] self.write(state_command+' '+str(value))
def set_units(
self, unit)
Sets the power meters units, aceptable units are W or adBM
def set_units(self,unit): """Sets the power meters units, aceptable units are W or adBM""" # Todo put an input checker on this to only allow desired commands self.write("UNIT:POW {0}".format(unit))
def show(
self, mode='Window')
Inheritance:
VisaInstrument
.show
Displays a XML Document either as formatted text in the command line or in a window (using wx)
def show(self,mode='Window'): """ Displays a XML Document either as formatted text in the command line or in a window (using wx)""" def tag_to_tagName(tag): tagName=tag.replace('<','') tagName=tagName.replace('/','') tagName=tagName.replace('>','') return tagName if mode in ['text','txt','cmd line','cmd']: for node in self.document.getElementsByTagName('Entry'): print 'Entry Index: %s \tDate: %s'%(node.getAttribute('Index'), node.getAttribute('Date')) print node.firstChild.nodeValue elif re.search('xml',mode,re.IGNORECASE): for node in self.document.getElementsByTagName('Entry'): print node.toprettyxml() elif re.search('Window|wx',mode,re.IGNORECASE): try: import wx import wx.html except: print 'Cannot locate wx, please add to sys.path' app = wx.App(False) frame=wx.Frame(None) html_window=wx.html.HtmlWindow(frame) html_window.SetPage(str(self.to_HTML())) frame.Show() app.MainLoop()
def to_HTML(
self, XSLT=None)
Inheritance:
VisaInstrument
.to_HTML
Returns HTML string by applying a XSL to the XML document
def to_HTML(self,XSLT=None): """ Returns HTML string by applying a XSL to the XML document""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] XSL_data=etree.parse(XSLT) XSL_transform=etree.XSLT(XSL_data) HTML=XSL_transform(etree.XML(self.document.toxml())) return str(HTML)
def update_current_state(
self)
Inheritance:
VisaInstrument
.update_current_state
def update_current_state(self): self.current_state=self.get_state()
def update_document(
self)
Inheritance:
VisaInstrument
.update_document
Updates the attribute document from the self.etree.
def update_document(self): """Updates the attribute document from the self.etree. """ self.document=xml.dom.minidom.parseString(etree.tostring(self.etree))
def update_etree(
self)
Inheritance:
VisaInstrument
.update_etree
Updates the attribute etree. Should be called anytime the xml content is changed
def update_etree(self): "Updates the attribute etree. Should be called anytime the xml content is changed" self.etree = etree.fromstring(self.document.toxml())
def write(
self, command)
Inheritance:
VisaInstrument
.write
Writes command to instrument
def write(self,command): "Writes command to instrument" return self.resource.write(command)
class VNA
Control class for a linear VNA. The .measure_sparameters ans .measure_switch_terms return a S2PV1 class that can be saved, printed or have a simple plot using show(). The attribute frequency_list stores the frequency points as Hz.
class VNA(VisaInstrument): """Control class for a linear VNA. The .measure_sparameters ans .measure_switch_terms return a S2PV1 class that can be saved, printed or have a simple plot using show(). The attribute frequency_list stores the frequency points as Hz.""" def __init__(self, resource_name=None, **options): """Initializes the E8631A control class""" defaults = {"state_directory": os.getcwd(), "frequency_units": "Hz"} self.options = {} for key, value in defaults.iteritems(): self.options[key] = value for key, value in options.iteritems(): self.options[key] = value VisaInstrument.__init__(self, resource_name, **self.options) self.power = self.get_power() self.IFBW = self.get_IFBW() self.frequency_units = self.options["frequency_units"] self.frequency_table = [] # this should be if SENS:SWE:TYPE? is LIN or LOG self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] def initialize(self, **options): """Intializes the system""" defaults = {"reset": True} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options: initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'S11',S11") self.write("DISPlay:WINDow1:TRACe1:FEED 'S11'") self.write("CALCulate:PARameter:DEFine 'S12',S12") self.write("DISPlay:WINDow1:TRACe2:FEED 'S12'") self.write("CALCulate:PARameter:DEFine 'S21',S21") self.write("DISPlay:WINDow1:TRACe3:FEED 'S21'") self.write("CALCulate:PARameter:DEFine 'S22',S22") self.write("DISPlay:WINDow1:TRACe4:FEED 'S22'") self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] def set_power(self, power): """Sets the power of the Instrument in dbm""" self.write('SOUR:POW {0}'.format(power)) def get_power(self): "Returns the power of the instrument in dbm" return self.query('SOUR:POW?') def get_sweep_type(self): "Returns the current sweep type. It can be LIN, LOG, or SEG" return self.query("SENS:SWE:TYPE?") def set_IFBW(self, ifbw): """Sets the IF Bandwidth of the instrument in Hz""" self.write('SENS:BAND {0}'.format(ifbw)) self.write('SENS:BAND:TRAC OFF') self.IFBW = ifbw def get_IFBW(self): """Returns the IFBW of the instrument in Hz""" ifbw = float(self.query('SENS:BAND?')) self.IFBW = ifbw return ifbw def set_frequency_units(self, frequency_units="Hz"): """Sets the frequency units of the class, all values are still written to the VNA as Hz and the attrbiute frequncy_list is in Hz, however all commands that deal with sweeps and measurements will be in units""" for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): self.frequency_units = unit def add_segment(self, start, stop=None, number_points=None, step=None, frequency_units="Hz"): """Sets the VNA to a segment mode and appends a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz. """ # first handle the start only case if stop is None and number_points is None: stop = start number_points = 1 # fix the frequency units for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): start = start * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] stop = stop * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] if step: step = step * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] self.frequency_units = unit # handle creating step and number of points if number_points is None and not step is None: number_points = round((stop - start) / step) + 1 elif number_points is None: number_points = 201 # I don't like the default for n_points this far down in the code step = (stop - start) / (number_points - 1) else: step = (stop - start) / (number_points - 1) # append the new segment to self.frequency_table and fix any strangeness self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table[:]) # update the frequency_list frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list # now we write the segment to the instrument if not re.search("SEG", self.get_sweep_type(), re.IGNORECASE): self.write('SENS:SWE:TYPE SEGM') # now get the number of segments and add or delete the right amount to make it line up with self.frequency_table # This routine is broken number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) print("{0} is {1}".format("number_segments", number_segments)) if len(self.frequency_table) < number_segments: difference = number_segments - len(self.frequency_table) max_segment = number_segments while (difference != 0): self.write("SENS:SEGM{0}:DEL".format(max_segment)) max_segment -= 1 difference -= 1 elif len(self.frequency_table) > number_segments: difference = len(self.frequency_table) - number_segments max_segment = number_segments + 1 print("{0} is {1}".format("difference", difference)) while (difference != 0): self.write("SENS:SEGM{0}:ADD".format(max_segment)) max_segment += 1 difference -= 1 print("{0} is {1}".format("difference", difference)) else: pass for row_index, row in enumerate(self.frequency_table[:]): [start, stop, number_points] = [row["start"], row["stop"], row["number_points"]] # SENSe<cnum>:SEGMent<snum>:SWEep:POINts <num> self.write("SENS:SEGM{0}:FREQ:START {1}".format(row_index + 1, start)) self.write("SENS:SEGM{0}:FREQ:STOP {1}".format(row_index + 1, stop)) self.write("SENS:SEGM{0}:SWE:POIN {1}".format(row_index + 1, number_points)) self.write("SENS:SEGM{0}:STAT ON".format(row_index + 1)) def write_frequency_table(self, frequency_table=None): """Writes frequency_table to the instrument, the frequency table should be in the form [{start:,stop:,number_points:}..] or None""" if frequency_table is None: frequency_table = self.frequency_table[:] for row_index, row in enumerate(frequency_table[:]): [start, stop, number_points] = [row["start"], row["stop"], row["number_points"]] # SENSe<cnum>:SEGMent<snum>:SWEep:POINts <num> self.write("SENS:SEGM{0}:FREQ:START {1}".format(row_index + 1, start)) self.write("SENS:SEGM{0}:FREQ:STOP {1}".format(row_index + 1, stop)) self.write("SENS:SEGM{0}:SWE:POIN {1}".format(row_index + 1, number_points)) self.write("SENS:SEGM{0}:STAT ON".format(row_index + 1)) def set_frequency(self, start, stop=None, number_points=None, step=None, type='LIN', frequency_units="Hz"): """Sets the VNA to a linear mode and creates a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz. """ if stop is None and number_points is None: stop = start number_points = 1 for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): start = start * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] stop = stop * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] if step: step = step * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] self.frequency_units = unit if number_points is None and not step is None: number_points = round((stop - start) / step) + 1 if re.search("LIN", type, re.IGNORECASE): self.write('SENS:SWE:TYPE LIN') self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LOG", type, re.IGNORECASE): self.write('SENS:SWE:TYPE LOG') logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) else: self.write('SENS:SWE:TYPE LIN') self.frequency_list = map(lambda x: round(x, ndigits=3), np.linspace(start, stop, number_points).tolist()) self.write("SENS:FREQ:START {0}".format(start)) self.write("SENS:FREQ:STOP {0}".format(stop)) self.write("SENS:SWE:POIN {0}".format(number_points)) def get_frequency(self): "Returns the frequency in python list format" return self.frequency_list def is_busy(self): """Checks if the instrument is currently doing something and returns a boolean value""" opc = bool(self.resource.query("*OPC?")) return not opc def clear_window(self, window=1): """Clears the window of traces. Does not delete the variables""" string_response = self.query("DISPlay:WINDow{0}:CATalog?".format(window)) traces = string_response.split(",") for trace in traces: self.write("DISP:WIND{0}:TRAC{1}:DEL".format(window, trace)) def measure_switch_terms(self, **options): """Measures switch terms and returns a s2p table in forward and reverse format""" defaults = {"view_trace": True} self.measure_switch_term_options = {} for key, value in defaults.iteritems(): self.measure_switch_term_options[key] = value for key, value in options: self.measure_switch_term_options[key] = value # this resets the traces to be based on swith terms # Set VS to be remotely triggered by GPIB self.write("SENS:HOLD:FUNC HOLD") self.write("TRIG:REM:TYP CHAN") # Set the Channel to have 2 Traces self.write("CALC1:PAR:COUN 2") # Trace 1 This is port 2 or Forward Switch Terms self.write("CALC1:PAR:DEF 'FWD',R2,1") # note this command is different for vector star A2,B2 if self.measure_switch_term_options["view_trace"]: self.write("DISPlay:WINDow1:TRACe5:FEED 'FWD'") # Trace 2 This is port 1 or Reverse Switch Terms self.write("CALC1:PAR:DEF 'REV',R1,2") if self.measure_switch_term_options["view_trace"]: self.write("DISPlay:WINDow1:TRACe6:FEED 'REV'") # Select Channel self.write("CALC1:SEL;") self.write("ABORT;TRIG:SING;") # Sleep for the duration of the scan time.sleep(len(self.frequency_list) * 2.5 / float(self.IFBW)) # wait for other functions to be completed # while self.is_busy(): # time.sleep(.01) # Set the read format self.write("FORM:ASC,0") # Read in the data self.write("CALC:PAR:SEL FWD;") foward_switch_string = self.query("CALC:DATA? SDATA") while self.is_busy(): time.sleep(.01) self.write("CALC:PAR:SEL REV;") reverse_switch_string = self.query("CALC:DATA? SDATA") # Now parse the string foward_switch_list = foward_switch_string.replace("\n", "").split(",") reverse_switch_list = reverse_switch_string.replace("\n", "").split(",") real_foward = foward_switch_list[0::2] imaginary_forward = foward_switch_list[1::2] real_reverse = reverse_switch_list[0::2] imaginary_reverse = reverse_switch_list[1::2] switch_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency, real_foward[index], imaginary_forward[index], real_reverse[index], imaginary_reverse[index], 0, 0, 0, 0] new_row = map(lambda x: float(x), new_row) switch_data.append(new_row) option_line = "# Hz S RI R 50" # add some options here about auto saving # do we want comment options? s2p = S2PV1(None, option_line=option_line, data=switch_data) s2p.change_frequency_units(self.frequency_units) return s2p def measure_sparameters(self, **options): """Triggers a single sparameter measurement for all 4 parameters and returns a SP2V1 object""" defaults = {"trigger": "single"} self.measure_sparameter_options = {} for key, value in defaults.iteritems(): self.measure_sparameter_options[key] = value for key, value in options: self.measure_sparameter_options[key] = value if self.measure_sparameter_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the Sparameter lists self.write('CALC:PAR:SEL S11') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s11_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S12') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s12_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S21') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s21_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S22') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s22_string = self.query('CALC:DATA? SDATA') # String Parsing s11_list = s11_string.replace("\n", "").split(",") s12_list = s12_string.replace("\n", "").split(",") s21_list = s21_string.replace("\n", "").split(",") s22_list = s22_string.replace("\n", "").split(",") # Construct a list of lists that is data in RI format reS11 = s11_list[0::2] imS11 = s11_list[1::2] reS12 = s12_list[0::2] imS12 = s12_list[1::2] reS21 = s21_list[0::2] imS21 = s21_list[1::2] reS22 = s22_list[0::2] imS22 = s22_list[1::2] sparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency, reS11[index], imS11[index], reS21[index], imS21[index], reS12[index], imS12[index], reS22[index], imS22[index]] new_row = map(lambda x: float(x), new_row) sparameter_data.append(new_row) option_line = "# Hz S RI R 50" # add some options here about auto saving # do we want comment options? s2p = S2PV1(None, option_line=option_line, data=sparameter_data) s2p.change_frequency_units(self.frequency_units) return s2p def initialize_w2p(self,**options): """Initializes the system for w2p acquisition""" defaults = {"reset": True, "port1": 1,"port2":2, "b_name_list": ["A", "B", "C", "D"]} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") b1_name = initialize_options["b_name_list"][initialize_options["port1"] - 1] b2_name= initialize_options["b_name_list"][initialize_options["port2"] - 1] # Initialize Port 1 traces A1_D1,B1_D1,B2_D1 self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'A{0}_D{0}',R{0},{0}".format(initialize_options["port1"])) self.write("DISPlay:WINDow1:TRACe1:FEED 'A{0}_D{0}'".format(initialize_options["port1"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{0}',{1},{0}".format(initialize_options["port1"],b1_name)) self.write("DISPlay:WINDow1:TRACe2:FEED 'B{0}_D{0}'".format(initialize_options["port1"])) self.write("CALCulate:PARameter:DEFine 'A{1}_D{0}',R{1},{0}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe3:FEED 'A{1}_D{0}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{1}_D{0}',{2},{0}".format(initialize_options["port1"], initialize_options["port2"], b2_name)) self.write("DISPlay:WINDow1:TRACe4:FEED 'B{1}_D{0}'".format(initialize_options["port1"], initialize_options["port2"])) # Initialize Port 2 Traces A1_D2,B1_D2, self.write("CALCulate:PARameter:DEFine 'A{0}_D{1}',R{0},{1}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe5:FEED 'A{0}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{1}',{2},{1}".format(initialize_options["port1"], initialize_options["port2"], b1_name)) self.write("DISPlay:WINDow1:TRACe6:FEED 'B{0}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'A{1}_D{1}',R{1},{1}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe7:FEED 'A{1}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{1}_D{1}',{2},{1}".format(initialize_options["port1"], initialize_options["port2"], b2_name)) self.write("DISPlay:WINDow1:TRACe8:FEED 'B{1}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.sweep_type = self.get_sweep_type() self.frequency_list=self.get_frequency_list() def initialize_w1p(self, **options): """Initializes the system for w1p acquisition, default works for ZVA""" defaults = {"reset": True, "port": 1, "b_name_list": ["A", "B", "C", "D"],"source_port":1} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") b_name = initialize_options["b_name_list"][initialize_options["port"] - 1] self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'A{0}_D{0}',R{0}".format(initialize_options["port"])) self.write("DISPlay:WINDow1:TRACe1:FEED 'A{0}_D{0}'".format(initialize_options["port"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{0}',{1}".format(initialize_options["port"], b_name)) self.write("DISPlay:WINDow1:TRACe2:FEED 'B{0}_D{0}'".format(initialize_options["port"])) self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] def get_frequency_list(self): "Returns the frequency list as read from the VNA" self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] return self.frequency_list[:] def measure_w1p(self, **options): """Triggers a single w1p measurement for a specified port and returns a w1p object.""" defaults = {"trigger": "single", "port": 1, "b_name_list": ["A", "B", "C", "D"], "w1p_options": None} self.measure_w1p_options = {} for key, value in defaults.iteritems(): self.measure_w1p_options[key] = value for key, value in options.iteritems(): self.measure_w1p_options[key] = value if self.measure_w1p_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the A and Blists self.write('CALC:PAR:SEL A{0}_D{0}'.format(self.measure_w1p_options["port"])) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) a_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL B{0}_D{0}'.format(self.measure_w1p_options["port"])) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) b_string = self.query('CALC:DATA? SDATA') # String Parsing a_list = a_string.replace("\n", "").split(",") b_list = b_string.replace("\n", "").split(",") # Construct a list of lists that is data in RI format re_a = a_list[0::2] im_a = a_list[1::2] re_b = b_list[0::2] im_b = b_list[1::2] wparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency / 10. ** 9, re_a[index], im_a[index], re_b[index], im_b[index]] new_row = map(lambda x: float(x), new_row) wparameter_data.append(new_row) column_names = ["Frequency", "reA1_D1", "imA1_D1", "reB1_D1", "imB1_D1"] # add some options here about auto saving # do we want comment options? options = {"column_names_begin_token": "!", "data_delimiter": " ", "column_names": column_names, "data": wparameter_data, "specific_descriptor": "Wave_Parameters", "general_descriptor": "One_Port", "extension": "w1p"} if self.measure_w1p_options["w1p_options"]: for key,value in self.measure_w1p_options["w1p_options"].iteritems(): options[key]=value w1p = AsciiDataTable(None, **options) return w1p def measure_w2p(self, **options): """Triggers a single w2p measurement for a specified port and returns a w2p object.""" defaults = {"trigger": "single", "port1": 1,"port2":2, "b_name_list": ["A", "B", "C", "D"], "w2p_options": None} self.measure_w2p_options = {} for key, value in defaults.iteritems(): self.measure_w2p_options[key] = value for key, value in options.iteritems(): self.measure_w2p_options[key] = value if self.measure_w2p_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the A and B lists drive port 1 # Note this could be a loop over the list = [a1_d1,b1_d1,b2_d1...,b2_d2] waveparameter_names=[] for drive_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for detect_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for receiver in ["A","B"]: waveparameter_names.append("{0}{1}_D{2}".format(receiver,detect_port,drive_port)) # now get data for all of them all_wave_raw_string=[] for waveparameter in waveparameter_names: self.write('CALC:PAR:SEL {0}'.format(waveparameter)) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) all_wave_raw_string .append(self.query('CALC:DATA? SDATA')) # String Parsing all_wave_list=map(lambda x:x.replace("\n","").split(","),all_wave_raw_string) # Construct a list of lists that is data in RI format re_all_wave_list = [a_list[0::2] for a_list in all_wave_list] im_all_wave_list = [a_list[1::2] for a_list in all_wave_list] wparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): re_row=[re[index] for re in re_all_wave_list ] im_row=[im[index] for im in im_all_wave_list] wave_row=[] for index,value in enumerate(re_row): wave_row.append(value) wave_row.append(im_row[index]) new_row = [frequency / 10. ** 9]+wave_row new_row = map(lambda x: float(x), new_row) wparameter_data.append(new_row) waveparameter_column_names=[] for drive_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for detect_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for receiver in ["A","B"]: for complex_type in ["re","im"]: waveparameter_column_names.append("{3}{0}{1}_D{2}".format(receiver, detect_port, drive_port, complex_type)) column_names = ["Frequency"]+waveparameter_column_names # add some options here about auto saving # do we want comment options? options = {"column_names_begin_token": "!", "data_delimiter": " ", "column_names": column_names, "data": wparameter_data, "specific_descriptor": "Wave_Parameters", "general_descriptor": "Two_Port", "extension": "w2p"} if self.measure_w2p_options["w2p_options"]: for key,value in self.measure_w2p_options["w2p_options"].iteritems(): options[key]=value w2p = AsciiDataTable(None, **options) return w2p
Ancestors (in MRO)
- VNA
- VisaInstrument
- Code.DataHandlers.XMLModels.InstrumentSheet
- Code.DataHandlers.XMLModels.XMLBase
Instance variables
var IFBW
var frequency_table
var frequency_units
var power
var sweep_type
Methods
def __init__(
self, resource_name=None, **options)
Inheritance:
VisaInstrument
.__init__
Initializes the E8631A control class
def __init__(self, resource_name=None, **options): """Initializes the E8631A control class""" defaults = {"state_directory": os.getcwd(), "frequency_units": "Hz"} self.options = {} for key, value in defaults.iteritems(): self.options[key] = value for key, value in options.iteritems(): self.options[key] = value VisaInstrument.__init__(self, resource_name, **self.options) self.power = self.get_power() self.IFBW = self.get_IFBW() self.frequency_units = self.options["frequency_units"] self.frequency_table = [] # this should be if SENS:SWE:TYPE? is LIN or LOG self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = []
def add_entry(
self, tag_name, text=None, description='Specific', **attribute_dictionary)
Inheritance:
VisaInstrument
.add_entry
Adds an entry to the instrument sheet.
def add_entry(self,tag_name,text=None,description='Specific',**attribute_dictionary): """ Adds an entry to the instrument sheet.""" specific_match=re.compile('Specific',re.IGNORECASE) general_match=re.compile('General',re.IGNORECASE) if re.search(specific_match,description): description_node=self.document.getElementsByTagName('Specific_Information')[0] elif re.search(general_match,description): description_node=self.document.getElementsByTagName('General_Information')[0] new_entry=self.document.createElement(tag_name) if not text is None: text_node=self.document.createTextNode(tag_name) new_entry.appendChild(text_node) for key,value in attribute_dictionary.iteritems(): new_attribute=self.document.creatAttribute(key) new_entry.setAttributeNode(new_attribute) new_entry.setAttribute(key,str(value)) description_node.appendChild(new_entry)
def add_segment(
self, start, stop=None, number_points=None, step=None, frequency_units='Hz')
Sets the VNA to a segment mode and appends a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz.
def add_segment(self, start, stop=None, number_points=None, step=None, frequency_units="Hz"): """Sets the VNA to a segment mode and appends a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz. """ # first handle the start only case if stop is None and number_points is None: stop = start number_points = 1 # fix the frequency units for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): start = start * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] stop = stop * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] if step: step = step * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] self.frequency_units = unit # handle creating step and number of points if number_points is None and not step is None: number_points = round((stop - start) / step) + 1 elif number_points is None: number_points = 201 # I don't like the default for n_points this far down in the code step = (stop - start) / (number_points - 1) else: step = (stop - start) / (number_points - 1) # append the new segment to self.frequency_table and fix any strangeness self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table[:]) # update the frequency_list frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list # now we write the segment to the instrument if not re.search("SEG", self.get_sweep_type(), re.IGNORECASE): self.write('SENS:SWE:TYPE SEGM') # now get the number of segments and add or delete the right amount to make it line up with self.frequency_table # This routine is broken number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) print("{0} is {1}".format("number_segments", number_segments)) if len(self.frequency_table) < number_segments: difference = number_segments - len(self.frequency_table) max_segment = number_segments while (difference != 0): self.write("SENS:SEGM{0}:DEL".format(max_segment)) max_segment -= 1 difference -= 1 elif len(self.frequency_table) > number_segments: difference = len(self.frequency_table) - number_segments max_segment = number_segments + 1 print("{0} is {1}".format("difference", difference)) while (difference != 0): self.write("SENS:SEGM{0}:ADD".format(max_segment)) max_segment += 1 difference -= 1 print("{0} is {1}".format("difference", difference)) else: pass for row_index, row in enumerate(self.frequency_table[:]): [start, stop, number_points] = [row["start"], row["stop"], row["number_points"]] # SENSe<cnum>:SEGMent<snum>:SWEep:POINts <num> self.write("SENS:SEGM{0}:FREQ:START {1}".format(row_index + 1, start)) self.write("SENS:SEGM{0}:FREQ:STOP {1}".format(row_index + 1, stop)) self.write("SENS:SEGM{0}:SWE:POIN {1}".format(row_index + 1, number_points)) self.write("SENS:SEGM{0}:STAT ON".format(row_index + 1))
def ask(
self, command)
Inheritance:
VisaInstrument
.ask
Writes command and then reads a response
def ask(self,command): "Writes command and then reads a response" return self.resource.query(command)
def clear_window(
self, window=1)
Clears the window of traces. Does not delete the variables
def clear_window(self, window=1): """Clears the window of traces. Does not delete the variables""" string_response = self.query("DISPlay:WINDow{0}:CATalog?".format(window)) traces = string_response.split(",") for trace in traces: self.write("DISP:WIND{0}:TRAC{1}:DEL".format(window, trace))
def close(
self)
Inheritance:
VisaInstrument
.close
Closes the VISA session
def close(self): """Closes the VISA session""" self.resource_manager.close()
def get_IFBW(
self)
Returns the IFBW of the instrument in Hz
def get_IFBW(self): """Returns the IFBW of the instrument in Hz""" ifbw = float(self.query('SENS:BAND?')) self.IFBW = ifbw return ifbw
def get_frequency(
self)
Returns the frequency in python list format
def get_frequency(self): "Returns the frequency in python list format" return self.frequency_list
def get_frequency_list(
self)
Returns the frequency list as read from the VNA
def get_frequency_list(self): "Returns the frequency list as read from the VNA" self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = [] return self.frequency_list[:]
def get_image_path(
self)
Inheritance:
VisaInstrument
.get_image_path
Tries to return the image path, requires image to be in
def get_image_path(self): """Tries to return the image path, requires image to be in <Image href="http://132.163.53.152:8080/home_media/img/Fischione_1040.jpg"/> format""" # Take the first thing called Image image_node=self.document.getElementsByTagName('Image')[0] image_path=image_node.getAttribute('href') return image_path
def get_power(
self)
Returns the power of the instrument in dbm
def get_power(self): "Returns the power of the instrument in dbm" return self.query('SOUR:POW?')
def get_query_dictionary(
self)
Inheritance:
VisaInstrument
.get_query_dictionary
Returns a set:query dictionary if there is a State_Commands element
def get_query_dictionary(self): """ Returns a set:query dictionary if there is a State_Commands element""" try: state_commands=self.document.getElementsByTagName('State_Commands')[0] state_query_dictionary=dict([(str(node.getAttribute('Set') ),str(node.getAttribute('Query'))) for node in state_commands.childNodes if node.nodeType is \ NODE_TYPE_DICTIONARY['ELEMENT_NODE']]) return state_query_dictionary except: raise
def get_state(
self, state_query_dictionary=None, state_query_table=None)
Inheritance:
VisaInstrument
.get_state
Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet
def get_state(self,state_query_dictionary=None,state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary)==0 : state_query_dictionary=self.DEFAULT_STATE_QUERY_DICTIONARY state=dict([(state_command,self.query(str(query)).replace("\n","")) for state_command,query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table=sorted(state_query_table,key=lambda x:int(x["Index"])) state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] index=state_row["Index"] state.append({"Set":set,"Value":self.query(query).replace("\n",""),"Index":index}) return state else: state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] state.append({"Set":set,"Value":self.query(query).replace("\n","")}) return state
def get_sweep_type(
self)
Returns the current sweep type. It can be LIN, LOG, or SEG
def get_sweep_type(self): "Returns the current sweep type. It can be LIN, LOG, or SEG" return self.query("SENS:SWE:TYPE?")
def initialize(
self, **options)
Intializes the system
def initialize(self, **options): """Intializes the system""" defaults = {"reset": True} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options: initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'S11',S11") self.write("DISPlay:WINDow1:TRACe1:FEED 'S11'") self.write("CALCulate:PARameter:DEFine 'S12',S12") self.write("DISPlay:WINDow1:TRACe2:FEED 'S12'") self.write("CALCulate:PARameter:DEFine 'S21',S21") self.write("DISPlay:WINDow1:TRACe3:FEED 'S21'") self.write("CALCulate:PARameter:DEFine 'S22',S22") self.write("DISPlay:WINDow1:TRACe4:FEED 'S22'") self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = []
def initialize_w1p(
self, **options)
Initializes the system for w1p acquisition, default works for ZVA
def initialize_w1p(self, **options): """Initializes the system for w1p acquisition, default works for ZVA""" defaults = {"reset": True, "port": 1, "b_name_list": ["A", "B", "C", "D"],"source_port":1} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") b_name = initialize_options["b_name_list"][initialize_options["port"] - 1] self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'A{0}_D{0}',R{0}".format(initialize_options["port"])) self.write("DISPlay:WINDow1:TRACe1:FEED 'A{0}_D{0}'".format(initialize_options["port"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{0}',{1}".format(initialize_options["port"], b_name)) self.write("DISPlay:WINDow1:TRACe2:FEED 'B{0}_D{0}'".format(initialize_options["port"])) self.sweep_type = self.get_sweep_type() if re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LIN", self.sweep_type, re.IGNORECASE): start = float(self.query("SENS:FREQ:START?").replace("\n", "")) stop = float(self.query("SENS:FREQ:STOP?").replace("\n", "")) number_points = int(self.query("SENS:SWE:POIN?").replace("\n", "")) logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) elif re.search("SEG", self.sweep_type, re.IGNORECASE): number_segments = int(self.query("SENS:SEGM:COUN?").replace("\n", "")) for i in range(number_segments): start = float(self.query("SENS:SEGM{0}:FREQ:START?".format(i + 1)).replace("\n", "")) stop = float(self.query("SENS:SEGM{0}:FREQ:STOP?".format(i + 1)).replace("\n", "")) number_points = int(self.query("SENS:SEGM{0}:SWE:POIN?".format(i + 1)).replace("\n", "")) step = (stop - start) / float(number_points - 1) self.frequency_table.append({"start": start, "stop": stop, "number_points": number_points, "step": step}) self.frequency_table = fix_segment_table(self.frequency_table) frequency_list = [] for row in self.frequency_table[:]: new_list = np.linspace(row["start"], row["stop"], row["number_points"]).tolist() frequency_list = frequency_list + new_list self.frequency_list = frequency_list else: self.frequency_list = []
def initialize_w2p(
self, **options)
Initializes the system for w2p acquisition
def initialize_w2p(self,**options): """Initializes the system for w2p acquisition""" defaults = {"reset": True, "port1": 1,"port2":2, "b_name_list": ["A", "B", "C", "D"]} initialize_options = {} for key, value in defaults.iteritems(): initialize_options[key] = value for key, value in options.iteritems(): initialize_options[key] = value if initialize_options["reset"]: self.write("SYST:FPRESET") b1_name = initialize_options["b_name_list"][initialize_options["port1"] - 1] b2_name= initialize_options["b_name_list"][initialize_options["port2"] - 1] # Initialize Port 1 traces A1_D1,B1_D1,B2_D1 self.write("DISPlay:WINDow1:STATE ON") self.write("CALCulate:PARameter:DEFine 'A{0}_D{0}',R{0},{0}".format(initialize_options["port1"])) self.write("DISPlay:WINDow1:TRACe1:FEED 'A{0}_D{0}'".format(initialize_options["port1"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{0}',{1},{0}".format(initialize_options["port1"],b1_name)) self.write("DISPlay:WINDow1:TRACe2:FEED 'B{0}_D{0}'".format(initialize_options["port1"])) self.write("CALCulate:PARameter:DEFine 'A{1}_D{0}',R{1},{0}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe3:FEED 'A{1}_D{0}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{1}_D{0}',{2},{0}".format(initialize_options["port1"], initialize_options["port2"], b2_name)) self.write("DISPlay:WINDow1:TRACe4:FEED 'B{1}_D{0}'".format(initialize_options["port1"], initialize_options["port2"])) # Initialize Port 2 Traces A1_D2,B1_D2, self.write("CALCulate:PARameter:DEFine 'A{0}_D{1}',R{0},{1}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe5:FEED 'A{0}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{0}_D{1}',{2},{1}".format(initialize_options["port1"], initialize_options["port2"], b1_name)) self.write("DISPlay:WINDow1:TRACe6:FEED 'B{0}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'A{1}_D{1}',R{1},{1}".format(initialize_options["port1"], initialize_options["port2"] )) self.write("DISPlay:WINDow1:TRACe7:FEED 'A{1}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.write("CALCulate:PARameter:DEFine 'B{1}_D{1}',{2},{1}".format(initialize_options["port1"], initialize_options["port2"], b2_name)) self.write("DISPlay:WINDow1:TRACe8:FEED 'B{1}_D{1}'".format(initialize_options["port1"], initialize_options["port2"])) self.sweep_type = self.get_sweep_type() self.frequency_list=self.get_frequency_list()
def is_busy(
self)
Checks if the instrument is currently doing something and returns a boolean value
def is_busy(self): """Checks if the instrument is currently doing something and returns a boolean value""" opc = bool(self.resource.query("*OPC?")) return not opc
def load_state(
self, file_path)
Inheritance:
VisaInstrument
.load_state
Loads a state from a file.
def load_state(self,file_path): """Loads a state from a file.""" #TODO put a UDT to state_table state_model=InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary())
def measure_sparameters(
self, **options)
Triggers a single sparameter measurement for all 4 parameters and returns a SP2V1 object
def measure_sparameters(self, **options): """Triggers a single sparameter measurement for all 4 parameters and returns a SP2V1 object""" defaults = {"trigger": "single"} self.measure_sparameter_options = {} for key, value in defaults.iteritems(): self.measure_sparameter_options[key] = value for key, value in options: self.measure_sparameter_options[key] = value if self.measure_sparameter_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the Sparameter lists self.write('CALC:PAR:SEL S11') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s11_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S12') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s12_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S21') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s21_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL S22') self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) s22_string = self.query('CALC:DATA? SDATA') # String Parsing s11_list = s11_string.replace("\n", "").split(",") s12_list = s12_string.replace("\n", "").split(",") s21_list = s21_string.replace("\n", "").split(",") s22_list = s22_string.replace("\n", "").split(",") # Construct a list of lists that is data in RI format reS11 = s11_list[0::2] imS11 = s11_list[1::2] reS12 = s12_list[0::2] imS12 = s12_list[1::2] reS21 = s21_list[0::2] imS21 = s21_list[1::2] reS22 = s22_list[0::2] imS22 = s22_list[1::2] sparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency, reS11[index], imS11[index], reS21[index], imS21[index], reS12[index], imS12[index], reS22[index], imS22[index]] new_row = map(lambda x: float(x), new_row) sparameter_data.append(new_row) option_line = "# Hz S RI R 50" # add some options here about auto saving # do we want comment options? s2p = S2PV1(None, option_line=option_line, data=sparameter_data) s2p.change_frequency_units(self.frequency_units) return s2p
def measure_switch_terms(
self, **options)
Measures switch terms and returns a s2p table in forward and reverse format
def measure_switch_terms(self, **options): """Measures switch terms and returns a s2p table in forward and reverse format""" defaults = {"view_trace": True} self.measure_switch_term_options = {} for key, value in defaults.iteritems(): self.measure_switch_term_options[key] = value for key, value in options: self.measure_switch_term_options[key] = value # this resets the traces to be based on swith terms # Set VS to be remotely triggered by GPIB self.write("SENS:HOLD:FUNC HOLD") self.write("TRIG:REM:TYP CHAN") # Set the Channel to have 2 Traces self.write("CALC1:PAR:COUN 2") # Trace 1 This is port 2 or Forward Switch Terms self.write("CALC1:PAR:DEF 'FWD',R2,1") # note this command is different for vector star A2,B2 if self.measure_switch_term_options["view_trace"]: self.write("DISPlay:WINDow1:TRACe5:FEED 'FWD'") # Trace 2 This is port 1 or Reverse Switch Terms self.write("CALC1:PAR:DEF 'REV',R1,2") if self.measure_switch_term_options["view_trace"]: self.write("DISPlay:WINDow1:TRACe6:FEED 'REV'") # Select Channel self.write("CALC1:SEL;") self.write("ABORT;TRIG:SING;") # Sleep for the duration of the scan time.sleep(len(self.frequency_list) * 2.5 / float(self.IFBW)) # wait for other functions to be completed # while self.is_busy(): # time.sleep(.01) # Set the read format self.write("FORM:ASC,0") # Read in the data self.write("CALC:PAR:SEL FWD;") foward_switch_string = self.query("CALC:DATA? SDATA") while self.is_busy(): time.sleep(.01) self.write("CALC:PAR:SEL REV;") reverse_switch_string = self.query("CALC:DATA? SDATA") # Now parse the string foward_switch_list = foward_switch_string.replace("\n", "").split(",") reverse_switch_list = reverse_switch_string.replace("\n", "").split(",") real_foward = foward_switch_list[0::2] imaginary_forward = foward_switch_list[1::2] real_reverse = reverse_switch_list[0::2] imaginary_reverse = reverse_switch_list[1::2] switch_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency, real_foward[index], imaginary_forward[index], real_reverse[index], imaginary_reverse[index], 0, 0, 0, 0] new_row = map(lambda x: float(x), new_row) switch_data.append(new_row) option_line = "# Hz S RI R 50" # add some options here about auto saving # do we want comment options? s2p = S2PV1(None, option_line=option_line, data=switch_data) s2p.change_frequency_units(self.frequency_units) return s2p
def measure_w1p(
self, **options)
Triggers a single w1p measurement for a specified port and returns a w1p object.
def measure_w1p(self, **options): """Triggers a single w1p measurement for a specified port and returns a w1p object.""" defaults = {"trigger": "single", "port": 1, "b_name_list": ["A", "B", "C", "D"], "w1p_options": None} self.measure_w1p_options = {} for key, value in defaults.iteritems(): self.measure_w1p_options[key] = value for key, value in options.iteritems(): self.measure_w1p_options[key] = value if self.measure_w1p_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the A and Blists self.write('CALC:PAR:SEL A{0}_D{0}'.format(self.measure_w1p_options["port"])) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) a_string = self.query('CALC:DATA? SDATA') self.write('CALC:PAR:SEL B{0}_D{0}'.format(self.measure_w1p_options["port"])) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) b_string = self.query('CALC:DATA? SDATA') # String Parsing a_list = a_string.replace("\n", "").split(",") b_list = b_string.replace("\n", "").split(",") # Construct a list of lists that is data in RI format re_a = a_list[0::2] im_a = a_list[1::2] re_b = b_list[0::2] im_b = b_list[1::2] wparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): new_row = [frequency / 10. ** 9, re_a[index], im_a[index], re_b[index], im_b[index]] new_row = map(lambda x: float(x), new_row) wparameter_data.append(new_row) column_names = ["Frequency", "reA1_D1", "imA1_D1", "reB1_D1", "imB1_D1"] # add some options here about auto saving # do we want comment options? options = {"column_names_begin_token": "!", "data_delimiter": " ", "column_names": column_names, "data": wparameter_data, "specific_descriptor": "Wave_Parameters", "general_descriptor": "One_Port", "extension": "w1p"} if self.measure_w1p_options["w1p_options"]: for key,value in self.measure_w1p_options["w1p_options"].iteritems(): options[key]=value w1p = AsciiDataTable(None, **options) return w1p
def measure_w2p(
self, **options)
Triggers a single w2p measurement for a specified port and returns a w2p object.
def measure_w2p(self, **options): """Triggers a single w2p measurement for a specified port and returns a w2p object.""" defaults = {"trigger": "single", "port1": 1,"port2":2, "b_name_list": ["A", "B", "C", "D"], "w2p_options": None} self.measure_w2p_options = {} for key, value in defaults.iteritems(): self.measure_w2p_options[key] = value for key, value in options.iteritems(): self.measure_w2p_options[key] = value if self.measure_w2p_options["trigger"] in ["single"]: self.write("INITiate:CONTinuous OFF") self.write("ABORT;INITiate:IMMediate;*wai") # now go to sleep for the time to take the scan time.sleep(len(self.frequency_list) * 2 / float(self.IFBW)) # wait for other functions to be completed while self.is_busy(): time.sleep(.01) # Set the format to ascii and set up sweep definitions self.write('FORM:ASC,0') # First get the A and B lists drive port 1 # Note this could be a loop over the list = [a1_d1,b1_d1,b2_d1...,b2_d2] waveparameter_names=[] for drive_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for detect_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for receiver in ["A","B"]: waveparameter_names.append("{0}{1}_D{2}".format(receiver,detect_port,drive_port)) # now get data for all of them all_wave_raw_string=[] for waveparameter in waveparameter_names: self.write('CALC:PAR:SEL {0}'.format(waveparameter)) self.write('CALC:FORM MLIN') while self.is_busy(): time.sleep(.01) all_wave_raw_string .append(self.query('CALC:DATA? SDATA')) # String Parsing all_wave_list=map(lambda x:x.replace("\n","").split(","),all_wave_raw_string) # Construct a list of lists that is data in RI format re_all_wave_list = [a_list[0::2] for a_list in all_wave_list] im_all_wave_list = [a_list[1::2] for a_list in all_wave_list] wparameter_data = [] for index, frequency in enumerate(self.frequency_list[:]): re_row=[re[index] for re in re_all_wave_list ] im_row=[im[index] for im in im_all_wave_list] wave_row=[] for index,value in enumerate(re_row): wave_row.append(value) wave_row.append(im_row[index]) new_row = [frequency / 10. ** 9]+wave_row new_row = map(lambda x: float(x), new_row) wparameter_data.append(new_row) waveparameter_column_names=[] for drive_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for detect_port in [self.measure_w2p_options["port1"], self.measure_w2p_options["port2"]]: for receiver in ["A","B"]: for complex_type in ["re","im"]: waveparameter_column_names.append("{3}{0}{1}_D{2}".format(receiver, detect_port, drive_port, complex_type)) column_names = ["Frequency"]+waveparameter_column_names # add some options here about auto saving # do we want comment options? options = {"column_names_begin_token": "!", "data_delimiter": " ", "column_names": column_names, "data": wparameter_data, "specific_descriptor": "Wave_Parameters", "general_descriptor": "Two_Port", "extension": "w2p"} if self.measure_w2p_options["w2p_options"]: for key,value in self.measure_w2p_options["w2p_options"].iteritems(): options[key]=value w2p = AsciiDataTable(None, **options) return w2p
def query(
self, command)
Inheritance:
VisaInstrument
.query
Writes command and then reads a response
def query(self,command): "Writes command and then reads a response" return self.resource.query(command)
def read(
self)
Inheritance:
VisaInstrument
.read
Reads from the instrument
def read(self): "Reads from the instrument" return self.resource.read()
def save(
self, path=None)
Inheritance:
VisaInstrument
.save
" Saves as an XML file
def save(self,path=None): """" Saves as an XML file""" if path is None: path=self.path file_out=open(path,'w') file_out.write(str(self)) file_out.close()
def save_HTML(
self, file_path=None, XSLT=None)
Inheritance:
VisaInstrument
.save_HTML
Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')
def save_HTML(self,file_path=None,XSLT=None): """Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] HTML=self.to_HTML(XSLT=XSLT) #print type(HTML) if file_path is None: file_path=self.path.replace('.xml','.html') out_file=open(file_path,'w') out_file.write(HTML) out_file.close()
def save_current_state(
self)
Inheritance:
VisaInstrument
.save_current_state
Saves the state in self.current_state attribute
def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state=self.get_state() self.save_state(None,state_dictionary=self.current_state)
def save_state(
self, state_path=None, state_dictionary=None, state_table=None)
Inheritance:
VisaInstrument
.save_state
Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state
def save_state(self,state_path=None,state_dictionary=None,state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path=auto_name(specific_descriptor=self.name,general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state=InstrumentState(None,**{"state_dictionary":state_dictionary, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state=InstrumentState(None,**{"state_table":state_table, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) else: new_state=InstrumentState(None,**{"state_dictionary":self.get_state(), "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise #pass new_state.save(state_path) return state_path
def set_IFBW(
self, ifbw)
Sets the IF Bandwidth of the instrument in Hz
def set_IFBW(self, ifbw): """Sets the IF Bandwidth of the instrument in Hz""" self.write('SENS:BAND {0}'.format(ifbw)) self.write('SENS:BAND:TRAC OFF') self.IFBW = ifbw
def set_frequency(
self, start, stop=None, number_points=None, step=None, type='LIN', frequency_units='Hz')
Sets the VNA to a linear mode and creates a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz.
def set_frequency(self, start, stop=None, number_points=None, step=None, type='LIN', frequency_units="Hz"): """Sets the VNA to a linear mode and creates a single entry in the frequency table. If start is the only specified parameter sets the entry to start=stop and number_points = 1. If step is specified calculates the number of points and sets start, stop, number_points on the VNA. It also stores the value into the attribute frequency_list. Note this function was primarily tested on an agilent which stores frequency to the nearest mHz. """ if stop is None and number_points is None: stop = start number_points = 1 for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): start = start * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] stop = stop * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] if step: step = step * VNA_FREQUENCY_UNIT_MULTIPLIERS[unit] self.frequency_units = unit if number_points is None and not step is None: number_points = round((stop - start) / step) + 1 if re.search("LIN", type, re.IGNORECASE): self.write('SENS:SWE:TYPE LIN') self.frequency_list = np.linspace(start, stop, number_points).tolist() elif re.search("LOG", type, re.IGNORECASE): self.write('SENS:SWE:TYPE LOG') logspace_start = np.log10(start) logspace_stop = np.log10(stop) self.frequency_list = map(lambda x: round(x, ndigits=3), np.logspace(logspace_start, logspace_stop, num=number_points, base=10).tolist()) else: self.write('SENS:SWE:TYPE LIN') self.frequency_list = map(lambda x: round(x, ndigits=3), np.linspace(start, stop, number_points).tolist()) self.write("SENS:FREQ:START {0}".format(start)) self.write("SENS:FREQ:STOP {0}".format(stop)) self.write("SENS:SWE:POIN {0}".format(number_points))
def set_frequency_units(
self, frequency_units='Hz')
Sets the frequency units of the class, all values are still written to the VNA as Hz and the attrbiute frequncy_list is in Hz, however all commands that deal with sweeps and measurements will be in units
def set_frequency_units(self, frequency_units="Hz"): """Sets the frequency units of the class, all values are still written to the VNA as Hz and the attrbiute frequncy_list is in Hz, however all commands that deal with sweeps and measurements will be in units""" for unit in VNA_FREQUENCY_UNIT_MULTIPLIERS.keys(): if re.match(unit, frequency_units, re.IGNORECASE): self.frequency_units = unit
def set_power(
self, power)
Sets the power of the Instrument in dbm
def set_power(self, power): """Sets the power of the Instrument in dbm""" self.write('SOUR:POW {0}'.format(power))
def set_state(
self, state_dictionary=None, state_table=None)
Inheritance:
VisaInstrument
.set_state
Sets the instrument to the state specified by Command:Value pairs
def set_state(self,state_dictionary=None,state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) for state_command,value in state_dictionary.iteritems(): self.write(state_command+' '+str(value)) self.current_state=self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table=sorted(state_table,key=lambda x:x["Index"]) if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command=state_row["Set"] value=state_row["Value"] self.write(state_command+' '+str(value))
def show(
self, mode='Window')
Inheritance:
VisaInstrument
.show
Displays a XML Document either as formatted text in the command line or in a window (using wx)
def show(self,mode='Window'): """ Displays a XML Document either as formatted text in the command line or in a window (using wx)""" def tag_to_tagName(tag): tagName=tag.replace('<','') tagName=tagName.replace('/','') tagName=tagName.replace('>','') return tagName if mode in ['text','txt','cmd line','cmd']: for node in self.document.getElementsByTagName('Entry'): print 'Entry Index: %s \tDate: %s'%(node.getAttribute('Index'), node.getAttribute('Date')) print node.firstChild.nodeValue elif re.search('xml',mode,re.IGNORECASE): for node in self.document.getElementsByTagName('Entry'): print node.toprettyxml() elif re.search('Window|wx',mode,re.IGNORECASE): try: import wx import wx.html except: print 'Cannot locate wx, please add to sys.path' app = wx.App(False) frame=wx.Frame(None) html_window=wx.html.HtmlWindow(frame) html_window.SetPage(str(self.to_HTML())) frame.Show() app.MainLoop()
def to_HTML(
self, XSLT=None)
Inheritance:
VisaInstrument
.to_HTML
Returns HTML string by applying a XSL to the XML document
def to_HTML(self,XSLT=None): """ Returns HTML string by applying a XSL to the XML document""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] XSL_data=etree.parse(XSLT) XSL_transform=etree.XSLT(XSL_data) HTML=XSL_transform(etree.XML(self.document.toxml())) return str(HTML)
def update_current_state(
self)
Inheritance:
VisaInstrument
.update_current_state
def update_current_state(self): self.current_state=self.get_state()
def update_document(
self)
Inheritance:
VisaInstrument
.update_document
Updates the attribute document from the self.etree.
def update_document(self): """Updates the attribute document from the self.etree. """ self.document=xml.dom.minidom.parseString(etree.tostring(self.etree))
def update_etree(
self)
Inheritance:
VisaInstrument
.update_etree
Updates the attribute etree. Should be called anytime the xml content is changed
def update_etree(self): "Updates the attribute etree. Should be called anytime the xml content is changed" self.etree = etree.fromstring(self.document.toxml())
def write(
self, command)
Inheritance:
VisaInstrument
.write
Writes command to instrument
def write(self,command): "Writes command to instrument" return self.resource.write(command)
def write_frequency_table(
self, frequency_table=None)
Writes frequency_table to the instrument, the frequency table should be in the form [{start:,stop:,number_points:}..] or None
def write_frequency_table(self, frequency_table=None): """Writes frequency_table to the instrument, the frequency table should be in the form [{start:,stop:,number_points:}..] or None""" if frequency_table is None: frequency_table = self.frequency_table[:] for row_index, row in enumerate(frequency_table[:]): [start, stop, number_points] = [row["start"], row["stop"], row["number_points"]] # SENSe<cnum>:SEGMent<snum>:SWEep:POINts <num> self.write("SENS:SEGM{0}:FREQ:START {1}".format(row_index + 1, start)) self.write("SENS:SEGM{0}:FREQ:STOP {1}".format(row_index + 1, stop)) self.write("SENS:SEGM{0}:SWE:POIN {1}".format(row_index + 1, number_points)) self.write("SENS:SEGM{0}:STAT ON".format(row_index + 1))
class VisaInstrument
General Class to communicate with COMM and GPIB instruments This is a blend of the pyvisa resource and an xml description.
class VisaInstrument(InstrumentSheet): """ General Class to communicate with COMM and GPIB instruments This is a blend of the pyvisa resource and an xml description. """ def __init__(self,resource_name=None,**options): """ Initializes the VisaInstrument Class""" defaults={"state_directory":os.getcwd(), "instrument_description_directory":os.path.join(PYMEASURE_ROOT,'Instruments')} self.options={} for key,value in defaults.iteritems(): self.options[key]=value for key,value in options.iteritems(): self.options[key]=value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path=find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self,self.info_path,**self.options) self.info_found=True self.DEFAULT_STATE_QUERY_DICTIONARY=self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY={} self.info_found=False self.instrument_address=resource_name self.name=resource_name.replace(":","_") pass else: self.info_found=False self.DEFAULT_STATE_QUERY_DICTIONARY={} self.instrument_address=resource_name # Create a description for state saving if self.info_found: self.description={'Instrument_Description':self.path} else: self.description={'Instrument_Description':self.instrument_address} self.state_buffer=[] self.STATE_BUFFER_MAX_LENGTH=10 self.resource_manager=visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read self.resource=self.resource_manager.open_resource(self.instrument_address) self.current_state=self.get_state() def write(self,command): "Writes command to instrument" return self.resource.write(command) def read(self): "Reads from the instrument" return self.resource.read() def query(self,command): "Writes command and then reads a response" return self.resource.query(command) def ask(self,command): "Writes command and then reads a response" return self.resource.query(command) def set_state(self,state_dictionary=None,state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) for state_command,value in state_dictionary.iteritems(): self.write(state_command+' '+str(value)) self.current_state=self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table=sorted(state_table,key=lambda x:x["Index"]) if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command=state_row["Set"] value=state_row["Value"] self.write(state_command+' '+str(value)) def get_state(self,state_query_dictionary=None,state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary)==0 : state_query_dictionary=self.DEFAULT_STATE_QUERY_DICTIONARY state=dict([(state_command,self.query(str(query)).replace("\n","")) for state_command,query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table=sorted(state_query_table,key=lambda x:int(x["Index"])) state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] index=state_row["Index"] state.append({"Set":set,"Value":self.query(query).replace("\n",""),"Index":index}) return state else: state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] state.append({"Set":set,"Value":self.query(query).replace("\n","")}) return state def update_current_state(self): self.current_state=self.get_state() def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state=self.get_state() self.save_state(None,state_dictionary=self.current_state) def save_state(self,state_path=None,state_dictionary=None,state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path=auto_name(specific_descriptor=self.name,general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state=InstrumentState(None,**{"state_dictionary":state_dictionary, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state=InstrumentState(None,**{"state_table":state_table, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) else: new_state=InstrumentState(None,**{"state_dictionary":self.get_state(), "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise #pass new_state.save(state_path) return state_path def load_state(self,file_path): """Loads a state from a file.""" #TODO put a UDT to state_table state_model=InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary()) def close(self): """Closes the VISA session""" self.resource_manager.close()
Ancestors (in MRO)
- VisaInstrument
- Code.DataHandlers.XMLModels.InstrumentSheet
- Code.DataHandlers.XMLModels.XMLBase
Instance variables
var STATE_BUFFER_MAX_LENGTH
var current_state
var options
var resource
var resource_manager
var state_buffer
Methods
def __init__(
self, resource_name=None, **options)
Initializes the VisaInstrument Class
def __init__(self,resource_name=None,**options): """ Initializes the VisaInstrument Class""" defaults={"state_directory":os.getcwd(), "instrument_description_directory":os.path.join(PYMEASURE_ROOT,'Instruments')} self.options={} for key,value in defaults.iteritems(): self.options[key]=value for key,value in options.iteritems(): self.options[key]=value # First we try to look up the description and get info from it if DATA_SHEETS: try: self.info_path=find_description(resource_name, directory=self.options["instrument_description_directory"]) InstrumentSheet.__init__(self,self.info_path,**self.options) self.info_found=True self.DEFAULT_STATE_QUERY_DICTIONARY=self.get_query_dictionary() except: print('The information sheet was not found defaulting to address') self.DEFAULT_STATE_QUERY_DICTIONARY={} self.info_found=False self.instrument_address=resource_name self.name=resource_name.replace(":","_") pass else: self.info_found=False self.DEFAULT_STATE_QUERY_DICTIONARY={} self.instrument_address=resource_name # Create a description for state saving if self.info_found: self.description={'Instrument_Description':self.path} else: self.description={'Instrument_Description':self.instrument_address} self.state_buffer=[] self.STATE_BUFFER_MAX_LENGTH=10 self.resource_manager=visa.ResourceManager() # Call the visa instrument class-- this gives ask,write,read self.resource=self.resource_manager.open_resource(self.instrument_address) self.current_state=self.get_state()
def add_entry(
self, tag_name, text=None, description='Specific', **attribute_dictionary)
Adds an entry to the instrument sheet.
def add_entry(self,tag_name,text=None,description='Specific',**attribute_dictionary): """ Adds an entry to the instrument sheet.""" specific_match=re.compile('Specific',re.IGNORECASE) general_match=re.compile('General',re.IGNORECASE) if re.search(specific_match,description): description_node=self.document.getElementsByTagName('Specific_Information')[0] elif re.search(general_match,description): description_node=self.document.getElementsByTagName('General_Information')[0] new_entry=self.document.createElement(tag_name) if not text is None: text_node=self.document.createTextNode(tag_name) new_entry.appendChild(text_node) for key,value in attribute_dictionary.iteritems(): new_attribute=self.document.creatAttribute(key) new_entry.setAttributeNode(new_attribute) new_entry.setAttribute(key,str(value)) description_node.appendChild(new_entry)
def ask(
self, command)
Writes command and then reads a response
def ask(self,command): "Writes command and then reads a response" return self.resource.query(command)
def close(
self)
Closes the VISA session
def close(self): """Closes the VISA session""" self.resource_manager.close()
def get_image_path(
self)
Tries to return the image path, requires image to be in
def get_image_path(self): """Tries to return the image path, requires image to be in <Image href="http://132.163.53.152:8080/home_media/img/Fischione_1040.jpg"/> format""" # Take the first thing called Image image_node=self.document.getElementsByTagName('Image')[0] image_path=image_node.getAttribute('href') return image_path
def get_query_dictionary(
self)
Returns a set:query dictionary if there is a State_Commands element
def get_query_dictionary(self): """ Returns a set:query dictionary if there is a State_Commands element""" try: state_commands=self.document.getElementsByTagName('State_Commands')[0] state_query_dictionary=dict([(str(node.getAttribute('Set') ),str(node.getAttribute('Query'))) for node in state_commands.childNodes if node.nodeType is \ NODE_TYPE_DICTIONARY['ELEMENT_NODE']]) return state_query_dictionary except: raise
def get_state(
self, state_query_dictionary=None, state_query_table=None)
Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet
def get_state(self,state_query_dictionary=None,state_query_table=None): """ Gets the current state of the instrument. get_state accepts any query dictionary in the form state_query_dictionary={"GPIB_SET_COMMAND":"GPIB_QUERY_COMMAND",...} or any state_query_table in the form [{"Set":"GPIB_SET_COMMAND","Query":"GPIB_QUERY_COMMAND","Index":Optional_int_ordering commands, if no state is provided it returns the DEFAULT_STATE_QUERY_DICTIONARY as read in from the InstrumentSheet""" if not state_query_table: if state_query_dictionary is None or len(state_query_dictionary)==0 : state_query_dictionary=self.DEFAULT_STATE_QUERY_DICTIONARY state=dict([(state_command,self.query(str(query)).replace("\n","")) for state_command,query in state_query_dictionary.iteritems()]) return state else: # a state_query_table is a list of dictionaries, each row has at least a Set and Query key but could # have an Index key that denotes order if "Index" in state_query_table[0].keys(): state_query_table=sorted(state_query_table,key=lambda x:int(x["Index"])) state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] index=state_row["Index"] state.append({"Set":set,"Value":self.query(query).replace("\n",""),"Index":index}) return state else: state=[] for state_row in state_query_table: set=state_row["Set"] query=state_row["Query"] state.append({"Set":set,"Value":self.query(query).replace("\n","")}) return state
def load_state(
self, file_path)
Loads a state from a file.
def load_state(self,file_path): """Loads a state from a file.""" #TODO put a UDT to state_table state_model=InstrumentState(file_path) self.set_state(state_table=state_model.get_state_list_dictionary())
def query(
self, command)
Writes command and then reads a response
def query(self,command): "Writes command and then reads a response" return self.resource.query(command)
def read(
self)
Reads from the instrument
def read(self): "Reads from the instrument" return self.resource.read()
def save(
self, path=None)
" Saves as an XML file
def save(self,path=None): """" Saves as an XML file""" if path is None: path=self.path file_out=open(path,'w') file_out.write(str(self)) file_out.close()
def save_HTML(
self, file_path=None, XSLT=None)
Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')
def save_HTML(self,file_path=None,XSLT=None): """Saves a HTML transformation of the XML document using XLST at file_path. Defaults to an XLST in self.options["XSLT"] and file_path=self.path.replace('.xml','.html')""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] HTML=self.to_HTML(XSLT=XSLT) #print type(HTML) if file_path is None: file_path=self.path.replace('.xml','.html') out_file=open(file_path,'w') out_file.write(HTML) out_file.close()
def save_current_state(
self)
Saves the state in self.current_state attribute
def save_current_state(self): """ Saves the state in self.current_state attribute """ self.current_state=self.get_state() self.save_state(None,state_dictionary=self.current_state)
def save_state(
self, state_path=None, state_dictionary=None, state_table=None)
Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state
def save_state(self,state_path=None,state_dictionary=None,state_table=None): """ Saves any state dictionary to an xml file, with state_path, if not specified defaults to autonamed state """ if state_path is None: state_path=auto_name(specific_descriptor=self.name,general_descriptor="State", directory=self.options["state_directory"]) if state_dictionary: new_state=InstrumentState(None,**{"state_dictionary":state_dictionary, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) elif state_table: new_state=InstrumentState(None,**{"state_table":state_table, "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) else: new_state=InstrumentState(None,**{"state_dictionary":self.get_state(), "style_sheet":"./DEFAULT_STATE_STYLE.xsl"}) try: new_state.add_state_description() new_state.append_description(description_dictionary=self.description) except: raise #pass new_state.save(state_path) return state_path
def set_state(
self, state_dictionary=None, state_table=None)
Sets the instrument to the state specified by Command:Value pairs
def set_state(self,state_dictionary=None,state_table=None): """ Sets the instrument to the state specified by Command:Value pairs""" if state_dictionary: if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) for state_command,value in state_dictionary.iteritems(): self.write(state_command+' '+str(value)) self.current_state=self.get_state() if state_table: if "Index" in state_table[0].keys(): state_table=sorted(state_table,key=lambda x:x["Index"]) if len(self.state_buffer)+1<self.STATE_BUFFER_MAX_LENGTH: self.state_buffer.append(self.get_state()) else: self.state_buffer.pop(1) self.state_buffer.insert(-1,self.get_state()) # now we need to write the command for state_row in state_table: # a state row has a set and value state_command=state_row["Set"] value=state_row["Value"] self.write(state_command+' '+str(value))
def show(
self, mode='Window')
Displays a XML Document either as formatted text in the command line or in a window (using wx)
def show(self,mode='Window'): """ Displays a XML Document either as formatted text in the command line or in a window (using wx)""" def tag_to_tagName(tag): tagName=tag.replace('<','') tagName=tagName.replace('/','') tagName=tagName.replace('>','') return tagName if mode in ['text','txt','cmd line','cmd']: for node in self.document.getElementsByTagName('Entry'): print 'Entry Index: %s \tDate: %s'%(node.getAttribute('Index'), node.getAttribute('Date')) print node.firstChild.nodeValue elif re.search('xml',mode,re.IGNORECASE): for node in self.document.getElementsByTagName('Entry'): print node.toprettyxml() elif re.search('Window|wx',mode,re.IGNORECASE): try: import wx import wx.html except: print 'Cannot locate wx, please add to sys.path' app = wx.App(False) frame=wx.Frame(None) html_window=wx.html.HtmlWindow(frame) html_window.SetPage(str(self.to_HTML())) frame.Show() app.MainLoop()
def to_HTML(
self, XSLT=None)
Returns HTML string by applying a XSL to the XML document
def to_HTML(self,XSLT=None): """ Returns HTML string by applying a XSL to the XML document""" if XSLT is None: # For some reason an absolute path tends to break here, maybe a spaces in file names problem XSLT=self.options['style_sheet'] XSL_data=etree.parse(XSLT) XSL_transform=etree.XSLT(XSL_data) HTML=XSL_transform(etree.XML(self.document.toxml())) return str(HTML)
def update_current_state(
self)
def update_current_state(self): self.current_state=self.get_state()
def update_document(
self)
Updates the attribute document from the self.etree.
def update_document(self): """Updates the attribute document from the self.etree. """ self.document=xml.dom.minidom.parseString(etree.tostring(self.etree))
def update_etree(
self)
Updates the attribute etree. Should be called anytime the xml content is changed
def update_etree(self): "Updates the attribute etree. Should be called anytime the xml content is changed" self.etree = etree.fromstring(self.document.toxml())
def write(
self, command)
Writes command to instrument
def write(self,command): "Writes command to instrument" return self.resource.write(command)
class VisaInstrumentError
class VisaInstrumentError(Exception): def __init__(self,*args): Exception.__init__(self,*args)
Ancestors (in MRO)
- VisaInstrumentError
- exceptions.Exception
- exceptions.BaseException
- __builtin__.object
Class variables
var args
var message
Methods
def __init__(
self, *args)
def __init__(self,*args): Exception.__init__(self,*args)
Module variables
var ACTIVE_COMPONENTS
var COMMENT_PATTERN
var DATA_SHEETS
var DEFAULT_FILE_NAME
var DEFAULT_MODE
var EXTENSION_PATTERN
var FORMATS
var FREQUENCY_UNITS
var GENERAL_DESCRIPTORS
var INSTRUMENTS_DEFINED
var INSTRUMENT_TYPES
var METHOD_ALIASES
var MINIMUM_DB_ARG_VALUE
var MINIMUM_DB_VALUE
var NUMBER_MATCH_STRING
var OPTION_LINE_PATTERN
var PARAMETERS
var PIL_AVAILABLE
var PYMEASURE_ROOT
var RTLD_GLOBAL
var RTLD_LOCAL
var S1P_DB_COLUMN_NAMES
var S1P_MA_COLUMN_NAMES
var S1P_RI_COLUMN_NAMES
var S2P_COMPLEX_COLUMN_NAMES
var S2P_DB_COLUMN_DESCRIPTION
var S2P_DB_COLUMN_NAMES
var S2P_MA_COLUMN_DESCRIPTION
var S2P_MA_COLUMN_NAMES
var S2P_NOISE_PARAMETER_COLUMN_NAMES
var S2P_RI_COLUMN_DESCRIPTION
var S2P_RI_COLUMN_NAMES
var SMITHPLOT
var StringTypes
var TESTS_DIRECTORY
var TOUCHSTONE_KEYWORDS
var VNA_FREQUENCY_UNIT_MULTIPLIERS