Skip to content

Commit

Permalink
Merge 2e30706 into b59a45a
Browse files Browse the repository at this point in the history
  • Loading branch information
scasagrande committed Feb 15, 2019
2 parents b59a45a + 2e30706 commit 8822d88
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 0 deletions.
7 changes: 7 additions & 0 deletions doc/source/apiref/yokogawa.rst
Expand Up @@ -7,6 +7,13 @@
Yokogawa
========

:class:`Yokogawa6370` Optical Spectrum Analyzer
===============================================

.. autoclass:: Yokogawa6370
:members:
:undoc-members:

:class:`Yokogawa7651` Power Supply
==================================

Expand Down
5 changes: 5 additions & 0 deletions instruments/abstract_instruments/__init__.py
Expand Up @@ -19,3 +19,8 @@
PowerSupplyChannel,
PowerSupply,
)

from .optical_spectrum_analyzer import (
OSAChannel,
OpticalSpectrumAnalyzer,
)
136 changes: 136 additions & 0 deletions instruments/abstract_instruments/optical_spectrum_analyzer.py
@@ -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
1 change: 1 addition & 0 deletions instruments/yokogawa/__init__.py
Expand Up @@ -7,3 +7,4 @@
from __future__ import absolute_import

from .yokogawa7651 import Yokogawa7651
from .yokogawa6370 import Yokogawa6370
213 changes: 213 additions & 0 deletions instruments/yokogawa/yokogawa6370.py
@@ -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')

0 comments on commit 8822d88

Please sign in to comment.