wanglib
¶
Experimental control utilities for the Wang lab.
When writing a script to control your experiment (or working
interactively using the interpreter), use wanglib
to make
instrument control and data gathering easy.
Obtaining and Installing¶
wanglib
is hosted on Github. Follow the instructions there on how
best to install the package and its dependencies.
Contents¶
Instrument control with wanglib.instruments
¶
Class-based interfaces to various scientific instruments.
These interfaces are designed to complement the low-level instrument
talking already provided by PySerial (for RS232) and PyVISA
(for GPIB). Each instrument object defined here wraps a
serial.Serial
or visa.instrument
instance and uses
its write
/read
/ask
methods to accomplish common commands
and readings specific to that instrument.
Example usage¶
Here’s an example. We want to talk to an Agilent model 8648 RF signal generator using GPIB. We have PyVISA installed, and that makes GPIB talking a snap:
>>> from visa import instrument
>>> agilent = instrument("GPIB::18")
>>> agilent.ask("FREQ:CW?")
'200000000'
Three lines of code isn’t bad, but it’s cumbersome to write raw commands to the instrument all the time. Plus, the returned value is a string, not a number, and we’ll have to convert it.
Fortunately, wanglib defines a class that handles all these commands for us.
>>> from wanglib.instruments.signal_generators import ag8648
>>> rf = ag8648(agilent)
>>> rf.freq
200.
What happened here? Well, the ag8648 class we imported from wanglib has ‘wrapped’ the agilent object we made before, and returned an object representing our signal generator. This object has a variable attached to it (an ‘attribute’) representing the frequency. Whenever we access this attribute, the object performs the GPIB query behind the scenes and converts the instrument response to a number in MHz.
We can also change the attribute:
>>> rf.freq = 110
>>> rf.freq
110.
Again, all queries and commands are being handled behind the scenes. This makes your scripts much more readable, and is a especially useful for interactive use. If all of your instruments are supported by wanglib, you can feasibly run your whole experiment from a live python interpreter.
For a list of all you can do with this rf object, do
>>> dir(rf)
And, as always in Python, use the help() function for information on any object, attribute, or method.
>>> help(rf)
>>> help(rf.freq)
>>> help(rf.blink)
If the ag8648 class doesn’t have an attribute or method for a given instrument function, you can still send raw GPIB queries by accessing the original PyVISA object as a sub-object of the ag8648 instance.
>>> rf.bus.ask("FREQ:CW?")
'110000000'
In this example, we wrapped a PyVISA instrument, but that’s not required. The low-level instrument we started with can be anything that has similar read(), write(), and ask() methods:
PyVISA: visa.instrument linux-gpib: wanglib.linux_gpib.Gpib prologix: wanglib.prologix.instrument
It’s also easy to add functionality to the class. The help() function tells you where to find the source file for any object on your computer.
Supported instruments¶
Lock-in amplifiers: wanglib.instruments.lockins
¶
Lock-in amplifiers are commonly used for sensitive detection of a modulated voltage signal. They enable us to measure both the amplitude and phase of a signal, which we can access in either the cartesian (X, Y) or polar (R, phase) basis.
This module provides interfaces to two brands of lock-in, using two corresponding classes.
EG&G 5110: wanglib.instruments.lockins.egg5110
SRS 830: wanglib.instruments.lockins.srs830
Note
The methods implemented by these two classes are named the same, but don’t always behave the same way. For example, the EG&G 5110 returns a 2-tuple with unit when the ADC ports are queried, but the SRS 830 always returns a figure in volts.
Warning
I’m working toward parity between the return value formats of the two classes. This will make it easier to switch between lock-ins, but will break existing code!
-
class
wanglib.instruments.lockins.
egg5110
(bus)¶ An EG&G model 5110 lock-in.
Typically controlled over GPIB, address 12. Instantiate like:
>>> li = egg5110(plx.instrument(12))
where
plx
is a prologix controller. pyVISA instruments should also work fine.-
autophase
()¶ Automatically adjust the reference phase to maximize the X signal and minimize Y.
-
get_ADC
(n)¶ Read one of the four ADC ports. Return value in volts.
-
get_phase
()¶ Get current value of the phase, in degrees.
-
get_r
()¶ Get current value of R, in volts.
-
get_sensitivity
(unit='V')¶ Get the current sensitivity, in Volts.
>>> li.get_sensitivity() 0.1
If the unit kwarg is specified, the value will be converted to the desired unit instead.
>>> li.get_sensitivity(unit='uV') 100000.
Using unit=True will return a value in a 2-tuple along with the most sensible unit (as a string).
>>> li.get_sensitivity(unit=True) (100, 'mV')
-
get_timeconst
()¶ Get the current time constant (as a 2-tuple).
-
get_x
()¶ Get current value of X, in volts.
-
get_y
()¶ Get current value of Y, in volts.
-
lights
¶ Boolean. Turns the front panel lights on or off.
-
measure
(command, unit='V')¶ Measure one of the usual voltage signals (X, Y, or MAG).
>>> li.measure('X') 0.0014
Results are given in volts. To specify a different unit, use the
unit
kwarg.>>> li.measure('X', unit='mV') 1.4
To skip this conversion, and instead return the result as a fraction of the sensitivity (what the manual calls “percent of full-scale”), specify
unit=None
:>>> li.measure('X', unit=None) .14
You will need to multiply by the sensitivity (in this example, 10mV) to get a meaningful number. To perform this multiplication automatically, specify
unit=True
:>>> li.measure('X', unit=True) (1.4, 'mV')
This returns a 2-tuple containing the measurement and the unit string (“V”, “mV”, etc.),
Note
to provide an answer in real units, the EG&G 5110 needs to be queried for its sensitivity on every single measurement. This can slow things down. If you need to make measurements quickly, and are using a fixed sensitivity, specify
unit=None
for speed.
-
phase
¶ Get current value of the phase, in degrees.
-
r
¶ Get current value of R, in volts.
-
sensitivities
= {0: (100, 'nV'), 1: (200, 'nV'), 2: (500, 'nV'), 3: (1, 'uV'), 4: (2, 'uV'), 5: (5, 'uV'), 6: (10, 'uV'), 7: (20, 'uV'), 8: (50, 'uV'), 9: (100, 'uV'), 10: (200, 'uV'), 11: (500, 'uV'), 12: (1, 'mV'), 13: (2, 'mV'), 14: (5, 'mV'), 15: (10, 'mV'), 16: (20, 'mV'), 17: (50, 'mV'), 18: (100, 'mV'), 19: (200, 'mV'), 20: (500, 'mV'), 21: (1, 'V')}¶
-
sensitivity
¶ Get the current sensitivity, in Volts.
>>> li.get_sensitivity() 0.1
If the unit kwarg is specified, the value will be converted to the desired unit instead.
>>> li.get_sensitivity(unit='uV') 100000.
Using unit=True will return a value in a 2-tuple along with the most sensible unit (as a string).
>>> li.get_sensitivity(unit=True) (100, 'mV')
-
set_sensitivity
(code)¶ Set the current sensitivity (Using a code).
-
set_timeconst
(code)¶ Set the current time constant (Using a code).
-
timeconst
¶ Get the current time constant (as a 2-tuple).
-
timeconsts
= {0: (0, 'MIN'), 1: (1, 'ms'), 2: (3, 'ms'), 3: (10, 'ms'), 4: (30, 'ms'), 5: (100, 'ms'), 6: (300, 'ms'), 7: (1, 's'), 8: (3, 's'), 9: (10, 's'), 10: (30, 's'), 11: (100, 's'), 12: (300, 's')}¶
-
x
¶ Get current value of X, in volts.
-
y
¶ Get current value of Y, in volts.
-
-
class
wanglib.instruments.lockins.
srs830
(bus)¶ A Stanford Research Systems model SR830 DSP lock-in.
Typically controlled over GPIB, address 8. Instantiate like:
>>> li = srs830(plx.instrument(8))
where
plx
is a prologix controller. pyVISA instruments should also work fine.-
ADC_cmd
= 'OAUX?%d'¶
-
ADC_range
= (1, 2, 3, 4)¶
-
DAC_range
= (1, 2, 3, 4)¶
-
get_ADC
(n)¶ read one of the ADC ports. Return value in volts.
-
get_DAC
(n)¶ read one of the DAC ports. Return value in volts.
-
get_r
()¶
-
get_x
()¶
-
get_y
()¶
-
measure
(command)¶ Measure one of the usual signals (X, Y, or MAG).
Results are given in units of volts or degrees.
-
measurements
= {'Y': 2, 'X': 1, 'R': 3, 'MAG': 3}¶
-
r
¶
-
set_DAC
(n, value)¶ set one of the DAC ports. Provide value in volts.
-
x
¶
-
y
¶
-
Jobin-Yvon spectrometers: wanglib.instruments.spex750m
¶
This module contains utilities for controlling Jobin-Yvon “SPEX” series monochromators over RS232 serial.
- Classes defined:
Tutorial¶
both spex750m
and triax320
behave roughly the same
way. In this tutorial we use the 750M for example. Instantiate like:
>>> beast = spex750m()
This opens a connection with the larger of the two spectrometers (the SPEX 750M.)
Classes are configured to look for the spectrometer at the serial port where they are normally plugged in. To specify a different serial port, just pass it as an optional parameter when instantiating. For example, the following should be equivalent:
>>> beast = spex750m(addr=1)
>>> beast = spex750m(addr="COM2") # on windows
>>> beast = spex750m(addr="/dev/ttyS1") # on linux
It’s a good idea to check that the spectrometer has been
calibrated. This is unneccessary for the Triax, but on the 750M, we
should check it. Having instantiated it as beast
, run
>>> beast.wl
790.
This queries the current wavelength in nm, which ought to match the value displayed in the window. If it doesn’t, run
>>> beast.calibrate(800)
This will re-set the calibration to 800nm:
>>> beast.wl
800.
You can control the spectrometer using the methods documented below. For example, this performs a wavelength scan:
>>> beast = spex750m('/dev/ttyUSB0')
>>> beast.calibrate(800)
>>> beast.set_wavelength(750)
>>> for i in range(200):
... beast.rel_move(0.5)
... while beast.is_busy():
... sleep(0.1)
... result = measure_something()
... print beast.get_wavelength(), result
API documentation¶
-
class
wanglib.instruments.spex750m.
spex750m
(addr=None)¶ A class implementing standard Jobin-Yvon serial commands for simple spectrometers like the SPEX 750M.
By default, this class is configured to look for the 750M plugged into
/dev/ttyUSB0
(the first port on the USB-serial adapter, when run under linux).-
boot_status_check
()¶ Check the boot status of the controller.
- * : Just Autobauded
- B : Boot Acknowledged
- F : Just Flashed
-
calibrate
(wl_value)¶ Read the current wavelength from the window and pass it to this method (units of nm) to recalibrate the 750M.
-
get_wavelength
()¶ Query the current wavelength
-
get_wl
()¶ Query the current wavelength
-
init_hardware
()¶ Initialize 750M hardware. I don’t know why this works, I just copied Yan’s LabView routine.
-
is_busy
()¶ Check if the motors are busy.
-
reboot
()¶ Reboot the controller if it’s not responding
-
rel_move
(distance_to_move)¶ Move the grating by the given number of nanometers.
-
set_wavelength
(wl)¶ Move to the wavelength value specified. contingent on proper calibration, of course.
-
set_wl
(wl)¶ Move to the wavelength value specified. contingent on proper calibration, of course.
-
wait_for_ok
(expected_bytes=1)¶ Wait indefinitely for the ‘o’ status byte.
This function waits until a certain number of bytes (usually just one) are present on the bus. When that data arrives, the first bye is read and checked to make sure it’s the “okay” status.
-
wavelength
¶ Query the current wavelength
-
wl
¶ Query the current wavelength
-
-
class
wanglib.instruments.spex750m.
triax320
(addr=None)¶ A class implementing Jobin-Yvon serial commands for more advanced spectrometers like the TRIAX 320.
Instantiate as you would a spex750m. If you don’t specify a serial port, this class will assume the spectrometer is attached to
/dev/ttyUSB1
, the second port on the USB-serial converter.- Unlike the 750M, the Triax
- has motorized entrance and exit slits
- zeroes its grating on power-up.
To perform a motor init on the triax, call
motor_init()
.-
calibrate
(wl)¶ Set wavelength of Triax without moving motor
-
entr_slit
¶
-
exit_slit
¶
-
get_wavelength
()¶ Query the current wavelength
-
get_wl
()¶ Query the current wavelength
-
motor_init
()¶ Move all motors to their power-up (autocal) positions.
This zeroes the wavelength grating and both entrance and exit slits. Don’t forget to reopen the slits after calling this.
-
set_wavelength
(wl)¶ Move to a new wavelength
-
set_wl
(wl)¶ Move to a new wavelength
-
slits
¶ Return the entrance and exit slit settings together.
>>> beast.slits (30., 30.)
Indicates that both slits are at 30. They can also be set together:
>>> beast.slits = (20,30) >>> beast.slits (20., 30.)
sets the entrance slit to 20. There is a shortcut for setting the slits to equal values:
>>> beast.slits = 20 >>> beast.slits (20., 20.)
-
wavelength
¶ Query the current wavelength
-
wl
¶ Query the current wavelength
Motion control: wanglib.instruments.stages
¶
Interfaces to motion controllers.
Newport motion cotroller command syntax has significant overlap between models, so I’ve written several classes to keep things as modular as possible.
To control a stage attached to a Newport ESP300 controller, which is on address 9 of a GPIB network run by a prologix controller ‘plx’, you might do this:
>>> from wanglib.instruments.stages import ESP300_stage
>>> esp = plx.instrument(9)
>>> example_stage = ESP300_stage(1, esp)
Here the ‘esp’ object is the prologix GPIB connection, but pyVISA instruments should also work.
To control another axis of the stage, just make another ESP300_stage instance using the same instrument object.
>>> other_stage = ESP300_stage(2, esp)
This creates another stage on axis 2.
This class also defines handy classes specific to actual stages that are on the table, and you probably want those. For example:
>>> from wanglib.instruments.stages import long_stage
>>> from wanglib.instruments.stages import short_stage
Will get two delay stages, with extra properties representing the delay in picoseconds, etc.
-
class
wanglib.instruments.stages.
ESP300_stage
(axisnum, bus=None)¶ A single stage controlled by the ESP300.
The ESP300 is typically on GPIB address 9.
- To use over RS232, use the following parameters:
baudrate: 19200 rtscts: True term_chars: ‘\r\n’
These settings are used by default if you simply pass the name of the serial port as a string:
>>> my_stage = ESP300_stage(1, '/dev/ttyUSB')
This will make an object corresponding to axis 1 of the stage.
For full control over the RS232 communication, provide a
Serial
instance instead of an address. For example:>>> from wanglib.util import Serial >>> esp = Serial('/dev/ttyUSB', baudrate=19200, timeout=10, ... rtscts=1, log='esp300.log', term_chars="\r\n") >>> my_stage = ESP300_stage(1, esp)
This will work the same as above, but also log command traffic to the file
esp300.log
.-
busy
¶ ask whether motion is in progress
-
cmd
(string)¶ Prepend the axis number to a command.
-
define_home
(loc=None)¶ Define the origin of this stage to be its current position.
To define the current position to be some number other than zero, provide that number in the loc kwarg.
-
encoder_resolution
¶ Get the distance represented by one encoder pulse.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_max_velocity
()¶ Get the maximum motor velocity.
-
get_pos
()¶ Query the absolute position of the stage
-
get_velocity
()¶ Get the current motor velocity.
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
on
¶ Turn motor on/off.
-
pos
¶ Query the absolute position of the stage
-
set_max_velocity
(val)¶ Set the max motor velocity.
-
set_pos
(val)¶ Set the absolute position of the stage
-
set_unit
(key)¶ Set the unit label for a given axis, by index.
Unit labels (‘mm’, ‘um’, etc) have corresponding integer indices. Look these up in the _unit_labels dictionary.
-
set_velocity
(val)¶ Set the motor velocity.
-
step_size
¶ Get the distance represented by one motor step.
-
unit
¶ Get the unit label for a given axis.
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
class
wanglib.instruments.stages.
MM3000_stage
(axisnum, bus=None)¶ A single stage controlled by the Newport MM3000 motion controller.
Firmware version: 2.2
The MM3000 is typically on GPIB address 8.
-
busy
¶
-
cmd
(string)¶ Prepend the axis number to a command.
-
define_home
()¶ Define the origin of this stage to be its current position.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_pos
()¶ Query the absolute position of the stage
-
motor_status
(bit=None)¶ Request the MM3000 motor status byte.
- Optionally, pick out a specific bit.
- bit 0: True if axis is moving bit 1: True if motor is off bit 2: True if direction of move is positive bit 3: True if positive travel limit is active bit 4: True if negative travel limit is active bit 5: True if positive side of home bit 6: always True bit 7: always False
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
on
¶
-
pos
¶ Query the absolute position of the stage
-
set_pos
(val)¶ Set the absolute position of the stage
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
-
class
wanglib.instruments.stages.
delay_stage
(axisnum, bus=None)¶ Mixin class for stages used primarily to delay pulses.
Defines one extra feature: the ‘t’ attribute, which is basically the position of the stage in picosecond units.
- When mixing in, you need to define two extra attributes:
stage_length: length of the stage, in its natural length units. c: speed of light, in natural length units per picosecond.
Important: make sure to call ‘find_zero’ on the stage before using t to control motion. Otherwise you might run out of range.
-
cmd
(string)¶ Prepend the axis number to a command.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_pos
()¶ Query the absolute position of the stage
-
get_t
()¶ Convert stage position in mm to delay in ps
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
pos
¶ Query the absolute position of the stage
-
set_pos
(val)¶ Set the absolute position of the stage
-
set_t
(new_val)¶
-
t
¶ Convert stage position in mm to delay in ps
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
class
wanglib.instruments.stages.
long_stage
(axisnum, bus=None)¶ -
busy
¶ ask whether motion is in progress
-
c
= 0.3¶
-
cmd
(string)¶ Prepend the axis number to a command.
-
define_home
(loc=None)¶ Define the origin of this stage to be its current position.
To define the current position to be some number other than zero, provide that number in the loc kwarg.
-
encoder_resolution
¶ Get the distance represented by one encoder pulse.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_max_velocity
()¶ Get the maximum motor velocity.
-
get_pos
()¶ Query the absolute position of the stage
-
get_t
()¶ Convert stage position in mm to delay in ps
-
get_velocity
()¶ Get the current motor velocity.
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
on
¶ Turn motor on/off.
-
pos
¶ Query the absolute position of the stage
-
set_max_velocity
(val)¶ Set the max motor velocity.
-
set_pos
(val)¶ Set the absolute position of the stage
-
set_t
(new_val)¶
-
set_unit
(key)¶ Set the unit label for a given axis, by index.
Unit labels (‘mm’, ‘um’, etc) have corresponding integer indices. Look these up in the _unit_labels dictionary.
-
set_velocity
(val)¶ Set the motor velocity.
-
stage_length
= 600¶
-
step_size
¶ Get the distance represented by one motor step.
-
t
¶ Convert stage position in mm to delay in ps
-
unit
¶ Get the unit label for a given axis.
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
-
class
wanglib.instruments.stages.
short_stage
(axisnum, bus=None)¶ -
busy
¶
-
c
= 3000.0¶
-
cmd
(string)¶ Prepend the axis number to a command.
-
define_home
()¶ Define the origin of this stage to be its current position.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_pos
()¶ Query the absolute position of the stage
-
get_t
()¶ Convert stage position in mm to delay in ps
-
mm
= 10000.0¶
-
motor_status
(bit=None)¶ Request the MM3000 motor status byte.
- Optionally, pick out a specific bit.
- bit 0: True if axis is moving bit 1: True if motor is off bit 2: True if direction of move is positive bit 3: True if positive travel limit is active bit 4: True if negative travel limit is active bit 5: True if positive side of home bit 6: always True bit 7: always False
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
on
¶
-
pos
¶ Query the absolute position of the stage
-
set_pos
(val)¶ Set the absolute position of the stage
-
set_t
(new_val)¶
-
stage_length
= 1000000.0¶
-
t
¶ Convert stage position in mm to delay in ps
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
-
class
wanglib.instruments.stages.
shorty_stage
(axisnum, bus=None)¶ Newport UTM100pp.1 stage, when plugged into ESP300
-
busy
¶ ask whether motion is in progress
-
cmd
(string)¶ Prepend the axis number to a command.
-
define_home
(loc=None)¶ Define the origin of this stage to be its current position.
To define the current position to be some number other than zero, provide that number in the loc kwarg.
-
encoder_resolution
¶ Get the distance represented by one encoder pulse.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_max_velocity
()¶ Get the maximum motor velocity.
-
get_pos
()¶ Query the absolute position of the stage
-
get_t
()¶ Convert stage position in mm to delay in ps
-
get_velocity
()¶ Get the current motor velocity.
-
initialize
()¶
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
on
¶ Turn motor on/off.
-
pos
¶ Query the absolute position of the stage
-
set_max_velocity
(val)¶ Set the max motor velocity.
-
set_pos
(val)¶ Set the absolute position of the stage
-
set_t
(new_val)¶
-
set_unit
(key)¶ Set the unit label for a given axis, by index.
Unit labels (‘mm’, ‘um’, etc) have corresponding integer indices. Look these up in the _unit_labels dictionary.
-
set_velocity
(val)¶ Set the motor velocity.
-
step_size
¶ Get the distance represented by one motor step.
-
t
¶ Convert stage position in mm to delay in ps
-
unit
¶ Get the unit label for a given axis.
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
-
class
wanglib.instruments.stages.
thorlabs_Z612B
(axisnum, bus=None)¶ Thorlabs Z612B motorized actuator.
-
busy
¶ ask whether motion is in progress
-
cmd
(string)¶ Prepend the axis number to a command.
-
define_home
(loc=None)¶ Define the origin of this stage to be its current position.
To define the current position to be some number other than zero, provide that number in the loc kwarg.
-
encoder_resolution
¶ Get the distance represented by one encoder pulse.
-
find_zero
()¶ Place the zero 1mm from the hardware limit. This follows Yan’s old labview routine.
-
get_max_velocity
()¶ Get the maximum motor velocity.
-
get_pos
()¶ Query the absolute position of the stage
-
get_velocity
()¶ Get the current motor velocity.
-
initialize
()¶
-
move
(delta)¶ Move the stage (relative move)
-
move_to_limit
(direction=-1)¶ Move to the hardware limit of the stage.
By default, finds the negative limit. To find the positive limit, provide a positive number as the argument.
NOTE: sometimes, the ESP300 will time out and give up looking for the hardware limit if it takes too long to get there. So, try to get reasonably close to the limit before using this function.
-
on
¶ Turn motor on/off.
-
pos
¶ Query the absolute position of the stage
-
set_max_velocity
(val)¶ Set the max motor velocity.
-
set_pos
(val)¶ Set the absolute position of the stage
-
set_unit
(key)¶ Set the unit label for a given axis, by index.
Unit labels (‘mm’, ‘um’, etc) have corresponding integer indices. Look these up in the _unit_labels dictionary.
-
set_velocity
(val)¶ Set the motor velocity.
-
step_size
¶ Get the distance represented by one motor step.
-
unit
¶ Get the unit label for a given axis.
-
wait
(lag=0.5)¶ Stop the python program until motors stop moving.
optionally, specify a check interval in seconds (default: 0.5)
-
RF signal generators: wanglib.instruments.signal_generators
¶
Interfaces to Agilent RF signal generators.
-
class
wanglib.instruments.signal_generators.
ag8648
(bus)¶ The Agilent 8648A/B/C/D RF signal generator.
These instruments are configured to work on GPIB address 18 by factory default. To instantiate one plugged in to prologix controller plx, do this:
>>> rf = ag8648(plx.instrument(18))
Other instrument objects (e.g. pyVISA) should also work.
Attributes:
- on – boolean indicating whether RF
- output is on or off.
amp – RF output amplitude, in DBM.
The signal generator can be controlled remotely by setting these attributes of the instance.
>>> rf.amp -5.0 >>> rf.amp = -10 >>> rf.amp -10.0
-
amp
¶ RF amplitude in dBm.
-
blink
(interval=1.0)¶ Blink the RF output on and off with time.
Useful when aligning AOMs.
-
freq
¶ RF frequency in MHz.
-
get_amp
()¶ RF amplitude in dBm.
-
get_freq
()¶ RF frequency in MHz.
-
get_on
()¶ is RF output on?
-
get_pulse
()¶ is pulse modulation enabled?
-
on
¶ is RF output on?
-
pulse
¶ is pulse modulation enabled?
-
set_amp
(val, unit='DBM')¶ Set the output amplitude. Assumes units of DBM.
Available units: DBM, MV, UV, MVEMF, UVEMF, DBUV, DBUVEMF.
-
set_freq
(val, unit='MHZ')¶ Set the RF frequency in MHz.
-
set_on
(val)¶
-
set_pulse
(val)¶
Newport Diode Lasers: wanglib.instruments.lasers
¶
Interfaces to New Focus diode laser controllers.
-
class
wanglib.instruments.lasers.
velocity6300
(bus)¶ A New Focus Velocity 6300 diode laser controller.
To instantiate, pass an instrument object to the constructor. e.g., for a controller with GPIB address 1, attached to a prologix GPIB controller:
>>> laser = velocity6300(plx.instrument(1, auto=False))
where
plx
is the prologix object. If you’re using prologix, it’s very important to turn off read-after-write!To use with RS232, use
\r
as the termination character. For example:>>> from wanglib.util import Serial >>> laser = velocity6300(Serial('/dev/ttyUSB0', baudrate=19200, term_chars='\r'))
-
busy
¶ is an operation in progress?
-
current
¶ return current level in the diode (mA)
-
get_piezo
()¶ Return piezo voltage as % of full-scale.
-
get_wl
()¶ Get current wavelength of laser (nm)
-
on
¶ is the laser on or off?
-
piezo
¶ Return piezo voltage as % of full-scale.
-
power
¶ return front-facet laser power level (mW)
-
set_piezo
(val)¶ Set piezo voltage as % of full-scale.
-
set_wl
(val)¶ Set current wavelength of laser (nm).
Can take a numerical value, or ‘min’ or ‘max’
-
stop_tracking
()¶ exit track mode to ready mode.
-
wl
¶ Get current wavelength of laser (nm)
-
wl_max
¶ max wavelength of this diode
-
wl_min
¶ min wavelength of this diode
-
write
(cmd)¶ Issue a command to the laser.
- This takes care of two things:
- Formats the command with
@
if using RS-232 - Verifies that the laser responds with
OK
- Formats the command with
-
Burleigh Wavemeter: wanglib.instruments.wavemeter
¶
-
class
wanglib.instruments.wavemeter.
Serial
¶
-
class
wanglib.instruments.wavemeter.
burleigh
(port='/dev/ttyUSB0')¶ encapsulates a burleigh wavemeter
-
display
¶
-
display_masks
= {64: 'wavelength', 128: 'deviation'}¶
-
get_display
()¶
-
get_response
()¶
-
get_unit
()¶
-
get_wl
(strict=True)¶ Get the current wavelength (or frequency).
If strict, cast approximate measurements to None.
-
parse
(response)¶ parse the wavemeter’s broadcast string
-
parse_code
(code, dic)¶
-
purge
()¶ purge the buffer of old measurements
-
query
()¶ Request a single response string.
The first time the wavemeter receives this command, it will switch from broadcast to query mode.
-
unit
¶
-
unit_masks
= {9: 'nm', 18: 'cm-1', 36: 'GHz'}¶
-
wl
¶ Get the current wavelength (or frequency).
If strict, cast approximate measurements to None.
-
Tektronix Oscilloscopes: wanglib.instruments.tektronix
¶
Interfaces to Tektronix oscilloscopes.
-
class
wanglib.instruments.tektronix.
TDS3000
(bus=None)¶ A Tektronix oscilloscope from the TDS3000 series.
Can be controlled over GPIB, RS-232, or Ethernet. Just pass an object with
write
,read
, andask
methods to the constructor.>>> from wanglib.util import Serial >>> bus = Serial('/dev/ttyS0', rtscts=True) >>> scope = tds3000(bus)
If using RS-232 (as above), be sure to use rtscts, and connect using a null modem cable. You will probably need to use the highest baud rate you can.
-
acquire
= {}¶
-
acquire_restart
()¶ Discards collected data and restarts acquisition.
-
data_source
¶ Determines the default data curve returned by
get_curve()
.Possible values include CH1, CH2, CH3, CH4, MATH, MATH1 (same as MATH), REF1, REF2, REF3, and REF4.
-
get_curve
(source=None)¶ Fetch a trace.
Parameters: source – Channel to retrieve. Defaults to value of data_source
. Valid channels are CH1, CH2, CH3, CH4, MATH, MATH1 (same as MATH), REF1, REF2, REF3, or REF4.Returns: A numpy array representing the current waveform.
-
get_timediv
()¶ Get time per division, in seconds.
Returns: Seconds per division, as a floating-point number.
-
get_wfm
(source=None)¶ Fetch a trace, scaled to actual units.
Parameters: source – Channel to retrieve. Defaults to value of data_source
. Valid channels are CH1, CH2, CH3, CH4, MATH, MATH1 (same as MATH), REF1, REF2, REF3, or REF4.Returns: Two numpy arrays: t and y
-
is_active
(channel)¶ Ask whether a given waveform is active
Parameters: channel – CH1, CH2, CH3, CH4, MATH, MATH1 (same as MATH), REF1, REF2, REF3, or REF4.
-
save_wfm
(source, dest)¶ Store a waveform locally on the oscilloscope.
Parameters: - source (str) – channel to transfer data from. CH<x>, MATH<x>, or REF<x>.
- dest (str) – Which one of the four REF<x> to save into.
-
set_timediv
(to)¶ Set time per division, in seconds.
Parameters: to (float) – Desired seconds per division. Acceptable values range from 10 seconds to 1, 2, or 4ns, depending on model, in a 1-2-4 sequence.
-
timediv
¶ Get time per division, in seconds.
Returns: Seconds per division, as a floating-point number.
-
Alternative GPIB drivers¶
If PyVISA is not installed, wanglib
provides two alternative GPIB
interfaces that emulate the behavior of visa.instrument
.
Prologix controllers with wanglib.prologix
¶
This module enables you to control various instruments over GPIB using
low-cost Prologix controllers. The interface aims to emulate that
of PyVISA, such that wanglib.prologix.instrument
objects
can be a drop-in replacement for visa.instrument()
.
For example, the canonical PyVISA three-liner
>>> import visa
>>> keithley = visa.instrument("GPIB::12")
>>> print keithley.ask("*IDN?")
is just one line longer with wanglib.prologix
:
>>> from wanglib import prologix
>>> plx = prologix.prologix_USB('/dev/ttyUSBgpib')
>>> keithley = plx.instrument(12)
>>> print keithley.ask("*IDN?")
This extra verbosity is necessary to specify which GPIB controller to
use. Here we are using a Prologix GPIB-USB controller at
/dev/ttyUSBgpib
. If we later switch to using a Prologix
GPIB-Ethernet controller, we would instead use
>>> plx = prologix.prologix_ethernet('128.223.xxx.xxx')
for our plx
controller object (replace the ``xxx``es
with the controller’s actual ip address, found using the
Prologix Netfinder tool).
-
class
wanglib.prologix.
PrologixEthernet
(ip)¶ Interface to a Prologix GPIB-Ethernet controller.
To instantiate, use the
prologix_ethernet
factory:>>> plx = prologix.prologix_ethernet('128.223.xxx.xxx')
Replace the ``xxx``es with the controller’s actual ip address, found using the Prologix Netfinder tool.
-
addr
¶ The Prologix controller can calk to one instrument at a time. This sets the GPIB address of the currently addressed instrument.
Use this attribute to set or check which instrument is currently selected:
>>> plx.addr 9 >>> plx.addr = 12 >>> plx.addr 12
-
ask
(query, *args, **kwargs)¶ Write to the bus, then read response.
-
auto
¶ Boolean. Read-after-write setting.
The Prologix ‘read-after-write’ setting can automatically address instruments to talk after writing to them. This is usually convenient, but some instruments do poorly with it.
-
instrument
(addr, **kwargs)¶ Factory function for
instrument
objects.>>> plx.instrument(12)
is equivalent to
>>> instrument(plx, 12)
- addr – the GPIB address for an instrument
- attached to this controller.
-
readall
()¶
-
savecfg
¶ Boolean. Determines whether the controller should save its settings in EEPROM.
It is usually best to turn this off, since it will reduce wear on the EEPROM in applications that involve talking to more than one instrument.
-
version
()¶ Check the Prologix firmware version.
-
write
(command, lag=0.1)¶
-
-
class
wanglib.prologix.
PrologixUSB
(port='/dev/ttyUSBgpib', log=False)¶ Interface to a Prologix GPIB-USB controller.
To instantiate, specify the virtual serial port where the controller is plugged in:
>>> plx = prologix.prologix_USB('/dev/ttyUSBgpib')
On Windows, you could use something like
>>> plx = prologix.prologix_USB('COM1')
-
addr
¶ The Prologix controller can calk to one instrument at a time. This sets the GPIB address of the currently addressed instrument.
Use this attribute to set or check which instrument is currently selected:
>>> plx.addr 9 >>> plx.addr = 12 >>> plx.addr 12
-
ask
(query, *args, **kwargs)¶ Write to the bus, then read response.
-
auto
¶ Boolean. Read-after-write setting.
The Prologix ‘read-after-write’ setting can automatically address instruments to talk after writing to them. This is usually convenient, but some instruments do poorly with it.
-
instrument
(addr, **kwargs)¶ Factory function for
instrument
objects.>>> plx.instrument(12)
is equivalent to
>>> instrument(plx, 12)
- addr – the GPIB address for an instrument
- attached to this controller.
-
readall
()¶
-
savecfg
¶ Boolean. Determines whether the controller should save its settings in EEPROM.
It is usually best to turn this off, since it will reduce wear on the EEPROM in applications that involve talking to more than one instrument.
-
version
()¶ Check the Prologix firmware version.
-
write
(command, lag=0.1)¶
-
-
class
wanglib.prologix.
instrument
(controller, addr, delay=0.1, auto=True)¶ Represents an instrument attached to a Prologix controller.
Pass the controller instance and GPIB address to the constructor. This creates a GPIB instrument at address 12:
>>> plx = prologix_USB() >>> inst = instrument(plx, 12)
A somewhat nicer way to do the second step would be to use the
instrument()
factory method of the Prologix controller:>>> inst = plx.instrument(12)
Once we have our instrument object
inst
, we can use theask()
andwrite()
methods to send GPIB queries and commands.-
ask
(command)¶ Send a query the instrument, then read its response.
Equivalent to
write()
thenread()
.For example, get the ‘ID’ string from an EG&G model 5110 lock-in:
>>> inst.ask('ID') '5110'
Is the same as:
>>> inst.write('ID?') >>> inst.read() '5110'
-
delay
= 0.1¶
-
read
()¶ Read a response from an instrument.
-
write
(command)¶ Write a command to the instrument.
-
-
wanglib.prologix.
prologix_USB
(port='/dev/ttyUSBgpib', log=False)¶ Factory for a Prologix GPIB-USB controller.
To instantiate, specify the virtual serial port where the controller is plugged in:
>>> plx = prologix.prologix_USB('/dev/ttyUSBgpib')
On Windows, you could use something like
>>> plx = prologix.prologix_USB('COM1')
-
wanglib.prologix.
prologix_ethernet
(ip)¶ Factory function for a Prologix GPIB-Ethernet controller.
To instantiate, specify the IP address of the controller:
>>> plx = prologix.prologix_ethernet('128.223.xxx.xxx')
linux_gpib compatibility layer: wanglib.linux_gpib
¶
Utilities for computers using linux-gpib.
linux-gpib (http://linux-gpib.sourceforge.net/) is an open-source driver for various GPIB cards. It includes two python modules:
- the low-level gpib module
- an object-oriented Gpib module.
The Gpib module defines a Gpib class representing individual instruments. This module modifies that class to make it behave a little more like PyVISA’s instrument class, for better compatibility with the rest of wanglib.
This will only work if your linux-gpib installation has been patched with the following enhancement:
http://sourceforge.net/tracker/?func=detail&aid=3437534&group_id=42378&atid=432942
This should apply to any linux-gpib released since January 2012.
Improved interactive plotting with wanglib.pylab_extensions
¶
This module contains some useful extensions to the pylab interface.
Plotting while acquiring data¶
To plot while acquiring data, you will need to implement your data
gathering using Python generators. A generator is like a Python
function that, rather than returning data all at once (with the
return
statement), returns it point by point (with the yield
statement).
Suppose we have a spex
spectrometer object, and a
lockin
object that we are using to detect the signal at
the output slit of the spectrometer. Here is an example of a
generator we might use to scan a spectrum, while yielding
values along the way:
def scan_wls(wls):
for wl in wls:
spex.set_wl(wl)
sleep(0.1)
val = lockin.get_x()
yield wl, val
Note
This pattern is so common that a shorthand is provided for it in wanglib.util.scanner()
.
Then, if we wanted to scan from 800nm to 810nm, we would do
scan = scan_wls(numpy.arange(800, 810, 0.1))
for x,y in scan:
print x,y
This will print the data to STDOUT, but we could also:
- save it to a python list using list comprehensions
- save it as a numpy object using
numpy.fromiter()
- plot it progressively using
wanglib.pylab_extensions.live_plot.plotgen()
The plotgen
function reads from your generator, plotting data as
it goes along. In the case of our scan_wls
example above, we can
view the spectrum as it gets collected:
wls = arange(800, 810, 0.1))
plotgen(scan_wls(wls))
# ... measures data, plotting as it goes along ...
After your generator yields its last value, it will return the complete array of measured X and Y values. Sometimes we want to do extra things with that:
_,ref = plotgen(scan_wls(wls)) # measure reference spectrum and plot it
_,trn = plotgen(scan_wls(wls)) # measure transmission spectrum and plot it
plot(wls, log(ref/trn), 'k--') # plot absorption spectrum
Additionally, plotgen
can generate multiple lines. Say we wanted
to plot both the X and the Y quadrature from our lockin. We’d write
our generator like:
def scan_wls(wls):
for wl in wls:
spex.set_wl(wl)
sleep(0.1)
x = lockin.get_x()
y = lockin.get_y()
yield wl, x, wl, y
This is the same as before, but we’re yielding two X,Y pairs: one with
the X quadrature (wl, x)
and one with the Y quadrature (wl, y)
.
plotgen
recognizes this and plots two lines:
_,x,_,y = plotgen(scan_wls(wls))
By default, plotgen
plots these on the same axes, but sometimes
that doesn’t make sense. For example, if we’re measuring the signal
magnitude (in Volts) and phase (in degrees), then those two units have
nothing to do with each other, and we should plot them on separate
axes.
def scan_wls(wls):
for wl in wls:
spex.set_wl(wl)
sleep(0.1)
r = lockin.get_r()
p = lockin.get_phase()
yield wl, r, wl, p
# create two axes and pass them to plotgen explicitly
ax1 = pylab.subplot(211)
ax2 = pylab.subplot(212)
plotgen(scan_wls(wls), ax=(ax1,ax2))
Finally, you can limit the length of the plotted lines using the
maxlen
parameter. This is useful for generators which yield
infinitely - such as monitoring the last five minutes of a signal.
def monitor_signal():
start = time()
while True:
yield time() - start, lockin.get_phase()
sleep(0.1)
Note
This pattern is so common that a shorthand is provided for it in wanglib.util.monitor()
.
This will yield about 10 points per second forever. To cut it short after about 5 minutes of data, try this:
plotgen(monitor_signal(), maxlen=10*60*5)
Full documentation for plotgen
:
-
wanglib.pylab_extensions.live_plot.
plotgen
(gen, ax=None, maxlen=None, **kwargs)¶ Take X,Y data from a generator, and plot it at the same time.
Parameters: - gen – a generator object yielding X,Y pairs.
- ax – an axes object (optional).
- maxlen – maximum number of points to retain (optional).
Returns: an array of the measured X and Y values.
Any extra keyword arguments are passed to the plot function.
gen
can yield any even number of values, and these are interpreted as a set of X,Y pairs. That is, if the provided generator yields 4 values each time, plotgen will plot two lines - with the first line updated from the [0:2] slice and the second line updated from the [2:4] slice.ax
is the axes object into which the line(s) are plotted. By default, the current axes.ax
can also be a tuple of axes objects, as long as the tuple is the same length as the number of lines being plotted. Each line is then plotted into the corresponding axes.maxlen
, when provided, limits the buffer size. When the plotted lines each grow to this number of points, the oldest data points will start being trimmed off the line’s trailing end.
Saving/clearing traces¶
-
wanglib.pylab_extensions.misc.
apply_mask
(line, mask)¶ mask x and y (to remove bad points, etc).
-
wanglib.pylab_extensions.misc.
apply_offset
(line, offset)¶ move the line up or down
-
wanglib.pylab_extensions.misc.
apply_reference
(line, ref)¶ apply reference data (for absorption spectra)
-
wanglib.pylab_extensions.misc.
bll
(index=-1, lag=0.3)¶ blink the last line, identifying it
-
wanglib.pylab_extensions.misc.
cll
(index=-1)¶ clear last line. removes the last line from the figure.
To remove a different line, specify the index.
-
wanglib.pylab_extensions.misc.
dualtick
(func)¶ Decorator for dual-tick functions.
A dual-tick function is a function that, when called on an axis, adds a second set of tick to it in different units. This decorator creates such functions when applied to the unit conversion function.
For example:
>>> @dualtick >>> def eV(wl): >>> return 1240. / wl
Now, when working with plots of spectral data in units of nm, calling
>>> eV()
will add a second axis along the top in units of eV. To explicitly apply to some other axis
ax
, useeV(ax)
. Returns a reference to the twiny axis that was made.Another example, for a delay stage:
>>> @dualtick >>> def ns(pos): >>> c = 300. # mm / ns >>> zd = 521. # mm >>> return 2 * (zd - pos) / c
When plotting delay stage data enumerated in mm, this function will add an axis in ps delay from the zero-delay point at 521mm.
-
wanglib.pylab_extensions.misc.
gll
(index=-1, blink=True)¶ Get last line.
Retrieves x,y data of the last line and returns them as a tuple of two numpy arrays.
To get a different line, specify the index.
-
wanglib.pylab_extensions.misc.
relim
(line)¶ redraw the line’s figure to include the line.
-
wanglib.pylab_extensions.misc.
sll
(fname, index=-1, blink=True)¶ Save last line.
Saves x,y data of the last line, in .npy format. Specify the file name.
To save a different line, specify the index.
Density plots¶
-
wanglib.pylab_extensions.density.
density_plot
(two_dimensional, horiz, vert, ax=None, **kwargs)¶ Display a 2D density plot - like imshow, but with axes labels corresponding to the two axes provided.
This will only be accurate for regularly-spaced x and y axes (e.g., as generated by arange or linspace).
Parameters: - two_dimensional – data to plot. shape: (M, N)
- horiz – x-axis. should have length N.
- vert – y-axis. should have length M.
- ax – axis upon which to plot.
Keyword arguments are passed to imshow.
Miscellaneous utilities — wanglib.util
¶
This file provides useful utilities for the wanglib package.
-
exception
wanglib.util.
InstrumentError
¶ Raise this when talking to instruments fails.
-
class
wanglib.util.
Serial
(*args, **kwargs)¶ Extension of PySerial‘s
serial.Serial
class that implements a few extra features:To log whatever’s written or read to a serial port, pass a filename into the
log
kwarg:>>> port = Serial('/dev/ttyS0', log='wtf.log')
To automatically append a newline to each command, specify
term_chars
:>>> port.term_chars = '/n'
This can also be supplied as a keyword argument.
-
ask
(query, lag=0.05)¶ Write to the bus, then read response.
This doesn’t seem to work very well.
-
read
(size=1)¶
-
readall
(term_chars=None)¶ Automatically read all the bytes from the serial port.
if
term_chars
is set, this will continue to read until the terminating bytes are received. This can be provided as a keyword argument.
-
start_logging
(fname)¶ start logging read/write data to file.
-
write
(data)¶
-
-
wanglib.util.
averager
(func, n, lag=0.1)¶ Given a function
func
, returns an implementation of that function that just repeats itn
times, and returns an average of the result.Parameters: - func (function) – function returning a measurement
- n (int) – number of times to call
func
. - lag (float) – seconds to sleep between measurements.
Returns: the average of the
n
measurements.This is useful when scanning. For example, if scanning a spectrum with the lockin like so:
>>> gen = scanner(wls, set=tr.set_wl, get=li.get_x)
We can implement a version that averages three lockin measurements with a 0.3s delay like so:
>>> acq = averager(li.get_x, 3, lag=0.3) >>> gen = scanner(wls, set=tr.set_wl, get=acq)
-
wanglib.util.
gaussian
(p, x)¶ gaussian function.
p is a 4-component parameter vector defining:
0 -- a baseline offset 1 -- the area between curve and baseline 2 -- the location of the maximum 3 -- the standard deviation
-
wanglib.util.
monitor
(function, lag=0.3, absolute=False)¶ Periodically yield output of a function, along with timestamp. Compatible with
wanglib.pylab_extensions.live_plot.plotgen()
.Parameters: - function (function) – function to call
- lag (float) – interval between calls to
function
(default 0.3 seconds) - absolute (boolean) – if True, yielded x values are seconds since epoch. otherwise, time since first yield.
Returns: a generator object yielding t,y pairs.
-
wanglib.util.
notraceback
(*args, **kwds)¶ Context manager to swallow keyboard interrupt.
Execute any infinitely-looping process in this context, like:
>>> from time import sleep >>> with notraceback(): ... while True: ... sleep(0.1)
If you are planning to interrupt it anyway then you are not interested in the traceback and this prevents your output from being cluttered.
-
wanglib.util.
num
(string)¶ convert string to number. decide whether to convert to int or float.
-
wanglib.util.
save
(fname, array)¶ Save a Numpy array to file.
Parameters: - fname – Filename, as a string
- array – Numpy array to save.
Unlike
numpy.save()
, this function will raise ValueError if overwriting an existing file.
-
class
wanglib.util.
saver
(name, verbose=False)¶ Sequential file saver.
after initializing
saver
with the base filename, use thesave()
method to save arrays to sequentially-numbered files.>>> s = saver('foo') >>> s.save(arange(5)) # saves to 'foo000.npy' >>> s.save(arange(2)) # saves to 'foo001.npy'
-
save
(array)¶ Save an array to the next file in the sequence.
-
-
wanglib.util.
scanner
(xvals, set, get, lag=0.3)¶ Generic scan generator - useful for spectra, delay scans, whatever. Compatible with
wanglib.pylab_extensions.live_plot.plotgen()
.Parameters: - xvals (iterable) – values of x over which to scan.
- set (function) – Function to call on each step that advances the independent
variable to the next value of
xvals
. This function should take that value as an argument. - get (function) – Function to call on each step that performs the measurement. The return value of this function should be the measurement result.
- lag (float) – seconds to sleep between setting and measuring
Returns: a generator object yielding x,y pairs.
Example: while scanning triax wavelength, measure lockin x
>>> from triax.instruments.lockins import egg5110 >>> from triax.instruments.spex750m import triax320 >>> from wanglib.pylab_extensions import plotgen >>> tr = triax320() >>> li = egg5110(instrument(plx,12)) >>> wls = arange(770, 774, .1) >>> gen = scanner(wls, set=tr.set_wl, get=li.get_x) >>> result = plotgen(gen)
Sometimes we will want to set/measure an attribute of an object on each step, instead of calling a method. In this case, we can provide an (object, attribute_name) tuple in lieu of a function for
set
orget
. For example, in place of thegen
used above, we could do:>>> gen = scanner(wls, set=(tr,'wl'), get=(li,'x'))
Avoid this if you can, though.
-
wanglib.util.
sciround
(number, sigfigs=1)¶ Round a number to a desired significant figure precision.
>>> sciround(.000671438, 3) .000671
-
wanglib.util.
show_newlines
(string)¶ replace CR+LF with the words “CR” and “LF”. useful for debugging.
Jobin-Yvon CCD client — wanglib.ccd
¶
Client routines for use with the CCD-2000 camera (generally attached to the Spex 750M spectrometer). These utilities talk to the CCD server LabView program running on the old computer over TCP/IP.
To configure the CCD server, refer to README file on the desktop of the CCD controller computer.
Command-line invocation¶
For a simple live display from the CCD, invoke this module as a script:
$ python -m wanglib.ccd --ip 128.223.xxx.xxx 800
where 800 is the center wavelength of the grating
(as read from the window). You will need to specify
the real IP address of the CCD server using the --ip
flag.
A more sophisticated GUI for the CCD is available. This program can save data, zoom in and out, and move the grating on the Spex 750M.
Client library¶
To integrate the CCD client into your own script,
use labview_client
.
-
class
wanglib.ccd.
labview_client
(center_wl, host=None, port=3663)¶ TCP client for Tim’s labview ccd server.
Instantiate like so:
>>> ccd = labview_client(700, '128.223.xxx.xxx')
where
121.223.xxx.xxx
is the IP address of the computer running the Labview server, and 700 is the current wavelength of the spectrometer in nanometers (read from the window).This info is needed because the labview program calculates wavelength values (from dispersion calibration info) on the server-side. Tye Hetherington wrote that sub-routine.
This client implements no control whatsoever of the SPEX 750m spectrometer to which the CCD is attached. For proper wavelength and dispersion info, you’ll need to keep the client informed.
Whenever you move the spectrometer, set
center_wl
attribute to match:>>> ccd.center_wl = 750
To get a spectrum, use
get_spectrum()
.-
connect
()¶ Establish a connection with the labview server.
If the labview program is ever stopped and restarted (as it should be when not taking data, to avoid wearing out the shutter), this should be called to reestablish the connection.
-
get_spectrum
()¶ Takes a shot on the CCD.
Returns a 2-tuple
(wl, ccd)
.wl
: a 1-D array of the horizontal (wavelength) axis.ccd
: a 2-D array of CCD counts.To collapse
ccd
into a 1D array matchingwl
, sum over axis 0:>>> wl,ccd = clnt.get_spectrum() >>> line, = pylab.plot(wl,ccd.sum(axis=0))
-
To Do¶
I still haven’t documented the following:
wanglib.grating
- a bunch of old stuff for making SLM gratings/pulse shapers