Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
instruments/abstract_instruments/optical_spectrum_analyzer.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Provides an abstract base class for optical spectrum analyzer instruments | ||
""" | ||
|
||
# IMPORTS ##################################################################### | ||
|
||
from __future__ import absolute_import | ||
from __future__ import division | ||
|
||
import abc | ||
|
||
from future.utils import with_metaclass | ||
|
||
from instruments.abstract_instruments import Instrument | ||
|
||
# CLASSES ##################################################################### | ||
|
||
|
||
class OSAChannel(with_metaclass(abc.ABCMeta, object)): | ||
|
||
""" | ||
Abstract base class for physical channels on an optical spectrum analyzer. | ||
All applicable concrete instruments should inherit from this ABC to | ||
provide a consistent interface to the user. | ||
""" | ||
|
||
# METHODS # | ||
|
||
@abc.abstractmethod | ||
def wavelength(self, bin_format=True): | ||
""" | ||
Gets the x-axis of the specified data source channel. This is an | ||
abstract property. | ||
:param bool bin_format: If the waveform should be transfered in binary | ||
(``True``) or ASCII (``False``) formats. | ||
:return: The wavelength component of the waveform. | ||
:rtype: `numpy.ndarray` | ||
""" | ||
raise NotImplementedError | ||
|
||
@abc.abstractmethod | ||
def data(self, bin_format=True): | ||
""" | ||
Gets the y-axis of the specified data source channel. This is an | ||
abstract property. | ||
:param bool bin_format: If the waveform should be transfered in binary | ||
(``True``) or ASCII (``False``) formats. | ||
:return: The y-component of the waveform. | ||
:rtype: `numpy.ndarray` | ||
""" | ||
raise NotImplementedError | ||
|
||
|
||
class OpticalSpectrumAnalyzer(with_metaclass(abc.ABCMeta, Instrument)): | ||
|
||
""" | ||
Abstract base class for optical spectrum analyzer instruments. | ||
All applicable concrete instruments should inherit from this ABC to | ||
provide a consistent interface to the user. | ||
""" | ||
|
||
# PROPERTIES # | ||
|
||
@abc.abstractproperty | ||
def channel(self): | ||
""" | ||
Gets an iterator or list for easy Pythonic access to the various | ||
channel objects on the OSA instrument. Typically generated | ||
by the `~instruments.util_fns.ProxyList` helper. | ||
""" | ||
raise NotImplementedError | ||
|
||
|
||
@property | ||
@abc.abstractmethod | ||
def start_wl(self): | ||
""" | ||
Gets/sets the the start wavelength of the OSA. This is | ||
an abstract property. | ||
:type: `~quantities.Quantity` | ||
""" | ||
raise NotImplementedError | ||
|
||
@start_wl.setter | ||
@abc.abstractmethod | ||
def start_wl(self, newval): | ||
raise NotImplementedError | ||
|
||
@property | ||
@abc.abstractmethod | ||
def stop_wl(self): | ||
""" | ||
Gets/sets the the stop wavelength of the OSA. This is | ||
an abstract property. | ||
:type: `~quantities.Quantity` | ||
""" | ||
raise NotImplementedError | ||
|
||
@stop_wl.setter | ||
@abc.abstractmethod | ||
def stop_wl(self, newval): | ||
raise NotImplementedError | ||
|
||
@property | ||
@abc.abstractmethod | ||
def bandwidth(self): | ||
""" | ||
Gets/sets the the bandwidth of the OSA. This is | ||
an abstract property. | ||
:type: `~quantities.Quantity` | ||
""" | ||
raise NotImplementedError | ||
|
||
@bandwidth.setter | ||
@abc.abstractmethod | ||
def bandwidth(self, newval): | ||
raise NotImplementedError | ||
|
||
|
||
# METHODS # | ||
|
||
@abc.abstractmethod | ||
def start_sweep(self): | ||
""" | ||
Forces a start sweep on the attached OSA. | ||
""" | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Provides support for the Yokogawa 6370 optical spectrum analyzer. | ||
""" | ||
|
||
# IMPORTS ##################################################################### | ||
|
||
from __future__ import absolute_import | ||
from __future__ import division | ||
|
||
from builtins import range | ||
from enum import IntEnum, Enum | ||
|
||
import quantities as pq | ||
|
||
from instruments.abstract_instruments import ( | ||
OpticalSpectrumAnalyzer, | ||
OSAChannel, | ||
) | ||
from instruments.util_fns import ( | ||
enum_property, unitful_property, unitless_property, | ||
bounded_unitful_property, ProxyList | ||
) | ||
|
||
|
||
# CLASSES ##################################################################### | ||
|
||
class Yokogawa6370(OpticalSpectrumAnalyzer): | ||
|
||
""" | ||
The Yokogawa 6370 is a optical spectrum analyzer. | ||
Example usage: | ||
>>> import instruments as ik | ||
>>> import quantities as pq | ||
>>> inst = ik.yokogawa.Yokogawa6370.open_visa('TCPIP0:192.168.0.35') | ||
>>> inst.start_wl = 1030e-9 * pq.m | ||
""" | ||
|
||
def __init__(self, *args, **kwargs): | ||
super(Yokogawa6370, self).__init__(*args, **kwargs) | ||
# Set data Format to binary | ||
self.sendcmd(":FORMat:DATA REAL,64") # TODO: Find out where we want this | ||
|
||
# INNER CLASSES # | ||
|
||
class Channel(OSAChannel): | ||
|
||
""" | ||
Class representing the channels on the Yokogawa 6370. | ||
This class inherits from `OSAChannel`. | ||
.. warning:: This class should NOT be manually created by the user. It | ||
is designed to be initialized by the `Yokogawa6370` class. | ||
""" | ||
_trace_names = ["TRA", "TRB", "TRC", "TRD", "TRE", "TRF", "TRG"] | ||
|
||
def __init__(self, parent, idx): | ||
self._parent = parent | ||
self._name = self._trace_names[idx] | ||
|
||
# METHODS # | ||
|
||
def data(self, bin_format=True): | ||
cmd = ":TRAC:Y? {0}".format(self._name) | ||
self._parent.sendcmd(cmd) | ||
data = self._parent.binblockread(data_width=4, fmt="<d") | ||
self._parent._file.read_raw(1) # pylint: disable=protected-access | ||
return data | ||
|
||
def wavelength(self, bin_format=True): | ||
cmd = ":TRAC:X? {0}".format(self._name) | ||
self._parent.sendcmd(cmd) | ||
data = self._parent.binblockread(data_width=4, fmt="<d") | ||
self._parent._file.read_raw(1) # pylint: disable=protected-access | ||
return data | ||
|
||
# ENUMS # | ||
|
||
class SweepModes(IntEnum): | ||
""" | ||
Enum containing valid output modes for the Yokogawa 6370 | ||
""" | ||
SINGLE = 1 | ||
REPEAT = 2 | ||
AUTO = 3 | ||
|
||
class Traces(Enum): | ||
""" | ||
Enum containing valid Traces for the Yokogawa 6370 | ||
""" | ||
A = "TRA" | ||
B = "TRB" | ||
C = "TRC" | ||
D = "TRD" | ||
E = "TRE" | ||
F = "TRF" | ||
G = "TRG" | ||
|
||
# PROPERTIES # | ||
|
||
@property | ||
def channel(self): | ||
""" | ||
Gets the specific channel object. | ||
This channel is accessed as a list in the following manner:: | ||
>>> import instruments as ik | ||
>>> osa = ik.yokogawa.Yokogawa6370.open_gpibusb('/dev/ttyUSB0') | ||
>>> dat = osa.channel[0].data # Gets the data of channel 0 | ||
:rtype: `list`[`~Yokogawa6370.Channel`] | ||
""" | ||
return ProxyList(self, Yokogawa6370.Channel, range(6)) | ||
|
||
start_wl, start_wl_min, start_wl_max = bounded_unitful_property( | ||
":SENS:WAV:STAR", | ||
pq.meter, | ||
doc=""" | ||
The start wavelength in m. | ||
""", | ||
valid_range=(600e-9, 1700e-9) | ||
) | ||
|
||
stop_wl, stop_wl_min, stop_wl_max = bounded_unitful_property( | ||
":SENS:WAV:STOP", | ||
pq.meter, | ||
doc=""" | ||
The stop wavelength in m. | ||
""", | ||
valid_range=(600e-9, 1700e-9) | ||
) | ||
|
||
bandwidth = unitful_property( | ||
":SENS:BAND:RES", | ||
pq.meter, | ||
doc=""" | ||
The bandwidth in m. | ||
""" | ||
) | ||
|
||
span = unitful_property( | ||
":SENS:WAV:SPAN", | ||
pq.meter, | ||
doc=""" | ||
A floating point property that controls the wavelength span in m. | ||
""" | ||
) | ||
|
||
center_wl = unitful_property( | ||
":SENS:WAV:CENT", | ||
pq.meter, | ||
doc=""" | ||
A floating point property that controls the center wavelength m. | ||
""" | ||
) | ||
|
||
points = unitless_property( | ||
":SENS:SWE:POIN", | ||
doc=""" | ||
An integer property that controls the number of points in a trace. | ||
""" | ||
) | ||
|
||
sweep_mode = enum_property( | ||
":INIT:SMOD", | ||
SweepModes, | ||
input_decoration=int, | ||
doc=""" | ||
A property to control the Sweep Mode as oe of Yokogawa6370.SweepMode. | ||
Effective only after a self.start_sweep().""" | ||
) | ||
|
||
active_trace = enum_property( | ||
":TRAC:ACTIVE", | ||
Traces, | ||
doc=""" | ||
The active trace of the OSA of enum Yokogawa6370.Traces. Determines the | ||
result of Yokogawa6370.data() and Yokogawa6370.wavelength().""" | ||
) | ||
|
||
# METHODS # | ||
|
||
def data(self): | ||
""" | ||
Function to query the active Trace data of the OSA. | ||
""" | ||
cmd = ":TRAC:Y? {0}".format(self.active_trace.value) | ||
self.sendcmd(cmd) | ||
data = self.binblockread(data_width=4, fmt="<d") | ||
self._file.read_raw(1) | ||
return data | ||
|
||
def wavelength(self): | ||
""" | ||
Query the wavelength axis of the active trace. | ||
""" | ||
cmd = ":TRAC:X? {0}".format(self.active_trace.value) | ||
self.sendcmd(cmd) | ||
data = self.binblockread(data_width=4, fmt="<d") | ||
self._file.read_raw(1) | ||
return data | ||
|
||
def start_sweep(self): | ||
""" | ||
Triggering function for the Yokogawa 6370. | ||
After changing the sweep mode, the device needs to be triggered before it will update. | ||
""" | ||
self.sendcmd('*CLS;:init') |