diff --git a/cfg/lockin_cfg.py b/cfg/lockin_cfg.py new file mode 100644 index 0000000..dc6415c --- /dev/null +++ b/cfg/lockin_cfg.py @@ -0,0 +1,10 @@ +Node('lockintest.psi.ch', + 'lockin test', + 'tcp://5000', + ) + +Mod('io', + 'frappy_psi.SR_7270.SR7270', + 'lockin communication', + uri='10105266.psi.ch:50000', + ) diff --git a/frappy_psi/FG_Lecroy_3000.py b/frappy_psi/FG_Lecroy_3000.py new file mode 100644 index 0000000..618fc38 --- /dev/null +++ b/frappy_psi/FG_Lecroy_3000.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# ***************************************************************************** +# 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., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Module authors: +# Daniel Margineda +# ***************************************************************************** +"""WAVE FUNCTION LECROY XX: SIGNAL GENERATOR + +modifications not tested! +""" + +from frappy.core import Readable, Parameter, FloatRange, \ + IntRange, BoolType, EnumType, Module, Property, HasIO + + +class Channel(HasIO, Module): + channel = Property('choose channel to manipulate', IntRange(1, 2)) + + # seperate module (Writeable): + freq = Parameter('frequency', FloatRange(1e-6, 20e6, unit='Hz'), + initwrite=True, default=1000) + # seperate module (Writable): + amp = Parameter('exc_volt_int', FloatRange(0.00, 5, unit='Vrms'), + readonly=False, initwrite=True, default=0.1) + offset = Parameter('offset_volt_int', FloatRange(0.0, 10, unit='V'), + readonly=False, initwrite=True, default=0.0) + wave = Parameter('type of wavefunction', + EnumType('WaveFunction', SINE=1, SQUARE=2, RAMP=3, PULSE=4, NOISE=5, ARB=6, DC=7), + readonly=False, default='SINE') + phase = Parameter('signal phase', FloatRange(0, 360, unit='deg'), + readonly=False, initwrite=True, default=0) + enabled = Parameter('enable output channel', datatype=EnumType('OnOff', OFF=0, ON=1), + readonly=False, default='OFF') + symm = Parameter('wavefunction symmetry', FloatRange(0, 100, unit=''), + readonly=False, default=0) + + def read_value(self): + return self.communicate('C%d:BSWV FRQ?' % self.channel) + + def write_target(self, value): + self.communicate('C%d:BSWV FRQ, %gHz' % (self.channel, value)) + return value + + # signal wavefunction parameter + def read_wave(self): + return self.communicate('C%d:BSWV WVTP?' % self.channel) + + def write_wave(self, value): # string value + self.communicate('C%d:BSWV WVTP, %s' % (self.channel, value.name)) + return value + + # signal amplitude parameter + def read_amp(self): + return self.communicate('C%d:BSWV AMP?' % self.channel) + + def write_amp(self, value): + self.communicate('C%d:BSWV AMP, %g' % (self.channel, value)) + return value + + # offset value parameter + def read_offset(self): + return self.communicate('C%d:BSWV OFST?' % self.channel) + + def write_offset(self, value): + self.communicate('C%d:BSWV OFST %g' % (self.channel, value)) + return value + + # channel symmetry + def read_symm(self): + return self.communicate('C%d:BSWV SYM?' % self.channel) + + def write_symm(self, value): + self.communicate('C%d:BSWV SYM %g' % (self.channel, value)) + return value + + # wave phase parameter + def read_phase(self): + return self.communicate('C%d:BSWV PHSE?' % self.channel) + + def write_phase(self, value): + self.communicate('C%d:BSWV PHSE %g' % (self.channel, value)) + return value + + # dis/enable output channel + def read_enabled(self): + return self.communicate('C%d: OUTP?' % self.channel) + + def write_enabled(self, value): + self.communicate('C%d: OUTP %s' % (self.channel, value.name)) + return value + + +# devices are defined as arg less output enable what is defined as arg2 + +class arg(Readable): + pollerClass = None + value = Parameter(datatype=FloatRange(unit='')) + + +class arg2(Readable): + pollerClass = None + value = Parameter(datatype=BoolType()) diff --git a/frappy_psi/SR_7270.py b/frappy_psi/SR_7270.py new file mode 100644 index 0000000..fea4f1c --- /dev/null +++ b/frappy_psi/SR_7270.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# ***************************************************************************** +# 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., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Module authors: +# Daniel Margineda +# ***************************************************************************** +"""Signal Recovery SR7270: lockin amplifier for AC susceptibility""" + +from frappy.core import Readable, Parameter, Command, FloatRange, TupleOf, \ + HasIO, StringIO, Attached, IntRange, BoolType, EnumType + + +class SR7270(StringIO): + end_of_line = b'\x00' + + def communicate(self, command): # remove dash from terminator + reply = StringIO.communicate(self, command) + status = self._conn.readbytes(2, 0.1) # get the 2 status bytes + return reply + ';%d;%d' % tuple(status) + + +class XY(HasIO, Readable): + x = Attached() + y = Attached() + freq_arg = Attached() + amp_arg = Attached() + tc_arg = Attached() + phase_arg = Attached() + dac_arg = Attached() + + # parameters required an initial value but initwrite write the default value for polled parameters + value = Parameter('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V'))) + + # separate module (Writable) + freq = Parameter('exc_freq_int', + FloatRange(0.001, 250e3, unit='Hz'), + readonly=False, default=1000) # initwrite=True, + # separate module (Writable) + amp = Parameter('exc_volt_int', + FloatRange(0.00, 5, unit='Vrms'), + readonly=False, default=0.1) # initwrite=True, + # unify the following + range = Parameter('sensitivity value', FloatRange(0.00, 1, unit='V'), default=1) + irange = Parameter('sensitivity index', IntRange(0, 27), readonly=False, default=25) + + autorange = Parameter('autorange_on', EnumType('autorange', off=0, soft=1, hard=2), + readonly=False, default=0) # , initwrite=True + + # unify the following + tc = Parameter('time constant value', FloatRange(10e-6, 100, unit='s'), default=0.1) + itc = Parameter('time constant index', IntRange(0, 30), readonly=False, default=14) + + nm = Parameter('noise mode', BoolType(), readonly=False, default=0) + phase = Parameter('Reference phase control', FloatRange(-360, 360, unit='deg'), + readonly=False, default=0) + + # convert to enum + vmode = Parameter('Voltage input configuration', IntRange(0, 3), readonly=False, default=3) + # dac = Parameter('output DAC channel value', datatype=TupleOf(IntRange(1, 4), FloatRange(0.0, 5000, unit='mV')), + # readonly=False, initwrite=True, default=(3,0)) + # dac = Parameter('output DAC channel value', FloatRange(-10000, 10000, unit='mV'), + # readonly=False, initwrite=True, default=0) + + ioClass = SR7270 + + def comm(self, command): + reply, status, overload = self.communicate(command).split(';') + if overload != '0': + self.status = self.Status.WARN, 'overload %s' % overload + else: + self.status = self.Status.IDLE, '' + return reply + + def read_value(self): + reply = self.comm('XY.').split(',') + x = float(reply[0]) + y = float(reply[1]) + if self.autorange == 1: # soft + if max(abs(x), abs(y)) >= 0.9*self.range and self.irange < 27: + self.write_irange(self.irange+1) + elif max(abs(x), abs(y)) <= 0.3*self.range and self.irange > 1: + self.write_irange(self.irange-1) + self._x.value = x # to update X,Y classes which will be the collected data. + self._y.value = y + return x, y + + def read_freq(self): + reply = self.comm('OF.') + return reply + + def write_freq(self, value): + self.comm('OF. %g' % value) + return value + + def write_autorange(self, value): + if value == 2: # hard + self.comm('AS') # put hardware autorange on + self.comm('AUTOMATIC. 1') + else: + self.comm('AUTOMATIC. 0') + return value + + def read_autorange(self): + reply = self.comm('AUTOMATIC') + # determine hardware autorange + if reply == 1: # "hardware auto range is on" + return 2 # hard + if self.autorange == 0: # soft + return self.autorange() # read autorange + return reply # off + + # oscillator amplitude module + def read_amp(self): + reply = self.comm('OA.') + return reply + + def write_amp(self, value): + self.comm('OA. %g' % value) + return value + + # external output DAC + #def read_dac(self): + # # reply = self.comm('DAC %g' % channel) # failed to add the DAC channel you want to control + # reply = self.comm('DAC 3') # stack to channel 3 + # return reply + + #def write_dac(self, value): + # # self.comm('DAC %g %g' % channel % value) + # self.comm('DAC 3 %g' % value) + # return value + + # sensitivity module + def read_range(self): + reply = self.comm('SEN.') + return reply + + def write_irange(self, value): + self.comm('SEN %g' % value) + self.read_range() + return value + + def read_irange(self): + reply = self.comm('SEN') + return reply + + # time constant module/ noisemode off or 0 allows to use all the time constant range + def read_nm(self): + reply = self.comm('NOISEMODE') + return reply + + def write_nm(self, value): + self.comm('NOISEMODE %d' % int(value)) + self.read_nm() + return value + + def read_tc(self): + reply = self.comm('TC.') + return reply + + def write_itc(self, value): + self.comm('TC %g' % value) + self.read_tc() + return value + + def read_itc(self): + reply = self.comm('TC') + + return reply + + # phase and autophase + def read_phase(self): + reply = self.comm('REFP.') + return reply + + def write_phase(self, value): + self.comm('REFP %d' % round(1000*value, 0)) + self.read_phase() + return value + + @Command() + def aphase(self): + """auto phase""" + self.read_phase() + reply = self.comm('AQN') + self.read_phase() + + # voltage input configuration 0:grounded,1=A,2=B,3=A-B + # def read_vmode(self): + # reply = self.comm('VMODE') + # return reply + + def write_vmode(self, value): + self.comm('VMODE %d' % value) + # self.read_vmode() + return value + + +class Comp(Readable): + enablePoll = False + value = Parameter(datatype=FloatRange(unit='V')) + + +class arg(Readable): + enablePoll = False + value = Parameter(datatype=FloatRange(unit=''))