diff --git a/INSTALL b/INSTALL index 0c0bc8c1..cafcd1e0 100644 --- a/INSTALL +++ b/INSTALL @@ -41,7 +41,7 @@ B) other programs. scipy has many math routines (like fitting), based on numpy. URL: scipy.org (for both numpy and scipy) -3a) ipython (>=0.10) +3a) ipython (>=1.0.0) 3b) pyreadline (>=1.5) enhanced interactive shell for python @@ -58,7 +58,7 @@ B) other programs. libraries used for creating graphical interfaces. URL: pygtk.org -5) pyvisa (1.3) +5) pyvisa (1.3, < 1.6) library for communication with GPIB/USB/SERIAL instruments URL: pyvisa.sourceforge.net/ diff --git a/README b/README index e71cc176..f72df36f 100644 --- a/README +++ b/README @@ -1 +1,5 @@ QT Lab environment + +requirements: +IPython ≥ 1.0.0 +pyVISA < 1.5 diff --git a/instrument_plugins/Agilent_81180A.py b/instrument_plugins/Agilent_81180A.py new file mode 100644 index 00000000..f118dc07 --- /dev/null +++ b/instrument_plugins/Agilent_81180A.py @@ -0,0 +1,220 @@ +# Agilent_81180A.py class, to perform the communication between the Wrapper and the device +# Pablo Asshoff, Dec. 2013 +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import visa +import types +import logging +import numpy + +class Agilent_81180A(Instrument): + ''' + This is the driver for the Agilent_81180A Signal Genarator + + Usage: + Initialize with + = instruments.create('', 'Agilent_81180A', address=', reset=') + ''' + + def __init__(self, name, address, reset=False): + ''' + Initializes the Agilent_81180A, and communicates with the wrapper. + + Input: + name (string) : name of the instrument + address (string) : GPIB address + reset (bool) : resets to default values, default=False + ''' + logging.info(__name__ + ' : Initializing instrument Agilent_81180A') + Instrument.__init__(self, name, tags=['physical']) + + # Add some global constants + self._address = address + self._visainstrument = visa.instrument(self._address) + + self.add_parameter('channel', + flags=Instrument.FLAG_GETSET, units='', type=types.IntType) + self.add_parameter('output', + flags=Instrument.FLAG_GETSET, units='', type=types.StringType) + self.add_parameter('frequency', + flags=Instrument.FLAG_GETSET, units='Hz', minval=1e5, maxval=20e9, type=types.FloatType) + self.add_parameter('voltage', + flags=Instrument.FLAG_GETSET, units='V', minval=0.05, maxval=0.5, type=types.FloatType) + + + self.add_function('reset') + self.add_function ('get_all') + + + if (reset): + self.reset() + else: + self.get_all() + + def reset(self): + ''' + Resets the instrument to default values + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : resetting instrument') + self._visainstrument.write('*RST\n') + self.get_all() + + def get_all(self): + ''' + Reads all implemented parameters from the instrument, + and updates the wrapper. + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : get all') + self.get_channel() + self.get_output() + #self.get_power() + #self.get_phase() + self.get_frequency() + + + def do_set_channel(self, channelnumber): + ''' + Set the active channel + + Input: + channel (integer) : 1 or 2 + + Output: + None + ''' + logging.debug(__name__ + ' : set active channel: %i' % channelnumber) + self._visainstrument.write('INST:SEL %i \n' % channelnumber) + + def do_get_channel(self): + ''' + Reads the active channel from the instrument + + Input: + None + + Output: + Active Channel : 1 or 2 + ''' + logging.debug(__name__ + ' : active channel') + return int(self._visainstrument.ask('INST:SEL?\n')) + + def do_set_output(self, on_off): + ''' + Set the active channel + + Input: + on or off (str) : + + Output: + None + ''' + logging.debug(__name__ + ' : set output of active channel: %s' % on_off) + self._visainstrument.write('OUTP:STAT %s\n' % on_off) + + def do_get_output(self): + ''' + Reads weather the output is on or off from the instrument + + Input: + None + + Output: + On or Off (1/0) + ''' + logging.debug(__name__ + ' : output is on or off') + return str(self._visainstrument.ask('OUTP:STAT?\n')) + + + def do_set_frequency(self, freq): + ''' + Set the frequency of the instrument + + Input: + freq (float) : Frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : set frequency to %f' % freq) + self._visainstrument.write('SOUR:FREQ %f\n' % freq) + + + def do_get_frequency(self): + ''' + Reads the frequency of the signal from the instrument + + Input: + None + + Output: + freq (float) : Frequency in Hz + ''' + logging.debug(__name__ + ' : get frequency') + return float(self._visainstrument.ask('SOUR:FREQ?\n')) + + + + + + + + def do_set_voltage(self, volt): + ''' + Set the voltage of the instrument + + Input: + volt (float) : voltage in V + + Output: + None + ''' + logging.debug(__name__ + ' : set vooltage to %f' % volt) + self._visainstrument.write('SOUR:VOLT %f\n' % volt) + + + def do_get_frequency(self): + ''' + Reads the voltage setting from the instrument + + Input: + None + + Output: + volt (float) : voltage in V + ''' + logging.debug(__name__ + ' : get voltage') + return float(self._visainstrument.ask('SOUR:VOLT?\n')) + + + + + + + diff --git a/instrument_plugins/Agilent_8648C.py b/instrument_plugins/Agilent_8648C.py new file mode 100755 index 00000000..a561d089 --- /dev/null +++ b/instrument_plugins/Agilent_8648C.py @@ -0,0 +1,412 @@ +# Agilent_8648C.py class, to perform the communication between the Wrapper and the device +# Sam Hile , 2011 +# Karsten Beckmann , 2012 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import visa +import types +import logging +import qt + +class Agilent_8648C(Instrument): + ''' + This is the driver for the Agilent 8648C Signal Genarator + + Usage: + Initialize with + = instruments.create('', 'Agilent_8648C', address=', reset=') + ''' + + def __init__(self, name, address, reset=False): + ''' + Initializes the Agilent_8648C, and communicates with the wrapper. + + Input: + name (string) : name of the instrument + address (string) : GPIB address + reset (bool) : resets to default values, default=False + ''' + logging.info(__name__ + ' : Initializing instrument Agilent_8648C') + Instrument.__init__(self, name, tags=['physical']) + + # Add some global constants + self._address = address + self._visainstrument = visa.instrument(self._address) + + # Implemented parameters + self.add_parameter('power', + flags=Instrument.FLAG_GETSET, units='dBm', minval=-136, maxval=13, type=types.FloatType) + self.add_parameter('frequency', + flags=Instrument.FLAG_GETSET, units='MHz', minval=9e-3, maxval=3.2e3, type=types.FloatType) + self.add_parameter('output_status', + flags=Instrument.FLAG_GETSET, type=types.BooleanType) + self.add_parameter('frequency_modulation_status', + flags=Instrument.FLAG_GET, type=types.BooleanType) + self.add_parameter('frequency_modulation_deviation', + flags=Instrument.FLAG_GET, type=types.FloatType, units='Hz') + self.add_parameter('frequency_modulation_source', + flags=Instrument.FLAG_GET, type=types.StringType, + option_list=('INT','EXT')) + self.add_parameter('amplitude_modulation_status', + flags=Instrument.FLAG_GET, type=types.BooleanType) + self.add_parameter('frequency_reference_status', + flags=Instrument.FLAG_GET, type=types.BooleanType) + self.add_parameter('automatic_attenuator_control_status', + flags=Instrument.FLAG_GET, type=types.BooleanType) + + self.add_function('reset') + self.add_function('get_all') + self.add_function('on') + self.add_function('off') +# self.add_function('alc_off') + + self._power_step = 5e-1 + self._power_step_time = 100e-3 + + self._frequency_step = 500e-2 + self._frequency_step_time = 100e-3 + + if (reset): + self.reset() + else: + self.get_all() + + def set_power_ramp(self, power_step, power_step_time): + ''' + Set power ramp settings, default values set in "__init__" + + Input: + power step and power step time + Output: + none + ''' + self._power_step = power_step + self._power_step_time = power_step_time + + def set_frequency_ramp(self, frequency_step, frequency_step_time): + ''' + Set frequency ramp settings, default values set in "__init__" + + Input: + frequency step and frequency step time + Output: + none + ''' + self._frequency_step = frequency_step + self._frequency_step_time = frequency_step_time + + def reset(self): + ''' + Resets the instrument to default values + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : resetting instrument') + self._visainstrument.write('*RST') + self.get_all() + + def get_all(self): + ''' + Reads all implemented parameters from the instrument, + and updates the wrapper. + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : get all') + self.get_power() + self.get_frequency() + self.get_output_status() + self.get_frequency_modulation_status() + self.get_frequency_modulation_deviation() + self.get_frequency_modulation_source() + self.get_amplitude_modulation_status() + self.get_frequency_reference_status() + self.get_automatic_attenuator_control_status() + + def do_get_power(self): + ''' + Reads the power of the signal from the instrument + + Input: + None + + Output: + ampl (float) : power in dBm + ''' + logging.debug(__name__ + ' : get power') + return float(self._visainstrument.ask('POW:AMPL?')) + +# def alc_off(self): +# ''' +# Turn ALC off +# ''' +# logging.debug(__name__ + ' : turn ALC off') +# self._visainstrument.write('POW:ALC OFF') + + + def do_set_power(self, amp): + ''' + Set the power of the signal + + Input: + amp (float) : power in dBm + + Output: + None + ''' + + start_power = self.get_power(1) + + step = self._power_step * cmp(amp, start_power) + step_time = self._power_step_time + power_ramp = [] + if not(step == 0): + Nramp = int(abs((start_power - amp) / step)) + power_ramp = [x * step + start_power for x in range(Nramp + 1)] + power_ramp.append(amp) + else: + power_ramp = [start_power, amp] + + for v in power_ramp: + logging.debug(__name__ + ' : set power to %f dBm' % amp) + self._visainstrument.write('POW:AMPL %s dBm' % v) + qt.msleep(step_time) + self.get_power() + return self.get_power() + + #logging.debug(__name__ + ' : set power to %f dBm' % amp) + #self._visainstrument.write('POW:AMPL %s dBm' % amp) + + def do_get_frequency(self): + ''' + Reads the frequency of the signal from the instrument + + Input: + None + + Output: + freq (float) : Frequency in Hz + ''' + + logging.debug(__name__ + ' : get frequency') + return float(self._visainstrument.ask('FREQ:CW?')) + + def do_set_frequency(self, freq): + ''' + Set the frequency of the instrument + + Input: + freq (float) : Frequency in MHz + + Output: + None + ''' + + start_frequency = self.get_frequency()/1e6 + #print "get_freq"+str(self.get_frequency()) + step = self._frequency_step * cmp(freq, start_frequency) + step_time = self._frequency_step_time + frequency_ramp = [] + if not(step == 0): + Nramp = int(abs((start_frequency - freq) / step)) + #print 'sf'+str(start_frequency) + #print 'gf'+str(freq) + #print 'step'+str(step) + frequency_ramp = [x * step + start_frequency for x in range(Nramp + 1)] + frequency_ramp.append(freq) + else: + frequency_ramp = [start_frequency, freq] + + for v in frequency_ramp: + logging.debug(__name__ + ' : set frequency to %f MHz' % freq) + self._visainstrument.write('FREQ:CW %s MHz' % v) + qt.msleep(step_time) + self.get_frequency() + return self.get_frequency() + + #logging.debug(__name__ + ' : set frequency to %f MHz' % freq) + #self._visainstrument.write('FREQ:CW %s MHz' % v) + + + def do_get_output_status(self): + ''' + Reads the output status from the instrument + + Input: + None + + Output: + status (Boolean) : True or False + ''' + logging.debug(__name__ + ' : get status') + stat = self._visainstrument.ask('OUTP:STAT?') + + if (stat=='1'): + return True + elif (stat=='0'): + return False + else: + raise ValueError('Output status not specified : %s' % stat) + return + + def do_set_output_status(self, status): + ''' + Set the output status of the instrument + + Input: + status (Boolean) : True or False + + Output: + None + ''' + logging.debug(__name__ + ' : set status to %s' % status) +# if status.upper() in ('ON', 'OFF'): +# status = status.upper() +# else: +# raise ValueError('set_status(): can only set on or off') + if status: + self._visainstrument.write('OUTP:STAT ON') + else: + self._visainstrument.write('OUTP:STAT OFF') +# self._visainstrument.write('OUTP:STAT %s' % status) + + def do_get_frequency_modulation_status(self): + ''' + Input: + None + Output: + True or False + ''' + logging.debug(__name__ + ' : get the frequency modulation status.') + answer = self._visainstrument.ask('FM:STAT?') + if answer == '1': + return True + elif answer == '0': + return False + else: + raise ValueError('Frequency modulation status not specified : %s' % answer) + + def do_get_frequency_modulation_deviation(self): + ''' + Input: + None + Output: + Frequency Deviation in Hz + ''' + logging.debug(__name__ + ' : get the frequency modulation deviation.') + answer = self._visainstrument.ask('FM:DEV?') + return float(answer) + + def do_get_frequency_modulation_source(self): + ''' + Input: + None + Output: + INTERNAL + EXTERNAL + ''' + logging.debug(__name__ + ' : get the frequency modulation source.') + answer = self._visainstrument.ask('FM:SOUR?') + if (answer == 'INTERNAL') or (answer == 'EXTERNAL'): + return answer + else: + raise ValueError('Frequency modulation source not specified: %s' % answer) + + def do_get_amplitude_modulation_status(self): + ''' + Get the amplitude modulation status. + Input: + None + Output: + True or False + ''' + logging.debug(__name__ + ' : get the amplitude modulation status.') + answer = self._visainstrument.ask('AM:STAT?') + if answer == '0': + return False + elif answer == '1': + return True + else: + raise ValueError('Amplitude modulation status not specified: %s' % answer) + + def do_get_frequency_reference_status(self): + ''' + Get whether the frequency reference mode is off or on. + Input: + None + Output: + True or False + ''' + logging.debug(__name__ + ' : get the frequency reference status.') + answer = self._visainstrument.ask('FREQ:REF:STAT?') + if answer == '0': + return False + elif answer == '1': + return True + else: + raise ValueError('Frequency reference status not specified: %s' % answer) + + def do_get_automatic_attenuator_control_status(self): + ''' + Get whether the automatic attenuator control is on or off. + Input: + None + Output: + True or False + ''' + logging.debug(__name__ + ' : get the automatic attenuator control status.') + answer = self._visainstrument.ask('POW:ATT:AUTO?') + if answer == '0': + return False + elif answer == '1': + return True + else: + raise ValueError('Automatic attenuator control status not specified: %s' % answer) + + # shortcuts + def off(self): + ''' + Set status to 'off' + + Input: + None + + Output: + None + ''' + self.set_output_status(False) + + def on(self): + ''' + Set status to 'on' + + Input: + None + + Output: + None + ''' + self.set_output_status(True) + diff --git a/instrument_plugins/Agilent_8753E2.py b/instrument_plugins/Agilent_8753E2.py new file mode 100644 index 00000000..7a660f6e --- /dev/null +++ b/instrument_plugins/Agilent_8753E2.py @@ -0,0 +1,262 @@ +# Agilent_8753E2.py class, to perform the communication between the Wrapper and the device +# Pablo Asshoff , 2013 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import visa +import types +import logging +import numpy +import math + +class Agilent_8753E2(Instrument): + ''' + This is the driver for the Agilent 8753E2 Network Analyzer + + Usage: + Initialize with + = instruments.create('name', 'Agilent_8753E2', address='', + reset=) + ''' + + def __init__(self, name, address, reset=False): + ''' + Initializes the Agilent_8753E2, and communicates with the wrapper. + + Input: + name (string) : name of the instrument + address (string) : GPIB address + reset (bool) : resets to default values, default=false + + Output: + None + ''' + logging.info(__name__ + ' : Initializing instrument') + Instrument.__init__(self, name, tags=['physical']) + + self._address = address + self._visainstrument = visa.instrument(self._address) + self._visainstrument.timeout = 1 + + # Add parameters + self.add_parameter('startfrequency', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=9e3, maxval=6e9, + units='Hz', format='%.04e') + self.add_parameter('stopfrequency', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=9e3, maxval=6e9, + units='Hz', format='%.04e') + self.add_parameter('span', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=0, maxval=3e9, + units='Hz', format='%.04e') + + # Add functions + self.add_function('reset') + self.add_function('get_all') + self.add_function('read_trace') +# self.add_function('plot_trace') +# self.add_function('save_trace') + + if reset: + self.reset() + else: + self.get_all() + + # Functions + def reset(self): + ''' + Resets the instrument to default values + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : Resetting instrument') + self._visainstrument.write('*RST;*CLS') # zuvor nur *RST + self.get_all() + + def get_all(self): + ''' + Reads all implemented parameters from the instrument, + and updates the wrapper. + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : reading all settings from instrument') + self.get_startfrequency() + self.get_stopfrequency() + self.get_span() + + def read_trace(self): + ''' + Read a trace + p.427 Manual + + Input: + None + + Output: + trace + ''' + logging.debug(__name__ + ' : performing trace readout') + #self._visainstrument.write('OPC?;SING;') + #only use previous command if single sweep is required, not for readout of display as is. + self._visainstrument.write('FORM4;') + return(self._visainstrument.ask('OUTPFORM;')) + +# def plot_trace(self,trace): +# ''' +# plot the trace returned from read_trace() +# p.427 Manual +# +# Input: +# Trace +# +# Output: +# trace +# ''' +# array1 = trace +# array2 = array1.replace('E','e') +# array2 = array2.replace('\n',',') +# array3 = numpy.fromstring(array2, sep=',') +# y = array3[::2] +# startfreq = self.get_startfrequency() +# stopfreq = self.get_stopfrequency() +# steps = (stopfreq-startfreq)/(len(y)-1) +# x = arange(startfreq,stopfreq+0.001,steps) +# qt.Plot2D(x,y) +# +# def save_trace(self,trace,filename): +# ''' +# plot the trace returned from read_trace() +# p.427 Manual +# +# Input: +# Trace +# +# Output: +# trace +# ''' +# #convert data returned from instrument: +# array1 = trace +# array2 = array1.replace('E','e') +# array2 = array2.replace('\n',',') +# array3 = numpy.fromstring(array2, sep=',') +# y = array3[::2] +# startfreq = self.get_startfrequency() +# stopfreq = self.get_stopfrequency() +# steps = (stopfreq-startfreq)/(len(y)-1) +# x = arange(startfreq,stopfreq+0.001,steps) +# qt.Plot2D(x,y) +# #create a file and save trace: +# f = open(filename, 'w') +# f.write('frequency[Hz] power[dB]') +# for i in range(len(x)): +# f.write(str(x[i])) +# f.write(' ') +# f.write(str(y[i])) +# f.write('\n') +# f.close() + + # communication with machine + def do_get_startfrequency(self): + ''' + Get start frequency from device + + Input: + None + + Output: + startfrequency (float) : start frequency in Hz + ''' + logging.debug(__name__ + ' : reading start frequency from instrument') + return float(self._visainstrument.ask('STAR?;')) + + def do_set_startfrequency(self, startfrequency): + ''' + Set start frequency of device + + Input: + startfrequency (float) : start frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : setting start frequency to %s GHz' % startfrequency) + self._visainstrument.write('STAR; %e' % startfrequency) + #self._visainstrument.write('STAR; %e MHZ;' % startfrequency) + + def do_get_stopfrequency(self): + ''' + Get stop frequency from device + + Input: + None + + Output: + stopfrequency (float) : stop frequency in Hz + ''' + logging.debug(__name__ + ' : reading stop frequency from instrument') + return float(self._visainstrument.ask('STOP?;')) + + def do_set_stopfrequency(self, stopfrequency): + ''' + Set stop frequency of device + + Input: + stopfrequency (float) : stop frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : setting stop frequency to %s GHz' % stopfrequency) + self._visainstrument.write('STOP; %e' % stopfrequency) + #self._visainstrument.write('STAR; %e MHZ;' % startfrequency) + + def do_get_span(self): + ''' + Get span from device + + Input: + None + + Output: + span (float) : span in Hz + ''' + logging.debug(__name__ + ' : reading span from instrument') + return float(self._visainstrument.ask('SPAN?;')) + + def do_set_span(self,span): + ''' + Set span of device + + Input: + span (float) : span in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : setting span to %s Hz' % span) + self._visainstrument.write('SPAN; %e' % span) + diff --git a/instrument_plugins/Bristol_621.py b/instrument_plugins/Bristol_621.py new file mode 100644 index 00000000..8c672645 --- /dev/null +++ b/instrument_plugins/Bristol_621.py @@ -0,0 +1,92 @@ +# Bristol_621.py - Instrument plugin to communicate with a Bristol 621 +# wavelengthmeter +# Gabriele de Boo +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import types +import logging +from ctypes import * + +CLDevIFace = cdll.CLDevIFace + +CLOpenUSBSerialDevice = CLDevIFace.CLOpenUSBSerialDevice +CLOpenUSBSerialDevice.restype = c_long +CLCloseDevice = CLDevIFace.CLCloseDevice +CLSetLambdaUnits = CLDevIFace.CLSetLambdaUnits +CLSetLambdaUnits.restype = c_int +CLGetLambdaReading = CLDevIFace.CLGetLambdaReading +CLGetLambdaReading.restype = c_double +CLGetPowerReading = CLDevIFace.CLGetPowerReading +CLGetPowerReading.restype = c_float + +class Bristol_621(Instrument): + '''Bristol 621 Wavelength meter''' + + def __init__(self, name, address=None, reset=False): + Instrument.__init__(self,name) + self.devHandle = CLOpenUSBSerialDevice(c_long(address)) + logging.info('Device handle of Bristol wavemeter is %s' % self.devHandle) + # Set wavelength reading to nm + CLSetLambdaUnits(c_int(self.devHandle), c_uint(0)) + + self.add_parameter('wavelength', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='nm') +# self.add_parameter('frequency', +# type=types.FloatType, +# flags=Instrument.FLAG_GET, +# units='THz') + self.add_parameter('power', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='mW') + + self.add_function('close_device') + + if reset: + self.reset() + else: + self.get_all() + +#### initialization related + + def reset(self): + print __name__ + ' : resetting instrument' + + def get_all(self): + print __name__ + ' : reading all settings from instrument' + self.get_wavelength() + self.get_power() + +#### communication with machine + + def do_get_wavelength(self): + wavelength = None + while wavelength == None: + wavelength = CLGetLambdaReading(c_int(self.devHandle)) + logging.debug('Measured wavelength is %s.' % wavelength) + return wavelength + + def do_get_power(self): + power = CLGetPowerReading(c_int(self.devHandle)) + logging.debug('Measured power is %s.' % power) + return power + + def close_device(self): + if (CLCloseDevice(c_int(self.devHandle)) != 0): + logging.warning('%s: Closing device was unsuccesfull.' % self.name) diff --git a/instrument_plugins/Delta_PSC232.py b/instrument_plugins/Delta_PSC232.py new file mode 100644 index 00000000..7f644d81 --- /dev/null +++ b/instrument_plugins/Delta_PSC232.py @@ -0,0 +1,83 @@ +# Delta_PSC232.py driver for the PSC232 Delta Power Supply Controller +# Gabriele de Boo , 2012 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import types +import visa + +class Delta_PSC232(Instrument): + + def __init__(self, name, address=None, channel=1): + Instrument.__init__(self, name, tags=['measure']) + + self._address = address +# self._term_chars = '\n\r\x04' + self._channel = channel + self._visains = visa.instrument(address) #, term_chars = "\n\r\x04") # Hoo Rah + self._visains.baud_rate = 4800L + self._visains.write("*R") # Reset the instrument + self._visains.write("CH "+str(channel)) # Talking to the correct instrument + + self.add_parameter('Minimum_Voltage', type=types.FloatType, + flags=Instrument.FLAG_SET | Instrument.FLAG_SOFTGET) + self.add_parameter('Maximum_Voltage', type=types.FloatType, + flags=Instrument.FLAG_SET | Instrument.FLAG_SOFTGET) + self.add_parameter('Minimum_Current', type=types.FloatType, + flags=Instrument.FLAG_SET | Instrument.FLAG_SOFTGET) + self.add_parameter('Maximum_Current', type=types.FloatType, + flags=Instrument.FLAG_SET | Instrument.FLAG_SOFTGET) + self.add_parameter('Voltage', type=types.FloatType, + flags=Instrument.FLAG_GETSET) + self.add_parameter('Current', type=types.FloatType, + flags=Instrument.FLAG_GETSET) + +# self.add_function('set_defaults') + self.set_defaults() + + def set_defaults(self): + '''Set default parameters.''' + self.set_Minimum_Voltage(0) + self.set_Maximum_Voltage(30) + self.set_Minimum_Current(0) + self.set_Maximum_Current(5) + self._visains.write("REMOTE") + + def do_set_Minimum_Voltage(self, minvol): + self._visains.write("SOUR:VOLT:MIN " + str(minvol)) + + def do_set_Maximum_Voltage(self, maxvol): + self._visains.write("SOUR:VOLT:MAX " + str(maxvol)) + + def do_set_Minimum_Current(self, mincur): + self._visains.write("SOUR:CURR:MIN " + str(mincur)) + + def do_set_Maximum_Current(self, maxcur): + self._visains.write("SOUR:CURR:MAX " + str(maxcur)) + + def do_set_Voltage(self, V): + self._visains.write("SOU:VOLT " + str(V)) + + def do_set_Current(self, I): + self._visains.write("SOU:CURR " + str(I)) + + def do_get_Voltage(self): +# return self._remove_EOT(self._visains.ask("MEAS:VOLT?")) + return float(self._visains.ask("MEAS:VOLT?")) + + def do_get_Current(self): + return float(self._visains.ask("MEAS:CURR?")) + diff --git a/instrument_plugins/HP_3325B.py b/instrument_plugins/HP_3325B.py new file mode 100644 index 00000000..bca11272 --- /dev/null +++ b/instrument_plugins/HP_3325B.py @@ -0,0 +1,254 @@ +# HP_3325B.py class, to perform the communication between the Wrapper and the device +# Gabriele de Boo 2014 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +from visa import instrument +import types +import logging +from time import sleep + +class HP_3325B(Instrument): + ''' + This is the python driver for the HP 3325B + synthesizer + + Usage: + Initialize with + = instruments.create('', 'HP_33120A', address='', + reset=) + ''' + + def __init__(self, name, address, reset=False): + ''' + Initializes the HP_3325B, and communicates with the wrapper. + Our model doesn't have the high voltage option so I didn't add the use + of that option in this wrapper. + + Input: + name (string) : name of the instrument + address (string) : GPIB address + reset (bool) : resets to default values, default=false + + Output: + None + ''' + Instrument.__init__(self, name, tags=['physical']) + + self._address = address + self._visainstrument = instrument(self._address) + + self.add_parameter('frequency', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, + minval=0.0, maxval=60.999999e6, + units='Hz') + self.add_parameter('amplitude', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, + minval=0.001, maxval=40.0, + units='V') + self.add_parameter('offset', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, + minval=-5.0, maxval=5.0, + units='V') + self.add_parameter('connected_output', + type=types.StringType, + flags=Instrument.FLAG_GETSET, + option_list=['front','rear']) + self.add_parameter('function', + type=types.StringType, + flags=Instrument.FLAG_GETSET, + option_list=['DC','sine','square','triangle','positive ramp','negative ramp']) + self.add_parameter('amplitude_modulation_status', + type=types.BooleanType, + flags=Instrument.FLAG_GET) + + self.add_function('reset') + self.add_function('get_all') + + if reset: + self.reset() + else: + self.get_all() + + def get_all(self): + self.get_frequency() + self.get_connected_output() + self.get_amplitude() + self.get_offset() + self.get_function() + self.get_amplitude_modulation_status() + + def reset(self): + logging.info(__name__ + ' : Resetting instrument') + self._visainstrument.write('*RST') + sleep(0.1) + self.get_all() + +# Parameters + + def do_set_frequency(self, freq): + ''' + Sets the frequency. Uses Hz. + ''' + logging.debug(__name__ + ' : Setting frequency') + self._visainstrument.write('FR%8.3fHZ' % freq) + + def do_get_frequency(self): + logging.debug(__name__ + ' : Getting frequency') + response = self._visainstrument.ask('IFR') + if response[-2:] == 'HZ': + freq = response[2:-2] + elif response[-2:] == 'KH': + freq = response[2:-2]*1e3 + elif response[-2:] == 'MH': + freq = response[2:-2]*1e6 + else: + logging.warning(__name__ + ' : Response incorrect.') + return False + return float(freq) + + def do_set_amplitude(self, amp): + logging.debug(__name__ + ' : Setting amplitude') + self._visainstrument.write('AM%5.6fVO' % amp) + + def do_get_amplitude(self): + ''' + Gets the amplitude in V. + ''' + logging.debug(__name__ + ' : Getting amplitude') + response = self._visainstrument.ask('IAM') + if not response.startswith('AM'): + logging.warning(__name__ + ' : Wrong response.') + raise ValueError('Response from instrument was wrong.') + amp = response[2:-2] + if response[-2:] == 'VO': + return amp + elif response[-2:] == 'MV': + return amp*1000 +# elif response[-2:] == 'DB': +# elif response[-2:] == 'DV': + + def do_set_offset(self, amp): + logging.debug(__name__ + ' : Setting amplitude') + self._visainstrument.write('OF%5.6fVO' % amp) + + def do_get_offset(self): + ''' + Gets the amplitude in V. + ''' + logging.debug(__name__ + ' : Getting amplitude') + response = self._visainstrument.ask('IOF') + if not response.startswith('OF'): + logging.warning(__name__ + ' : Wrong response.') + raise ValueError('Response from instrument was wrong.') + amp = response[2:-2] + if response[-2:] == 'VO': + return amp + elif response[-2:] == 'MV': + return amp*1000 + + def do_get_connected_output(self): + logging.debug(__name__ + ' : Getting which output is connected.') + response = self._visainstrument.ask('IRF') + if response == 'RF1': + return 'front' + elif response == 'RF2': + return 'rear' + else: + logging.warning(__name__ + ' : Response incorrect.') + return False + + def do_set_connected_output(self, output): + ''' + Options are 'front' and 'rear'. + ''' + logging.debug(__name__ + ' : Setting the connected output to %s.' % output) + if output == 'FRONT': + self._visainstrument.write('RF1') + else: + self._visainstrument.write('RF2') + + def do_get_function(self): + ''' + Get the current waveform function of the instrument. + options are: + 'DC' + 'sine' + 'square' + 'triangle' + 'positive ramp' + 'negative ramp' + ''' + logging.debug(__name__ + ' : Getting the waveform function.') + response = self._visainstrument.ask('IFU') + if not response.startswith('FU'): + logging.warning(__name__ + ' : Wrong response.') + raise ValueError('Response from instrument was wrong.') + if response[2] == '0': + return 'DC' + elif response[2] == '1': + return 'sine' + elif response[2] == '2': + return 'square' + elif response[2] == '3': + return 'triangle' + elif response[2] == '4': + return 'positive ramp' + elif response[2] == '5': + return 'negative ramp' + + def do_set_function(self, function): + ''' + Set the current waveform function of the instrument. + options are: + 'DC' + 'sine' + 'square' + 'triangle' + 'positive ramp' + 'negative ramp' + ''' + logging.debug(__name__ + ' : Setting the waveform function to %s.' % function) + if function == 'DC': + self._visainstrument.write('FU0') + if function == 'SINE': + self._visainstrument.write('FU1') + if function == 'SQUARE': + self._visainstrument.write('FU2') + if function == 'TRIANGLE': + self._visainstrument.write('FU3') + if function == 'POSITIVE RAMP': + self._visainstrument.write('FU4') + if function == 'NEGATIVE RAMP': + self._visainstrument.write('FU5') + + def do_get_amplitude_modulation_status(self): + ''' + Get the amplitude modulation status. + Returns True or False + ''' + logging.debug(__name__ + ' : Getting the amplitude modulation status.') + response = self._visainstrument.ask('IMA') + if not response.startswith('MA'): + logging.warning(__name__ + ' : Wrong response.') + raise ValueError('Response from instrument was wrong.') + if response[2] == '0': + return False + if response[2] == '1': + return True diff --git a/instrument_plugins/HighFinesse.py b/instrument_plugins/HighFinesse.py new file mode 100644 index 00000000..5abfa888 --- /dev/null +++ b/instrument_plugins/HighFinesse.py @@ -0,0 +1,86 @@ +# HighFinesse.py - Instrument plugin to communicate with a High Finesse +# wavelengthmeter +# Gabriele de Boo +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import types +from ctypes import * + +wlmData = windll.wlmData + +GetWvl = wlmData.GetWavelength +GetWvl.restype = c_double +GetFrq = wlmData.GetFrequency +GetFrq.restype = c_double +GetLw = wlmData.GetLinewidth +GetLw.restype = c_double +GetPwr = wlmData.GetPowerNum +GetPwr.restype = c_double + +class HighFinesse(Instrument): + '''High Finesse Wavelength meter''' + + def __init__(self, name, reset=False): + Instrument.__init__(self,name) + + self.add_parameter('wavelength', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='nm') + self.add_parameter('frequency', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='THz') + self.add_parameter('linewidth', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='THz') + self.add_parameter('power', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='microW') + + if reset: + self.reset() + else: + self.get_all() + +#### initialization related + + def reset(self): + print __name__ + ' : resetting instrument' + + def get_all(self): + print __name__ + ' : reading all settings from instrument' + self.get_wavelength() + self.get_frequency() + +#### communication with machine + + def do_get_wavelength(self): + Wavelength = GetWvl(c_double(0)) + return Wavelength + + def do_get_power(self): + return GetPwr(c_long(1), c_double(0)) + + def do_get_frequency(self): + return GetFrq(c_double(0)) + + def do_get_linewidth(self): + return GetLw(c_char_p(cReturnFrequency),c_double(0)) + diff --git a/instrument_plugins/JDSU_SWS15101.py b/instrument_plugins/JDSU_SWS15101.py new file mode 100644 index 00000000..05cbcc44 --- /dev/null +++ b/instrument_plugins/JDSU_SWS15101.py @@ -0,0 +1,287 @@ +# JDSU_SWS15101 driver July 4, 2014 +# +# Gabriele de Boo +# Chunming Yin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import visa +import types +import logging +import numpy +from time import sleep + +class JDSU_SWS15101(Instrument): + ''' + This is the driver for the JDSU SWS15101 Tunable Laser Source + + Usage: + Initialize with + = instruments.create('', 'JDSU_SWS15101', address='') + ''' + + def __init__(self, name, address, reset=False): + ''' + Input: + name (string) : name of the instrument + address (string) : GPIB address + ''' + logging.info(__name__ + ' : Initializing instrument JDSU_SWS15101') + Instrument.__init__(self, name, tags=['physical']) + + # Add some global constants + self._address = address + self._visainstrument = visa.instrument(self._address) + + self.add_parameter('power', + flags=Instrument.FLAG_GETSET, units='mW', minval=0, maxval=10, type=types.FloatType) + self.add_parameter('diode_current', + flags=Instrument.FLAG_GETSET, units='mA', minval=0, maxval=150, type=types.FloatType) + self.add_parameter('wavelength', + flags=Instrument.FLAG_GETSET, units='nm', minval=1460, maxval=1600, type=types.FloatType) + self.add_parameter('output_status', + flags=Instrument.FLAG_GETSET, type=types.BooleanType) + self.add_parameter('FSCWaveL', + flags=Instrument.FLAG_SET, units='pm', minval=-22.4, maxval=+22.4, type=types.FloatType) + + self.add_function ('get_all') + + #self.get_all() + def reset(self): + ''' + Resets the instrument to default values + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : resetting instrument') + self._visainstrument.write('*RST') + self.get_all() + + def get_all(self): + ''' + Reads all implemented parameters from the instrument, + and updates the wrapper. + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : get all') + self.get_power() + self.get_diode_current() + self.get_wavelength() + self.get_output_status() + + def do_get_power(self): + ''' + Reads the power of the signal from the instrument + + Input: + None + + Output: + ampl (?) : power in ? + ''' + logging.debug(__name__ + ' : get power') + '''return float(self._visainstrument.ask('P?')) + ''' +# Make sure that the information in buffer has been read out. + attempt = 0 + Stat_word = self._visainstrument.stb + while (Stat_word != 1) and (attempt<10): + self._visainstrument.read() + Stat_word = self._visainstrument.stb + attempt += 1 + sleep(0.01) + if attempt >= 10: + logging.warning(__name__ + ' may not be running properly: Status Code %s.' % Stat_word) + self._visainstrument.write('P?') +# Wait until the status word shows the parameter available for reading. + while ((Stat_word & 0b00010000) == 0) and (attempt<100): + Stat_word = self._visainstrument.stb + attempt += 1 + sleep(0.01) + if attempt >= 100: + logging.warning(__name__ + ' may not be responding correctly: Status Code %s.' % Stat_word) + + P = self._visainstrument.read() + if P == ('DISABLED'): + return 0 + elif (P[0] == 'P'): + return float(P[2:]) + else: + logging.warning(__name__ + ' did not reply correctly: %s.' % P ) + return 0 + + def do_set_power(self, pow): + ''' + Set the power of the signal + + Input: + amp (float) : power in ?? + + Output: + None + ''' + logging.debug(__name__ + ' : set power to %f' % pow) + self._visainstrument.write('P=%s' % pow) + + def do_get_diode_current(self): + ''' + Read the diode current. + ''' + logging.debug(__name__ + ' : get diode_current.') + attempt = 0 + Stat_word = self._visainstrument.stb + while (Stat_word != 1) and (attempt<10): + self._visainstrument.read() + Stat_word = self._visainstrument.stb + attempt += 1 + sleep(0.01) + if attempt >= 10: + logging.warning(__name__ + ' may not be running properly: Status Code %s.' % Stat_word) + self._visainstrument.write('I?') +# Wait until the status word shows the parameter available for reading. + while ((Stat_word & 0b00010000) == 0) and (attempt<100): + Stat_word = self._visainstrument.stb + attempt += 1 + sleep(0.01) + if attempt >= 100: + logging.warning(__name__ + ' may not be responding correctly: Status Code %s.' % Stat_word) + + I = self._visainstrument.read() + if I == ('DISABLED'): + logging.info(__name__ + ' : Output is disabled.') + return 0 + elif (I[0] == 'I'): + return float(I[2:]) + else: + logging.warning(__name__ + ' did not reply correctly: %s.' % I ) + return 0 + + def do_set_diode_current(self, curr): + ''' + Set the diode current. + ''' + logging.debug(__name__ + ' : set diode_current to %.1f.' % curr) + self._visainstrument.write('I=%.1f' % curr) + + def do_get_wavelength(self): + ''' + Reads the wavelength from the laser + + Input: + None + + Output: + L (float) : Wavelength in nm + ''' + logging.debug(__name__ + ' : get wavelength') + '''return float(self._visainstrument.ask('L?')) + ''' + attempt = 0 + Stat_word = self._visainstrument.stb + while (Stat_word != 1) and (attempt<10): + self._visainstrument.read() + Stat_word = self._visainstrument.stb + attempt += 1 + sleep(0.01) + if attempt >= 10: + logging.warning(__name__ + ' may not be running properly: Status Code %s.' % Stat_word) + self._visainstrument.write('L?') +# Wait until the status word shows the parameter available for reading. + while ((Stat_word & 0b00010000) == 0) and (attempt<100): + Stat_word = self._visainstrument.stb + attempt += 1 + sleep(0.01) + if attempt >= 100: + logging.warning(__name__ + ' may not be responding correctly: Status Code %s.' % Stat_word) + + L = self._visainstrument.read() + + + if L == ('DISABLED'): + L = 0 + elif (L[0] == 'L'): + return float(L[2:]) + else: + logging.warning(__name__ + ' did not reply correctly: %s.' % L ) + return 0 + + def do_set_wavelength(self, wavel): + ''' + Set the frequency of the instrument + + Input: + freq (float) : Frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : set wavelength to %f' % wavel) + self._visainstrument.write('L=%s' % wavel) + + def do_set_FSCWaveL(self, FSCL): + ''' + Set the frequency of the instrument + + Input: + freq (float) : Frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : set FSCwavelength to %f' % FSCL) + self._visainstrument.write('FSCL=%s' % FSCL) + + def do_get_output_status(self): + ''' + Reads the output status from the instrument + + Input: + None + + Output: + status (Boolean) : True for 'on' or False for 'off' + ''' + logging.debug(__name__ + ' : get status') + P = self.get_power() + if P == 0: + return False + else: + return True + + def do_set_output_status(self, status): + ''' + Set the output status of the instrument + + Input: + status (Boolean) : True or False + + Output: + None + ''' + logging.debug(__name__ + ' : set status to %s' % status) + if status: + self._visainstrument.write('ENABLE') + else: + self._visainstrument.write('DISABLE') diff --git a/instrument_plugins/RS_FSL6.py b/instrument_plugins/RS_FSL6.py new file mode 100644 index 00000000..d4b4ba47 --- /dev/null +++ b/instrument_plugins/RS_FSL6.py @@ -0,0 +1,532 @@ +# RS_FSL6.py class, to perform the communication between the Wrapper and the device +# Pablo Asshoff , 2013 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import visa +import types +import logging +import numpy +import math + +class RS_FSL6(Instrument): + ''' + This is the driver for the Rohde & Schwarz FSL6 Spectrum Analyser + + Usage: + Initialize with + = instruments.create('name', 'RS_FSL6', address='', + reset=) + ''' + + def __init__(self, name, address, reset=False): + ''' + Initializes the RS_FSL6, and communicates with the wrapper. + + Input: + name (string) : name of the instrument + address (string) : GPIB address + reset (bool) : resets to default values, default=false + + Output: + None + ''' + logging.info(__name__ + ' : Initializing instrument') + Instrument.__init__(self, name, tags=['physical']) + + self._address = address + self._visainstrument = visa.instrument(self._address) + self._visainstrument.timeout = 1 + + # Add parameters + self.add_parameter('centerfrequency', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=9e3, maxval=6e9, + units='Hz', format='%.04e') + self.add_parameter('span', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=0, maxval=3e9, + units='Hz', format='%.04e') + self.add_parameter('referencelevel', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=-80, maxval=30, + units='dBm', format='%.04e') + self.add_parameter('sweeptime', type=types.FloatType, + flags=Instrument.FLAG_GETSET | Instrument.FLAG_GET_AFTER_SET, + minval=1e-6, maxval=60, + units='s', format='%.04e') + self.add_parameter('channelpower', type=types.FloatType, + flags=Instrument.FLAG_GET, + units='W', format='%.10e') + self.add_parameter('timetracemarkerpower', type=types.FloatType, + flags=Instrument.FLAG_GET, + units='W', format='%.10e') + self.add_parameter('IQresult', type=types.StringType, + flags=Instrument.FLAG_GET, + units='') + self.add_parameter('tracedata', type=types.StringType, + flags=Instrument.FLAG_GET, + units='') + self.add_parameter('display_onoff', + flags=Instrument.FLAG_SET, + type=types.StringType, units='') + self.add_parameter('triggerlevel', type=types.FloatType, + flags=Instrument.FLAG_SET, + minval=0.5, maxval=3.5, + units='V', format='%.04e') + + + # Add functions + self.add_function('reset') + self.add_function('get_all') + + self.add_function('init_power_measurement') + self.add_function('init_IQ_measurement') + self.add_function('init_zero_span') + self.add_function('init_trace_readout') + self.add_function('start_sweep') + self.add_function('stop_power_measurement') + self.add_function('convert_dBuV_to_V') # works but apparently not needed, device returns usually V by default +# self.add_function('stop_remote_control') +# self.add_function('trigger_mode') +# self.add_function('enable_trigger') + + + if reset: + self.reset() + else: + self.get_all() + + # Functions + def reset(self): + ''' + Resets the instrument to default values + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : Resetting instrument') + self._visainstrument.write('*RST;*CLS') # zuvor nur *RST + self.get_all() + + def get_all(self): + ''' + Reads all implemented parameters from the instrument, + and updates the wrapper. + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : reading all settings from instrument') + self.get_centerfrequency() + self.get_span() + self.get_referencelevel() + self.get_sweeptime() + self.get_channelpower() + + def do_set_display_onoff(self, type): + ''' + Set the display on or off + + Input: + type (string) : 'on' or 'off' + + Output: + None + ''' + + logging.debug('set display to %s', type) + if type is 'on': + self._visainstrument.write('SYST:DISP:UPD ON') + elif type is 'off': + self._visainstrument.write('SYST:DISP:UPD OFF') + else: + logging.error('invalid type %s' % type) + + + + + + + + def init_IQ_measurement(self): + ''' + Initializes an I/Q measurement + + Input: + None + + Output: + None + ''' + logging.debug(__name__ + ' : initialization of I/Q (quadrature) measurement') + + #setting the trigger level to 0.5 V (bounds: 0.5 V to 3.5 V, p.1590 of operating manual, RST value 1.4 V) + self._visainstrument.write('TRIG:LEV 0.5 V') + #self._visainstrument.write('BAND:RES 20MHz') #resultion bandwidth. 20 MHz, only for test + self._visainstrument.write('FREQ:SPAN 0Hz') + self._visainstrument.write('TRAC:IQ:STAT ON') + #enables acquisition of I/Q data, trace display on device not possible in this operation mode + self._visainstrument.write('TRAC:IQ:SET NORM,20MHz,64MHz,EXT,POS,0,640') + #self._visainstrument.write('TRAC:IQ:SET NORM,100kHz,32MHz,EXT,POS,0,512') + #sample measurement configuration + #filter: NORM, RBW: 10MHz, sample rate: 32 MHz, trigger source: external (EXT) / internal (IMM), trigger slope: positive, + #pretrigger samples: 0, numer of samples: 512 + self._visainstrument.write('FORMat ASC') #selects format of response data (either REAL,32 or ASC for ASCII) + self._visainstrument.write('FREQ:CONT OFF') + #return self._visainstrument.write('TRAC:IQ:DATA?') #starts measurements and reads results + #self._visainstrument.write('INIT;*WAI') #apparently not necessary + #self._visainstrument.write('TRAC:IQ OFF') #close I/Q operation mode + + def init_power_measurement(self): + ''' + Initializes a channel power measurement + + Input: + None + + Output: + None + + maybe add sweeptime parameter etc. later and measure both sidebands for better statistics + ''' + logging.debug(__name__ + ' : initialization of channel power measurement') + self._visainstrument.write('POW:ACH:ACP 0') + self._visainstrument.write('POW:ACH:BAND 5KHZ') + #self._visainstrument.write('POW:ACH:BAND:ACH 40KHZ') + #self._visainstrument.write('POW:ACH:BAND:ALT1 50KHZ') + #self._visainstrument.write('POW:ACH:BAND:ALT2 60KHZ') + #self._visainstrument.write('POW:ACH:SPAC 30KHZ') + #self._visainstrument.write('POW:ACH:SPAC:ALT1 100KHZ') + #self._visainstrument.write('POW:ACH:SPAC:ALT2 140KHZ') + self._visainstrument.write('POW:ACH:MODE ABS') # Switches on absolute power measurement. + self._visainstrument.write('INIT:CONT ON') # Switches over to single sweep mode (for OFF!!). + self._visainstrument.write('INIT;*WAI') # Starts a sweep and waits for the end of the sweep. + + def stop_power_measurement(self): + ''' + Initializes a channel power measurement + + Input: + None + + Output: + None + ''' + logging.debug(__name__ + ' : stop channel power measurement') + self._visainstrument.write('INIT:CONT ON') # Switches over to continuous sweep mode. + + def init_zero_span(self,resbw,vidbw): + ''' + Initializes a zero span measurement + + Input: + resolution bandwidth, video bandwidth + + Output: + None + ''' + logging.debug(__name__ + ' : initialization of zero span measurement') + self._visainstrument.write('FREQ:SPAN 0Hz') + self._visainstrument.write('BAND:RES %s' % resbw) #resolution bandwidth, suggested: 100kHz + self._visainstrument.write('BAND:VID %s' % vidbw) #video bandwidth, suggested: 100kHz + #sweep time --> set from measurement script + #self._visainstrument.write('CALC:MARK:FUNC:SUMM:PPE ON ') # not required if time trace is evaluate in control computer + self._visainstrument.write('INIT;*WAI') # starts a sweep and waits for the end of the sweep. + + def start_sweep(self): + logging.debug(__name__ + ' : start a sweep and wait till finished') + self._visainstrument.write('INIT') + #self._visainstrument.write('*WAI') + + + def init_trace_readout(self): + ''' + Read a trace + p. 230 operating manual + + Input: + mode, either ASCII or binary + + Output: + None + ''' + logging.debug(__name__ + ' : initialization of trace readout') + self._visainstrument.write('FORM ASC') + #if mode == 'ASCII': + # self._visainstrument.write('FORM ASC') + #elif mode == 'binary': + # self._visainstrument.write('FORM REAL,32') + #else: + # print 'Not a valid mode, function requires mode as argument, parameter either ASC for ASCII file or binary for binary file' + # # ASCII file format, alternative: FORMat REAL,32 (binary file) / FORM ASC for ASCII + ##self._visainstrument.write('MMEM:STOR:TRAC 1,'TEMPTRACE.DAT'') + # #the previous command just creates a file locally on the analyer + ##self._visainstrument.write('TRAC? TRACE1') + + + def convert_dBuV_to_V(self,dBuV): + ''' + converts dBuV to Volt + + Input: + Voltage in dBuV + + Output: + Voltage in Volt + ''' + logging.debug(__name__ + ' : convert dBuV to Volt') + UinV = 10**(dBuV/20)/1E6 # formula from http://www.kathrein.de/include/pegelumrechnung.cfm + return UinV + + + def convert_dBm_to_W(self,dBm): + ''' + converts dBm to Watt + + Input: + power in dBm + + Output: + power in Watt + ''' + logging.debug(__name__ + ' : convert dBm to Watt') + PinW = 10**(dBm/10)/1E3 # formula from http://www.kathrein.de/include/pegelumrechnung.cfm + return PinW + + + +# def stop_remote_control(self): +# ''' +# Initializes a channel power measurement +# +# Input: +# None +# +# Output: +# None +# ''' +# logging.debug(__name__ + ' : set to local control') +# self._visainstrument.write('INIT:CONT OFF') #GPIB COMMAND ?????? + + + + # communication with machine + def do_get_centerfrequency(self): + ''' + Get center frequency from device + + Input: + None + + Output: + centerfrequency (float) : center frequency in Hz + ''' + logging.debug(__name__ + ' : reading center frequency from instrument') + return float(self._visainstrument.ask('FREQ:CENT?')) + + + + + def do_set_centerfrequency(self, centerfrequency): + ''' + Set center frequency of device + + Input: + centerfrequency (float) : center frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : setting center frequency to %s Hz' % centerfrequency) + self._visainstrument.write('FREQ:CENT %e' % centerfrequency) + + + + + def do_set_triggerlevel(self, triggerlevel): + ''' + Set trigger level for TTL input + + Input: + trigger level (float) : center frequency in V + + Output: + None + ''' + logging.debug(__name__ + ' : setting trigger level to %s V' % triggerlevel) + self._visainstrument.write('TRIG:LEV %e V' % triggerlevel) + + + def do_get_span(self): + ''' + Get span from device + + Input: + None + + Output: + span (float) : span in Hz + ''' + logging.debug(__name__ + ' : reading span from instrument') + return float(self._visainstrument.ask('FREQ:SPAN?')) + + def do_set_span(self,span): + ''' + Set span of device + + Input: + span (float) : span in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : setting span to %s Hz' % span) + self._visainstrument.write('FREQ:SPAN %e' % span) + + def do_get_referencelevel(self): + ''' + Get reference level from device + + Input: + None + + Output: + referencelevel (float) : reference level in dBm + ''' + logging.debug(__name__ + ' : reading referencelevel from instrument') + return float(self._visainstrument.ask('DISP:TRAC:Y:RLEV?')) + + def do_set_referencelevel(self,referencelevel): + ''' + Set referencelevel of device + + Input: + referencelevel (float) : reference level in dBm(??) + + Output: + None + ''' + logging.debug(__name__ + ' : setting referencelevel to %s dBm' % referencelevel) + self._visainstrument.write('DISP:TRAC:Y:RLEV %e' % referencelevel) + + def do_get_sweeptime(self): + ''' + Get sweeptime level from device + + Input: + None + + Output: + sweeptime (float) : sweep time in s + ''' + logging.debug(__name__ + ' : reading sweeptime from instrument') + return float(self._visainstrument.ask('SWE:TIME?')) + + def do_set_sweeptime(self,sweeptime): + ''' + Set sweeptime of device + + Input: + sweeptime (float) : sweep time in s + + Output: + None + ''' + logging.debug(__name__ + ' : setting sweeptime to %s s' % sweeptime) + self._visainstrument.write('SWE:TIME %e' % sweeptime) + + def do_get_IQresult(self): + ''' + Get IQresult level from device in I/Q mode + + Input: + None + + Output: + IQresult (string) : either REAL,32 or ASCII, depending on choice in init_IQ_measurement + ''' + logging.debug(__name__ + ' : reading result of I/Q measurement from instrument') + #self._visainstrument.write('INIT,*WAI') + #self._visainstrument.write('*CLS') + self._visainstrument.write('INIT') + return self._visainstrument.ask('TRAC:IQ:DATA?') + #self._visainstrument.write('INIT,*WAI') + #return self._visainstrument.ask('TRAC:IQ:DATA:MEM? 0,4096') + + + + def do_get_tracedata(self): + ''' + read out trace data from device + + Input: + None + + Output: + tracedata (string) : either REAL,32 or ASCII, depending on choice + ''' + logging.debug(__name__ + ' : reading result of I/Q measurement from instrument') + self._visainstrument.write('INIT,*WAI') + #self._visainstrument.write('FORM ASC') # ASCII file format, alternative: FORMat REAL,32 (binary file) + return self._visainstrument.ask('TRAC? TRACE1') + + + def do_get_channelpower(self): + ''' + Get channel power from device (in MEAS. menu on front panel of the RS-FSL6, + command CP/ACP/MC-ACP) + + In measurement, call self.init_power_measurement() before reading channelpower! + + Documentation for remote control command in 'Operating manual', p. 821 + + Input: + None + + Output: + channelpower (float) : channel power in ??unit + ''' + logging.debug(__name__ + ' : reading channelpower from instrument') + self._visainstrument.write('*WAI') # Starts a sweep and waits for the end of the sweep. + return float(self._visainstrument.ask('CALC:MARK:FUNC:POW:RES? ACP')) + + + + def do_get_timetracemarkerpower(self): + ''' + Get marker power from device in zero span mode + + In measurement, call init_zero_span() before reading mean power! + + Documentation for remote control command in 'Operating manual', p. 1609 + + Input: + None + + Output: + timetracemarkerpower (float) : marker power in V!! (even if display shows dBuV) + ''' + logging.debug(__name__ + ' : reading marker power in zero span mode from instrument') + self._visainstrument.write('INIT;*WAI') # Starts a sweep and waits for the end of the sweep. + return float(self._visainstrument.ask('CALC:MARK:FUNC:SUMM:PPE:RES?')) + diff --git a/instrument_plugins/SRS_SG380.py b/instrument_plugins/SRS_SG380.py new file mode 100644 index 00000000..9656f53a --- /dev/null +++ b/instrument_plugins/SRS_SG380.py @@ -0,0 +1,613 @@ +# This Python file uses the following encoding: utf-8 +# SRS_SG386.py class, to perform the communication between the Wrapper and the device +# Chunming Yin 2013 +# Gabriele de Boo 2014 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +import visa +import types +import logging +import numpy + +class SRS_SG380(Instrument): + ''' + This is the driver for the Stanford Research Systems (SRS) SG380 range signal generators. + There are three models: + SG382 (DC to 2.025 GHz) + SG384 (DC to 4.050 GHz) + SG386 (DC to 6.075 GHz) + The wrapper will identify the model and set the ranges accordingly. + + Usage: + Initialize with + = instruments.create('', 'SRS_SG386', address=', reset=') + ''' + + def __init__(self, name, address, reset=False): + ''' + Initializes the SRS Signal Generator, and communicates with the wrapper. + + Input: + name (string) : name of the instrument + address (string) : GPIB address + reset (bool) : resets to default values, default=False + ''' + logging.info(__name__ + ' : Initializing instrument SRS_SG386') + Instrument.__init__(self, name, tags=['physical']) + + # Add some global constants + self._address = address + self._visainstrument = visa.instrument(self._address) + try: + identity = self._visainstrument.ask('*IDN?') + model = identity[26:31] + except IndexError: + raise Warning('The instrument is not a SRS RF signal generator. %s' % model) + + if model not in ['SG382','SG384','SG386']: + raise Warning('The instrument is not a SRS RF signal generator.') + logging.info('The model is %s' % model) + + options = {'1':'Rear clock outputs', '2':'RF doubler and DC outputs', '3':'IQ modulation inputs and outputs', '4':'OCXO timebase','5':'Rubidium timebase'} + for idx in range(1,5): + option_installed = bool(int(self._visainstrument.ask('OPTN? %i' % idx))) + if option_installed: + logging.info('Option %s is installed' % options[str(idx)]) + + minfreq_ntype = 950e3 + if model == 'SG382': + maxfreq_ntype = 2.025e9 + elif model == 'SG384': + maxfreq_ntype = 4.050e9 + else: + maxfreq_ntype = 6.075e9 + + self.add_parameter('ntype_power', + flags=Instrument.FLAG_GETSET, units='dBm', minval=-110, maxval=16.5, type=types.FloatType) + self.add_parameter('bnc_power', + flags=Instrument.FLAG_GETSET, units='dBm', minval=-110, maxval=16.5, type=types.FloatType) + self.add_parameter('bnc_output_status', + flags=Instrument.FLAG_GETSET, type=types.BooleanType) + + self.add_parameter('frequency', + flags=Instrument.FLAG_GETSET, units='Hz', minval=0.95e6, maxval=maxfreq_ntype, type=types.FloatType) + self.add_parameter('status', + flags=Instrument.FLAG_GETSET, type=types.StringType) + self.add_parameter('Frequency_Modulation_Rate', + flags=Instrument.FLAG_GETSET, units='Hz', minval=1e-6, maxval=50e3, type=types.FloatType) + self.add_parameter('Frequency_Modulation_Size', + flags=Instrument.FLAG_GETSET, units='Hz', minval=0.1, maxval=32e6, type=types.FloatType) + self.add_parameter('modulation_coupling', + flags=Instrument.FLAG_GETSET, type=types.StringType, + option_list=('DC', 'AC')) + self.add_parameter('modulation_function', + flags=Instrument.FLAG_GETSET, type=types.StringType, + option_list=('sine', + 'ramp', + 'triangle', + 'square', + 'noise', + 'external')) + self.add_parameter('modulation_type', + flags=Instrument.FLAG_GETSET, type=types.StringType, + option_list=('AM', + 'FM', + 'PhaseM', + 'sweep', + 'pulse', + 'blank', + 'IQ')) + + self.add_parameter('Modulation_State', + flags=Instrument.FLAG_GETSET, type=types.StringType) + self.add_parameter('rf_output_block_temperature', + flags=Instrument.FLAG_GET, type=types.FloatType) + self.add_parameter('timebase', + flags=Instrument.FLAG_GET, type=types.StringType) + self.add_parameter('list_mode', + flags=Instrument.FLAG_GETSET, type=types.BooleanType) +## self.add_parameter('Frequency_List', +## flags=Instrument.FLAG_SET, type=numpy.ndarray) +## self.add_parameter('Power_List', +## flags=Instrument.FLAG_SET, type=numpy.ndarray) +## self.add_parameter('Dwell_Times_List', +## flags=Instrument.FLAG_SET, type=numpy.ndarray) + + self.add_function('reset') + self.add_function('get_all') +## self.add_function('List_sweep_freq_on') +## self.add_function('List_sweep_freq_off') +## self.add_function('List_sweep_power_on') +## self.add_function('List_sweep_power_on') + self.add_function('trigger') + self.add_function('list_on') + self.add_function('list_off') + self.add_function('create_list') + self.add_function('get_list_entry') + self.add_function('set_list_entry') + self.add_function('get_error') + + + if (reset): + self.reset() + else: + self.get_all() + + def reset(self): + ''' + Resets the instrument to default values + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : resetting instrument') + self._visainstrument.write('*RST') + self.get_all() + + def get_all(self): + ''' + Reads all implemented parameters from the instrument, + and updates the wrapper. + + Input: + None + + Output: + None + ''' + logging.info(__name__ + ' : get all') + self.get_ntype_power() + self.get_bnc_power() + self.get_frequency() + self.get_status() + self.get_bnc_output_status() + self.get_rf_output_block_temperature() + self.get_timebase() + self.get_list_mode() + self.get_modulation_function() + self.get_modulation_coupling() + self.get_modulation_type() + + def do_get_ntype_power(self): + ''' + Reads the power of the signal from the instrument + + Input: + None + + Output: + ampl (?) : power in dBm + ''' + logging.debug(__name__ + ' : get ntype power') + return float(self._visainstrument.ask('AMPR?')) + + def do_set_ntype_power(self, amp): + ''' + Set the power of the signal + + Input: + amp (float) : power in dBm + + Output: + None + ''' + logging.debug(__name__ + ' : set ntype power to %f' % amp) + self._visainstrument.write('AMPR%s' % amp) + + def do_get_bnc_power(self): + ''' + Reads the power of the bnc output from the instrument + + Input: + None + + Output: + ampl (?) : power in dBm + ''' + logging.debug(__name__ + ' : get bnc_power') + return float(self._visainstrument.ask('AMPL?')) + + def do_set_bnc_power(self, amp): + ''' + Set the power of the signal + + Input: + amp (float) : power in dBm + + Output: + None + ''' + logging.debug(__name__ + ' : set bnc_power to %f' % amp) + self._visainstrument.write('AMPL %s' % amp) + + def do_get_bnc_output_status(self): + ''' + Get the output status of the BNC connector. + ''' + logging.debug(__name__ + ' : get the bnc output status') + return bool(self._visainstrument.ask('ENBL?')) + + def do_set_bnc_output_status(self, status): + ''' + Set the output status of the BNC connector. + Input: + True : On + False : Off + Output: + None + ''' + logging.debug(__name__ + ' : set the bnc output status to %s' % status) + self._visainstrument.write('ENBL %i' % status) + + def do_get_frequency(self): + ''' + Reads the frequency of the signal from the instrument + + Input: + None + + Output: + freq (float) : Frequency in Hz + ''' + logging.debug(__name__ + ' : get frequency') + return float(self._visainstrument.ask('FREQ?')) + + def do_set_frequency(self, freq): + ''' + Set the frequency of the instrument + + Input: + freq (float) : Frequency in Hz + + Output: + None + ''' + logging.debug(__name__ + ' : set frequency to %f' % freq) + self._visainstrument.write('FREQ%s' % freq) + + def do_get_status(self): + ''' + Reads the output status from the instrument + + Input: + None + + Output: + status (string) : 'On' or 'Off' + ''' + logging.debug(__name__ + ' : get status') + stat = self._visainstrument.ask('ENBR?') + + if (stat=='1'): + return 'ON' + elif (stat=='0'): + return 'OFF' + else: + raise ValueError('Output status not specified : %s' % stat) + return + + def do_set_status(self, status): + ''' + Set the output status of the instrument + + Input: + status (string) : 'On' or 'Off' + + Output: + None + ''' + logging.debug(__name__ + ' : set status to %s' % status) + if (status.upper()=='ON'): + status = 1 + elif (status.upper()=='OFF'): + status = 0 + else: + raise ValueError('set_status(): can only set on or off') + self._visainstrument.write('ENBR%s' % status) + + def do_get_Frequency_Modulation_Rate(self): + ''' + Get the size of the frequency modulation of FM + ''' + logging.debug(__name__ + ' : get FM rate') + return float(self._visainstrument.ask('RATE?')) + + def do_set_Frequency_Modulation_Rate(self, size): + ''' + Set the size of the frequency modulation of FM + ''' + logging.debug(__name__ + ' : set FM rate to %s' % size) + self._visainstrument.write('RATE%s' % size) + + def do_get_Frequency_Modulation_Size(self): + ''' + Get the size of the frequency modulation of FM + ''' + logging.debug(__name__ + ' : get FM size') + return float(self._visainstrument.ask('FDEV?')) + + def do_set_Frequency_Modulation_Size(self, size): + ''' + Set the size of the frequency modulation of FM + ''' + logging.debug(__name__ + ' : set FM size to %s' % size) + self._visainstrument.write('FDEV%s' % size) + + def do_get_Modulation_State(self): + ''' + Get the status of the modulation + ''' + logging.debug(__name__ + ' : get Modulation state') + response = self._visainstrument.ask('MODL?') + if response == '0': + return 'OFF' + if response == '1': + return 'ON' + def do_set_Modulation_State(self, status): + ''' + Set the status of the modulation + + Input: + status (string) : 'On' or 'Off' + + Output: + None + ''' + logging.debug(__name__ + ' : set status to %s' % status) + if (status.upper()=='ON'): + status = 1 + elif (status.upper()=='OFF'): + status = 0 + else: + raise ValueError('set_status(): can only set on or off') + self._visainstrument.write('MODL%s' % status) + + def do_get_modulation_coupling(self): + ''' + Get the modulation coupling + Output: + 'DC' + 'AC' + ''' + logging.debug(__name__ + ' : get modulation coupling') + response = self._visainstrument.ask('COUP?') + if response == '0': + return 'AC' + elif response == '1': + return 'DC' + else: + logging.warning(__name__ + ' : answer to COUP? was not 0 or 1 : %s' % response) + + def do_set_modulation_coupling(self, coupling): + ''' + Set the modulation coupling + Input: + 'AC' + 'DC' + ''' + logging.debug(__name__ + ' : set modulation coupling to %s' % coupling) + if coupling == 'AC': + self._visainstrument.write('COUP 0') + if coupling == 'DC': + self._visainstrument.write('COUP 1') + + def do_get_modulation_function(self): + ''' + Get the modulation function + 0 Sine wave: sine + 1 Ramp: ramp + 2 Triangle: triangle + 3 Square: square + 4 Noise: noise + 5 External: external + ''' + logging.debug(__name__ + ' : get the modulation function') + response = self._visainstrument.ask('MFNC?') + if response == '0': + return 'sine' + elif response == '1': + return 'ramp' + elif response == '2': + return 'triangle' + elif response == '3': + return 'square' + elif response == '4': + return 'noise' + elif response == '5': + return 'external' + else: + logging.warning(__name__ + ' : answer to MFNC? was not expected : %s' % response) + + def do_set_modulation_function(self, function): + ''' + ''' + function_dict = {'SINE' : 0, + 'RAMP' : 1, + 'TRIANGLE' : 2, + 'SQUARE' : 3, + 'NOISE' : 4, + 'EXTERNAL' : 5} + logging.debug(__name__ + ' : set the modulation function to %s' % function) + self._visainstrument.write('MFNC %s' % function_dict[function]) + + def do_get_modulation_type(self): + ''' + + ''' + logging.debug(__name__ + ' : get the modulation type') + response = self._visainstrument.ask('TYPE?') + if response == '0': + return 'AM' + elif response == '1': + return 'FM' + elif response == '2': + return 'PhaseM' + elif response == '3': + return 'sweep' + elif response == '4': + return 'pulse' + elif response == '5': + return 'blank' + elif response == '6': + return 'IQ' + else: + logging.warning(__name__ + ' : answer to TYPE? was not expected : %s' % response) + + def do_set_modulation_type(self, mtype): + ''' + ''' + type_dict = { 'AM' : 0, + 'FM' : 1, + 'PHASEM' : 2, + 'SWEEP' : 3, + 'PULSE' : 4, + 'BLANK' : 5, + 'IQ' : 6} + logging.debug(__name__ + ' : set the modulation type to %s' % mtype) + self._visainstrument.write('TYPE %s' % type_dict[mtype]) + + def do_get_rf_output_block_temperature(self): + ''' + Get the temperature of the RF output block. + ''' + return float(self._visainstrument.ask('TEMP?')) + + def do_get_timebase(self): + ''' + Get the timebase of the instrument. + ''' + timebase_dict = {'0':'Crystal', '1':'OCXO', '2':'Rubidium', '3':'External'} + return timebase_dict[self._visainstrument.ask('TIMB?')] + + def trigger(self): + ''' + Send a trigger to the instrument. Used for List mode. + ''' + logging.debug(__name__ + ' : trigger') + self._visainstrument.write('*TRG') + + def list_on(self): + self._visainstrument.write('LSTE 1') + + def list_off(self): + self._visainstrument.write('LSTE 0') + + def do_get_list_mode(self): + ''' + Get whether the instrument is in list mode or not. + Returns True or False + ''' + return bool(self._visainstrument.ask('LSTE?')) + + def do_set_list_mode(self, on): + ''' + Set whether the instrument is in list mode or not. + ''' + self._visainstrument.write('LSTE %i' % on) + + def get_list_entry(self, index): + ''' + Get the list entry for a given index. + ''' + self._visainstrument.write('LSTI %i' % index) + return self._visainstrument.ask('LSTI?') + + def set_list_entry(self, index, *args, **kwargs): + ''' + list_entry creates a list state for the list mode of the instrument. + See page 80 of the manual. + ''' + logging.debug(__name__ + ' : list_entry index %i' %index) + command_list = ['N']*15 + if 'frequency' in kwargs: + command_list[0]=str(kwargs['frequency']) + if 'phase' in kwargs: + command_list[1]=str(kwargs['phase']) + if 'lf_amplitude' in kwargs: + command_list[2]=str(kwargs['lf_amplitude']) + if 'lf_offset' in kwargs: + command_list[3]=str(kwargs['lf_offset']) + if 'rf_amplitude' in kwargs: + command_list[4]=('%.2f' % kwargs['rf_amplitude']) + if 'font_panel_display' in kwargs: + if kwargs['front_panel_display'] in range(13): + command_list[5]=str(kwargs['front_panel_display']) + else: + logging.error('Incorrect value for front_panel_display.') + if 'enable_setting' in kwargs: + if kwargs['enable_setting'] in range(32): + command_list[6]=str(kwargs['enable_setting']) + else: + logging.error('Incorrect value for enable_setting') + if 'modulation_type' in kwargs: + ''' + 0 AM + 1 FM + 2 PhaseM + 3 Sweep + 4 Pulse + 5 Blank + 6 IQ (if option 3 is installed) + ''' + if kwargs['modulation_type'] in range(7): + command_list[7]=str(kwargs['modulation_type']) + + command_string = ','.join(command_list) + logging.info(__name__ + ' : command list: LSTP %i %s' %(index,command_string)) + self._visainstrument.write('LSTP %i,%s' %(index, command_string)) + + def create_list(self, size): + ''' + Create a list with a certain size. + ''' + answer = self._visainstrument.ask('LSTC? %i' % size) + if answer: + print 'List succesfully created.' + else: + print 'There was an error.' + + def get_error(self): + return self._visainstrument.ask('LERR?') + + # shortcuts + def off(self): + ''' + Set status to 'off' + + Input: + None + + Output: + None + ''' + self.set_status('off') + + def on(self): + ''' + Set status to 'on' + + Input: + None + + Output: + None + ''' + self.set_status('on') + diff --git a/instrument_plugins/Superlum_BS_1060.py b/instrument_plugins/Superlum_BS_1060.py new file mode 100755 index 00000000..899e59ce --- /dev/null +++ b/instrument_plugins/Superlum_BS_1060.py @@ -0,0 +1,497 @@ +# June 2013 - Gabriele de Boo +from instrument import Instrument +from lib import visafunc +from time import sleep +import visa +import logging +import types + +freqs = (0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000) + +def int2wvl(i): + wvl = 900.0+float(i)/4000*200 + return wvl + +def wvl2int(wvl): + i = (wvl-900.0)/200*4000 + return i + +class Superlum_BS_1060(Instrument): + def __init__(self, name, address, reset=False): + logging.info('Initializing instrument Superlum') + Instrument.__init__(self, name, tags=['physical']) + self._address = address + self._name = name + self._visainstrument = visa.instrument(self._address) + self._visainstrument.baud_rate = 57600 + self._visainstrument.term_chars = '\r\n' + + self._visainstrument.clear() + self._visainstrument.ask('') # It always returns 'AE' after the clear command + self._visainstrument.ask('S12') + +# self.add_function('reset') + self.add_function('identify') + self.add_function('set_to_local') + self.add_function('set_to_remote') + self.add_function('set_power_low') + self.add_function('set_power_high') + + self.add_parameter('optical_output', + type=types.BooleanType, + flags=Instrument.FLAG_GETSET) + self.add_parameter('booster_emission', + type=types.BooleanType, + flags=Instrument.FLAG_GET) + self.add_parameter('power', + type=types.StringType, + flags=Instrument.FLAG_GET, + option_list=( + 'low', + 'high')) + self.add_parameter('master_key_control', + type=types.BooleanType, + flags=Instrument.FLAG_GET) + self.add_parameter('full_tuning_range', + type=types.ListType, + flags=Instrument.FLAG_GET) + self.add_parameter('operating_mode', + type=types.StringType, + flags=Instrument.FLAG_GETSET, + option_list=( + 'manual', + 'external', + 'automatic', + 'modulation')) + self.add_parameter('manual_mode_wavelength', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, minval=1024.0, maxval=1094.0, units='nm') + self.add_parameter('sweep_mode_start', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, minval=1024.0, maxval=1094.0, units='nm') + self.add_parameter('sweep_mode_end', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, minval=1024.0, maxval=1094.0, units='nm') + self.add_parameter('sweep_speed', + type=types.IntType, + flags=Instrument.FLAG_GETSET, minval=2, maxval=10000, units='nm/s') + self.add_parameter('modulation_mode_wavelength1', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, minval=1024.0, maxval=1094.0, units='nm') + self.add_parameter('modulation_mode_wavelength2', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, minval=1024.0, maxval=1094.0, units='nm') + self.add_parameter('modulation_mode_frequency', + type=types.FloatType, + flags=Instrument.FLAG_GETSET, units='Hz', + option_list=freqs) + + self.get_all() + + def get_all(self): + self.identify() + self.get_optical_output() + self.get_booster_emission() + self.get_power() + self.get_master_key_control() + self.get_full_tuning_range() + self.get_operating_mode() + self.get_manual_mode_wavelength() + self.get_sweep_mode_start() + self.get_sweep_mode_end() + self.get_sweep_speed() + self.get_modulation_mode_wavelength1() + self.get_modulation_mode_wavelength2() + self.get_modulation_mode_frequency() +# self.get_Sweep_Slow() + + def identify(self): + reply = self._visainstrument.ask('S0') + if reply.startswith('S20'): + return reply[3:] + + def do_get_optical_output(self): + ''' + Probes whether the optical output is active. + + Input: + None + Output: + True when it is on, False when it is off + In case of an error a warning exception is raised. + ''' + logging.debug('Getting the optical output of %s.' % self._name) + reply = self.reply_error_check(self._visainstrument.ask('S20')) + + if reply.startswith('A2'): + data1 = int(reply[2:5]) + data2 = int(reply[6:7]) + if ((data1 < 97) or (data1 == 97) or (data1 ==113)): + return False + logging.info('The optical output of %s is off' % self._name) + else: + return True + logging.info('The optical output of %s is on' % self._name) + else: + logging.warning('%s responded with an unknown string: %s' % ( self._name, reply)) + raise Warning('%s responded with an unknown string: %s' % ( self._name, reply)) + + def do_set_optical_output(self, output): + ''' + Sets the optical output. + + Input: + True to turn the laser on + False to turn the laser off + Output: + None + ''' + logging.info('Setting the optical output of %s to %s.' % (self._name, output)) + if output: + if not self.do_get_optical_output(): + reply = self._visainstrument.ask('S21') + sleep(0.5) + self.get_booster_emission() + else: +# print 'Optical output is already enabled.' + logging.info('The optical output of %s already was on.' %self._name) + else: + if self.do_get_optical_output(): + reply = self._visainstrument.ask('S21') + self.get_booster_emission() + else: +# print 'Optical output is already disabled.' + logging.info('The optical output of %s already was off.' %self._name) + + def do_get_booster_emission(self): + ''' + Get the status of the booster emission. + + Input: + None + Output: + True if booster emission is on + False if booster emission is off + ''' + logging.info('Getting the status of the booster emission of %s.' % self._name) + reply = self.reply_error_check(self._visainstrument.ask('S20')) + if reply.startswith('A2'): + data1 = int(reply[2:5]) + data2 = int(reply[6:7]) + if (data2 == 2) or (data2 == 6): + return False + else: + return True + else: + logging.warning('%s responded with: %s.' % (self._name, reply)) + + def do_get_power(self): + reply = self.reply_error_check(self._visainstrument.ask('S40')) + if reply.startswith('A4'): + data1 = int(reply[2:5]) + data2 = int(reply[6:7]) + if data1 < 104: + return 'low' + if data1 > 112: + return 'high' + else: + return 0 + else: + logging.warning('get_power: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_power failed because the response was: %s.' % (self._name, reply)) + + def set_power_low(self): + if self.get_optical_output: + if self.get_power() == 'low': + logging.info('Power is already low.') + else: + reply = self.reply_error_check(self._visainstrument.ask('S41')) + else: + logging.warning('set_power_low failed for %s because the optical output is active.' % self._name) + raise Warning('The power of %s can not be changed because the optical output is active.' % self._name) + + def set_power_high(self): + if self.get_optical_output: + if self.get_power() == 'High': + logging.info('Power is already high.') + else: + reply = self._visainstrument.ask('S41') + else: + logging.warning('set_power_high failed for %s because the optical output is active.' % self._name) + raise Warning('The power of %s can not be changed because the optical output is active.' % self._name) + + def do_get_master_key_control(self): + ''' + Get the status of the Master Key control. + Input: + None + Output: + True when 1 + False when 0 + Raise warning if the instrument is under local control. + ''' + reply = self.reply_error_check(self._visainstrument.ask('S20')) + if reply.startswith('A2'): + data1 = int(reply[2:5]) + data2 = int(reply[6:7]) + if data1 < 97: + return False + else: + return True + else: + logging.warning('get_master_key_control: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_master_key_control failed because the response was: %s.' % (self._name, reply)) + +# def _send_and_read(self, message): +# logging.debug('Sending %r', message) +# reply = self._visainstrument.ask(message) +# return reply + + def set_to_local(self): + logging.debug('Setting to local.') + reply = self._visainstrument.ask('S11') + if reply == 'A11': + print 'Superlum set to local mode.' + else: + print 'Superlum command failed with error: ' + reply + + def do_get_full_tuning_range(self): + # The Full Tuning range consists of one list, with two lists inside + # [[end wavelength low power, start wavelength low power, end wavelength high power, start wavelength high power]] + logging.debug('Getting Full Tuning Range.') + reply = self.reply_error_check(self._visainstrument.ask('S52')) + if reply.startswith('A52'): + start_low = int2wvl(int(reply[3:7])) + reply = self._visainstrument.ask('S51') + if reply.startswith('A51'): + end_low = int2wvl(int(reply[3:7])) + reply = self._visainstrument.ask('S54') + if reply.startswith('A54'): + start_high = int2wvl(int(reply[3:7])) + reply = self._visainstrument.ask('S53') + if reply.startswith('A53'): + end_high = int2wvl(int(reply[3:7])) + return [[start_low, end_low], [start_high, end_high]] + + def do_get_operating_mode(self): + logging.debug('Getting operating mode.') + reply = self.reply_error_check(self._visainstrument.ask('S60')) + if reply.startswith('A6'): + if reply[2] == '1': + return 'manual' + elif reply[2] == '2': + return 'automatic' + elif reply[2] == '3': + return 'external' + elif reply[2] == '4': + return 'modulation' + else: + logging.warning('get_operating_mode: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_operating_mode failed because the response was: %s.' % (self._name, reply)) + + def do_set_operating_mode(self, mode): + if mode == 'manual': + self._visainstrument.ask('S61') + elif mode == 'automatic': + self._visainstrument.ask('S62') + elif mode == 'external': + self._visainstrument.ask('S63') + elif mode == 'modulation': + self._visainstrument.ask('S64') + else: + print 'Mode selection value is wrong, choose either manual, automatic, external or modulation.' + + def set_to_remote(self): + logging.debug('Setting to remote.') + reply = self._visainstrument.ask('S12') + if reply == 'A12': + print 'Superlum set to remote mode.' + else: + print 'Superlum command failed with error: ' + reply + + def do_get_manual_mode_wavelength(self): + reply = self.reply_error_check(self._visainstrument.ask('S71')) + if reply.startswith('A71'): + return int2wvl(reply[3:7]) + else: + logging.warning('get_manual_mode_Wavelength: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_manual_mode_Wavelength failed because the response was: %s.' % (self._name, reply)) + + def do_set_manual_mode_wavelength(self, wvl): + ''' + Set the wavelength in the Manual Mode + Input: + Wavelength in nanometers + Output: + None + ''' + logging.info('Setting the wavelength of %s to %.2f.' % (self._name, wvl)) + laser_string = '%0*d' % (4, wvl2int(wvl)) + reply = self.reply_error_check(self._visainstrument.ask('S81'+laser_string)) + if reply == ('A81'+laser_string): +# print 'Wavelength changed to %4.2f nm' % wvl + logging.debug('Wavelength succesfully set.') + else: +# print 'Error: ' + reply + logging.warning('set_manual_mode_wavelength: Failed with reply from laser: %s' % reply) + raise Warning('%s responded with an incorrect string: %s' % ( self._name, reply)) + + def do_get_sweep_mode_start(self): + logging.debug('Getting Sweep Mode Start.') + reply = self.reply_error_check(self._visainstrument.ask('S72')) + if reply.startswith('A72'): + return int2wvl(reply[3:7]) + else: + logging.warning('get_sweep_mode_start: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_sweep_mode_start failed because the response was: %s.' % (self._name, reply)) + + def do_set_sweep_mode_start(self, wvl): + logging.debug('Setting sweep mode start.') + laser_string = '%0*d' % (4, wvl2int(wvl)) + reply = self._visainstrument.ask('S82'+laser_string) + if reply == ('A82'+laser_string): + print 'Sweep Mode Start changed to %4.2f nm' % wvl + else: + print 'Error: ' + reply + + def do_get_sweep_mode_end(self): + logging.debug('Getting sweep mode end.') + reply = self.reply_error_check(self._visainstrument.ask('S73')) + if reply.startswith('A73'): + return int2wvl(reply[3:7]) + else: + logging.warning('get_Sweep_Mode_End: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_Sweep_Mode_End failed because the response was: %s.' % (self._name, reply)) + + def do_set_sweep_mode_end(self, wvl): + logging.debug('Setting sweep mode end.') + laser_string = '%0*d' % (4, wvl2int(wvl)) + reply = self._visainstrument.ask('S83'+laser_string) + if reply == ('A83'+laser_string): + print 'Sweep mode end changed to ' + wvl + else: + print 'Error: ' + reply + + def do_get_sweep_speed(self): + logging.debug('Getting sweep speed.') + # If the sweep speed is slow: + # 2 - 9 nm/s in steps of 1 nm + # If the sweep speed is fast: + # 0001 is the 4-byte code for 10 nm/s + # 1000 is the 4-byte code for 10000 nm/s + # Steps of 10 nm, so conversion is just multiplication by 10 + reply1 = self.reply_error_check(self._visainstrument.ask('S74')) + reply2 = self.reply_error_check(self._visainstrument.ask('S78')) + if reply1.startswith('A74'): + if int(reply1[3:7])>0: + return (10*int(reply1[3:7])) # Fast sweep speed + else: + return (reply2[3:5]) # Slow sweep speed + else: + logging.warning('get_sweep_speed: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_sweep_sweep failed because the response was: %s.' % (self._name, reply)) + + def do_set_sweep_speed(self, speed): + if speed < 10: + reply = self._visainstrument.ask('S88'+str(speed)) + if reply.startswith('A88'): + print 'Fast Sweep Speed set to %d nm/s' % speed + else: + print 'Error: ' + reply + else: + reply = self._visainstrument.ask('S84'+str(speed/10)) + if reply.startswith('A84'): + print 'Fast Sweep Speed set to %d nm/s' % speed + else: + print 'Error: ' + reply + + def do_get_modulation_mode_wavelength1(self): + logging.debug('Getting Modulation Mode Wavelength1.') + reply = self.reply_error_check(self._visainstrument.ask('S75')) + if reply.startswith('A75'): + return int2wvl(reply[3:7]) + else: + logging.warning('get_modulation_mode_wavelength1: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_modulation_mode_wavelength1 failed because the response was: %s.' % (self._name, reply)) + + def do_set_modulation_mode_wavelength1(self, wvl): + logging.debug('Setting modulation mode wavelength1.') + laser_string = '%0*d' % (4, wvl2int(wvl)) + reply = self.reply_error_check(self._visainstrument.ask('S85'+laser_string)) + if reply == ('A85'+laser_string): + print 'Modulation mode wavelength 1 set to ' + str(wvl) + else: + logging.warning('set_Modulation_Mode_Wavelength1: %s responded with %s.' % (self._name, reply)) + raise Warning('%s set_Modulation_Mode_Wavelength1 failed because the response was: %s.' % (self._name, reply)) + + def do_get_modulation_mode_wavelength2(self): + logging.debug('Getting modulation mode wavelength2.') + reply = self.reply_error_check(self._visainstrument.ask('S76')) + if reply.startswith('A76'): + return int2wvl(reply[2:6]) + else: + logging.warning('get_modulation_mode_wavelength2: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_modulation_mode_wavelength2 failed because the response was: %s.' % (self._name, reply)) + + def do_set_modulation_mode_wavelength2(self, wvl): + logging.debug('Setting modulation mode wavelength2.') + laser_string = '%0*d' % (4, wvl2int(wvl)) + reply = self.reply_error_check(self._visainstrument.ask('S86'+laser_string)) + if reply == ('A86'+laser_string): + print 'Modulation mode wavelength 1 set to ' + str(wvl) + else: + logging.warning('set_modulation_mode_wavelength2: %s responded with %s.' % (self._name, reply)) + raise Warning('%s set_modulation_mode_wavelength2 failed because the response was: %s.' % (self._name, reply)) + + def do_get_modulation_mode_frequency(self): + logging.debug('Getting the modulation mode frequency.') + reply = self.reply_error_check(self._visainstrument.ask('S77')) + if reply.startswith('A77'): + freq_number = int(reply[3:5]) + return freqs[freq_number-1] + else: + logging.warning('get_modulation_mode_frequency: %s responded with %s.' % (self._name, reply)) + raise Warning('%s get_modulation_mode_frequency failed because the response was: %s.' % (self._name, reply)) + + def do_set_modulation_mode_frequency(self, freq): + logging.debug('Setting the modulation mode frequency.') + if freq in freqs: + i = freqs.index(freq) + print i + laser_string = '%0*d' % (2,(i+1)) + print laser_string + reply = self._visainstrument.ask('S87'+laser_string) + if reply == ('A87'+laser_string): + print 'Modulation mode frequency set to ' + str(freq) + else: + print 'Error: ' + reply + else: + print 'Frequency not in allowed frequencies' + print 'Allowed frequencies' + str(freqs) + + def reply_error_check(self, reply): + ''' + The instrument replies with two error messages: + : Instrument is under local control. + Any query except the control change query is denied. + : General error. + + If any of these errors occur the program should throw an exception + because the errors are avoidable. + Input: + Reply from the instrument + Output: + Reply from the instrument + ''' + if reply == 'AL': + logging.warning('%s responded with AL.' % self._name) + raise Warning( + 'The function could not be executed becase %s is under local control.' + % self._name) + elif reply == 'AE': + logging.warning('%s responded with AE.' % self._name) + raise Warning( + 'The function could not be executed becase %s responded with a general error.' + % self._name) + else: + return reply diff --git a/instrument_plugins/Thorlabs_FiberSwitch.py b/instrument_plugins/Thorlabs_FiberSwitch.py new file mode 100644 index 00000000..03bc1b7c --- /dev/null +++ b/instrument_plugins/Thorlabs_FiberSwitch.py @@ -0,0 +1,120 @@ +# Thorlabs_FiberSwitch.py - Instrument plugin to communicate with +# a Thorlabs Fiberswitch +# Gabriele de Boo +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from instrument import Instrument +from qt import msleep +import logging +from visa import SerialInstrument +import types + +class Thorlabs_FiberSwitch(Instrument): + ''' + Thorlabs Fiber Switch + + The switch is being used to switch between two inputs for a connected + wavemeter. The wavemeter reading should be accessed through this wrapper + so that the correct reading is given for the specified port and because + it will block access during that time for other readings. + + When creating the instrument the used wavemeter should be specified. + + ''' + + def __init__(self, name, address, wavemeter, reset=False): + logging.debug('Initializing fiber switch on port %s.' % address) + Instrument.__init__(self, name, tags=['physical']) + self._visainstrument = SerialInstrument(address) + self._visainstrument.baud_rate = 115200 + self._visainstrument.term_chars = '\n' + + self.wait_time = 0.3 + self._wavemeter = wavemeter + + self.add_parameter('active_port', + type=types.IntType, + flags=Instrument.FLAG_GETSET, + minval=1, maxval=2) + self.add_parameter('port1_wavelength', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='nm') + self.add_parameter('port2_wavelength', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='nm') + self.add_parameter('port1_power', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='mW') + self.add_parameter('port2_power', + type=types.FloatType, + flags=Instrument.FLAG_GET, + units='mW') + + if reset: + self.reset() + else: + self.get_all() + +#### initialization related + + def reset(self): + print __name__ + ' : resetting instrument' + + def get_all(self): + print __name__ + ' : reading all settings from instrument' + self.get_active_port() + self.get_port1_wavelength() + self.get_port1_power() + self.get_port2_wavelength() + self.get_port2_power() + +#### communication with machine + def do_get_active_port(self): + return self._visainstrument.ask('S?') + + def do_set_active_port(self, port): + self._visainstrument.write('S %i' %port) + if self.get_active_port() == port: + return True + else: + raise Warning('The switch did not reply with the expected port.') + + def do_get_port1_wavelength(self): + if self.get_active_port() == 2: + self.set_active_port(1) + msleep(self.wait_time) + return self._wavemeter.get_wavelength() + + def do_get_port2_wavelength(self): + if self.get_active_port() == 1: + self.set_active_port(2) + msleep(self.wait_time) + return self._wavemeter.get_wavelength() + + def do_get_port1_power(self): + if self.get_active_port()==2: + self.set_active_port(1) + msleep(self.wait_time) + return self._wavemeter.get_power() + + def do_get_port2_power(self): + if self.get_active_port()==1: + self.set_active_port(2) + msleep(self.wait_time) + return self._wavemeter.get_power() diff --git a/source/lib/gui/functionframe.py b/source/lib/gui/functionframe.py index 0beef5c0..dc89a1cb 100644 --- a/source/lib/gui/functionframe.py +++ b/source/lib/gui/functionframe.py @@ -46,8 +46,8 @@ def set_arg_spec(self, argspec): if argspec is None: return - names = argspec['args'] - defaults = argspec['defaults'] + names = argspec.args + defaults = argspec.defaults for i, name in enumerate(names): if name in self._exclude: continue diff --git a/source/lib/misc.py b/source/lib/misc.py index bc0157be..14aebb9b 100644 --- a/source/lib/misc.py +++ b/source/lib/misc.py @@ -3,6 +3,7 @@ import types import sys import time +from IPython import get_ipython def dict_to_ordered_tuples(dic): '''Convert a dictionary to a list of tuples, sorted by key.''' @@ -25,12 +26,6 @@ def get_dict_keys(dic, keys): ret[key] = dic[key] return ret -def invert_dict(dic): - ret = {} - for key, val in dic.iteritems(): - ret[val] = key - return ret - def seconds_to_str(secs): '''Convert a number of seconds to hh:mm:ss string.''' hours = np.floor(secs / 3600) @@ -100,55 +95,23 @@ def usleep(usec): while (exact_time() - start) * 1e6 < usec: pass -def get_ipython(): - import IPython - if ipython_is_newer((0, 11)): - return IPython.core.ipapi.get() - else: - return IPython.ipapi.get() - def get_traceback(): - if ipython_is_newer((0, 11)): - from IPython.core.ultratb import AutoFormattedTB - else: - from IPython.ultraTB import AutoFormattedTB + from IPython.core.ultratb import AutoFormattedTB return AutoFormattedTB -def ipython_is_newer(vin): - """ - vin is tuple of version (a,b,c) for version "a.b.c" - result gives True for larger or equal version - """ - import IPython - vs = IPython.__version__.split('.') - for i in range(len(vs)): - if i > (len(vin)-1): - return True - if int(vs[i]) > vin[i]: - return True - elif int(vs[i]) < vin[i]: - return False - return True - def is_ipython(): return get_ipython() != None def exit_shell(): if is_ipython(): ip = get_ipython() - if ipython_is_newer((0, 11)): - ip.exit() # FIXME This gives annoying request for y/n when called - else: - ip.magic('Exit') + ip.exit() # FIXME This gives annoying request for y/n when called sys.exit() def register_exit(func): if is_ipython(): ip = get_ipython() - if ipython_is_newer((0, 11)): - ip.hooks['shutdown_hook'].add(func, 1) - else: - ip.IP.hooks.shutdown_hook.add(func, 1) + ip.hooks['shutdown_hook'].add(func, 1) else: import atexit atexit.register(func)