# -*- coding: utf-8 -*-
"""Panels for use in various custom experiments.
See Also
--------
src.gui.panels.scanpanel
"""
from functools import partial
import wx
from src.core import instrument
from src.gui import gui_helpers as gh
V_MODES = ['Set', 'Read', 'Neither']
# pylint: disable=R0904
[docs]class VisaPanel(wx.Panel):
"""A panel to gather a VISA address for an instrument."""
def __init__(self, parent, label):
super(VisaPanel, self).__init__(parent, -1)
self.staticpanel = wx.StaticBox(self, -1, label)
staticsizer = wx.StaticBoxSizer(self.staticpanel, wx.VERTICAL)
self.visapanel = BaseVisaPanel(self)
staticsizer.Add(self.visapanel, 0, wx.EXPAND|wx.ALL, 5)
self.SetSizerAndFit(staticsizer)
@property
def label(self):
"""Get the panel's label."""
return self.staticpanel.GetLabel()
@label.setter
[docs] def label(self, newLabel):
"""Set the panel's label."""
self.staticpanel.SetLabel(newLabel)
@property
[docs] def address(self):
"""Get the VISA resource address."""
return self.visapanel.value
[docs]class LockinPanel(wx.Panel):
"""A panel for configuring an SRS 830 lock-in amplifier."""
def __init__(self, parent, label):
super(LockinPanel, self).__init__(parent, -1)
self.staticpanel = wx.StaticBox(self, -1, label)
staticsizer = wx.StaticBoxSizer(self.staticpanel, wx.VERTICAL)
self.visapanel = BaseVisaPanel(self)
otherpanel = wx.Panel(self, -1)
othersizer = wx.FlexGridSizer(7, 2, 2, 2)
otherpanel.SetSizer(othersizer)
controlStyle = wx.TE_RIGHT
myCtrl = partial(gh.createLabeledTextControl, otherpanel, othersizer,
wx.ID_ANY, style=controlStyle,
defocusHandler=self._onDefocusText)
self.voltageBox = myCtrl('Ref. Voltage (V):', '1.000')
self.voltageBox.Enable(False)
self.voltageMode = gh.createLabeledComboBox(otherpanel, othersizer,
label='Voltage Action:',
choices=V_MODES,
initialValue='Read',
style=wx.CB_READONLY)
self.voltageMode.SetMinSize((125, -1))
self.voltageMode.Bind(wx.EVT_COMBOBOX, self._onChangeVoltageMode)
self.ballastBox = myCtrl('Ballast (Ω):', '1.000e+06')
self.offsetBox = myCtrl('Offset (V):', '0.000000e+00')
self.averageBox = myCtrl('Averages:', '20')
self.pretimeBox = myCtrl('Pre-time (s):', '1.000')
self.intertimeBox = myCtrl('Inter-time (s):', '0.050')
othersizer.AddGrowableCol(1, 1)
staticsizer.Add(self.visapanel, 0, wx.EXPAND|wx.ALL, 5)
staticsizer.Add(otherpanel, 0, wx.EXPAND|wx.ALL, 5)
self.SetSizerAndFit(staticsizer)
def _onChangeVoltageMode(self, event):
"""Update the enabled state of the reference voltage based on mode."""
newMode = self.voltageMode.GetValue()
if newMode == 'Read':
self.voltageBox.Enable(False)
else:
self.voltageBox.Enable(True)
def _onDefocusText(self, event):
"""Format a value when its control loses focus."""
source = event.GetEventObject()
value = source.GetValue()
try:
fval = float(value)
except ValueError:
fval = 0.0
if source is self.voltageBox:
source.SetValue('%.3f' % fval)
elif source is self.ballastBox:
source.SetValue('%.3e' % fval)
elif source is self.offsetBox:
source.SetValue('%.6e' % fval)
elif source is self.averageBox:
source.SetValue('%d' % fval)
elif source is self.pretimeBox:
source.SetValue('%.3f' % fval)
elif source is self.intertimeBox:
source.SetValue('%.3f' % fval)
@property
def label(self):
"""Get the panel's label."""
return self.staticpanel.GetLabel()
@label.setter
[docs] def label(self, newLabel):
"""Set the panel's label."""
self.staticpanel.SetLabel(newLabel)
@property
[docs] def address(self):
"""Get the VISA resource address."""
return self.visapanel.value
@property
def outputVoltage(self):
"""Get the output voltage."""
return float(self.voltageBox.GetValue())
@outputVoltage.setter
[docs] def outputVoltage(self, newVoltage):
"""Set the output voltage."""
self.voltageBox.SetValue('%.3f' % newVoltage)
@property
[docs] def outputAction(self):
"""Get the output voltage action."""
return self.voltageMode.GetValue()
@property
[docs] def ballastResistance(self):
"""Get the ballast resistance in ohms."""
return float(self.ballastBox.GetValue())
@property
[docs] def offsetVoltage(self):
"""Get the offset voltage in volts."""
return float(self.offsetBox.GetValue())
@property
[docs] def averages(self):
"""Get the number of averages."""
return int(self.averageBox.GetValue())
@property
[docs] def intertime(self):
"""Get the time between averages."""
return float(self.intertimeBox.GetValue())
@property
[docs] def pretime(self):
"""Get the time before averaging begins in seconds."""
return float(self.pretimeBox.GetValue())
[docs]class BaseVisaPanel(wx.Panel):
"""A simple VISA panel (without a border)."""
def __init__(self, parent, wxId=wx.ID_ANY, controlWxId=wx.ID_ANY):
"""Constructor."""
super(BaseVisaPanel, self).__init__(parent, wxId)
visaLabel = wx.StaticText(self, wx.ID_ANY, label='Visa Address:')
self.visaControl = wx.ComboBox(self, controlWxId, style=wx.CB_DROPDOWN)
self.updateValues()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(visaLabel, 0, wx.BOTTOM, 2)
sizer.Add(self.visaControl, 1, wx.EXPAND|wx.LEFT, 10)
self.SetSizer(sizer)
self.Layout()
@property
[docs] def value(self):
"""Return the selected value of the VISA control.
Returns
-------
str
The selected VISA resource address.
"""
return self.visaControl.GetValue()
[docs] def updateValues(self):
"""Update the available resource addresses."""
currentValue = self.visaControl.GetValue()
values = instrument.getVisaAddresses()
self.visaControl.SetItems(values)
if len(values) > 0:
if currentValue in values:
self.visaControl.SetStringSelection(currentValue)
else:
self.visaControl.SetSelection(0)
[docs]class DcVoltmeterPanel(wx.Panel):
"""A panel for configuring DC Voltmeter."""
def __init__(self, parent, label):
super(DcVoltmeterPanel, self).__init__(parent, -1)
self.staticpanel = wx.StaticBox(self, -1, label)
staticsizer = wx.StaticBoxSizer(self.staticpanel, wx.VERTICAL)
self.visapanel = BaseVisaPanel(self)
otherpanel = wx.Panel(self, -1)
othersizer = wx.FlexGridSizer(3, 2, 2, 2)
otherpanel.SetSizer(othersizer)
controlStyle = wx.TE_RIGHT
myCtrl = partial(gh.createLabeledTextControl, otherpanel, othersizer,
wx.ID_ANY, style=controlStyle,
defocusHandler=self._onDefocusText)
self.averageBox = myCtrl('Averages:', '3')
self.pretimeBox = myCtrl('Pre-time (s):', '1.000')
self.intertimeBox = myCtrl('Inter-time (s):', '0.100')
othersizer.AddGrowableCol(1, 1)
staticsizer.Add(self.visapanel, 0, wx.EXPAND|wx.ALL, 5)
staticsizer.Add(otherpanel, 0, wx.EXPAND|wx.ALL, 5)
self.SetSizerAndFit(staticsizer)
def _onDefocusText(self, event):
"""Format a value when its control loses focus."""
source = event.GetEventObject()
value = source.GetValue()
try:
fval = float(value)
except ValueError:
fval = 0.0
if source is self.averageBox:
source.SetValue('%d' % fval)
elif source is self.pretimeBox:
source.SetValue('%.3f' % fval)
elif source is self.intertimeBox:
source.SetValue('%.3f' % fval)
@property
def label(self):
"""Get the panel's label."""
return self.staticpanel.GetLabel()
@label.setter
[docs] def label(self, newLabel):
"""Set the panel's label."""
self.staticpanel.SetLabel(newLabel)
@property
[docs] def address(self):
"""Get the VISA resource address."""
return self.visapanel.value
@property
[docs] def averages(self):
"""Get the number of averages."""
return int(self.averageBox.GetValue())
@property
[docs] def intertime(self):
"""Get the time between averages."""
return float(self.intertimeBox.GetValue())
@property
[docs] def pretime(self):
"""Get the time before averaging begins in seconds."""
return float(self.pretimeBox.GetValue())
[docs]class LockinPanelMaster(wx.Panel):
"""A panel for configuring an SRS 830 lock-in as a current source.
This class differs from the plain `LockinPanel` in that averaging
information is left out, since if the `LockinPanelMaster` is used, there
is probably another lock-in involved, in which case both would typically
use the same averaging parameters, so it does not make sense to have the
user enter it all twice.
"""
def __init__(self, parent, label):
super(LockinPanelMaster, self).__init__(parent, -1)
self.staticpanel = wx.StaticBox(self, -1, label)
staticsizer = wx.StaticBoxSizer(self.staticpanel, wx.VERTICAL)
self.visapanel = BaseVisaPanel(self)
otherpanel = wx.Panel(self, -1)
othersizer = wx.FlexGridSizer(4, 2, 2, 2)
otherpanel.SetSizer(othersizer)
controlStyle = wx.TE_RIGHT
myCtrl = partial(gh.createLabeledTextControl, otherpanel, othersizer,
wx.ID_ANY, style=controlStyle,
defocusHandler=self._onDefocusText)
self.voltageBox = myCtrl('Ref. Voltage (V):', '1.000')
self.voltageBox.Enable(False)
self.voltageMode = gh.createLabeledComboBox(otherpanel, othersizer,
label='Voltage Action:',
choices=V_MODES,
initialValue='Read',
style=wx.CB_READONLY)
self.voltageMode.SetMinSize((125, -1))
self.voltageMode.Bind(wx.EVT_COMBOBOX, self._onChangeVoltageMode)
self.ballastBox = myCtrl('Ballast (Ω):', '1.000e+06')
self.offsetBox = myCtrl('Offset (V):', '0.000000e+00')
othersizer.AddGrowableCol(1, 1)
staticsizer.Add(self.visapanel, 0, wx.EXPAND|wx.ALL, 5)
staticsizer.Add(otherpanel, 0, wx.EXPAND|wx.ALL, 5)
self.SetSizerAndFit(staticsizer)
def _onChangeVoltageMode(self, event):
"""Update the enabled state of the reference voltage based on mode."""
newMode = self.voltageMode.GetValue()
if newMode == 'Read':
self.voltageBox.Enable(False)
else:
self.voltageBox.Enable(True)
def _onDefocusText(self, event):
"""Format a value when its control loses focus."""
source = event.GetEventObject()
value = source.GetValue()
try:
fval = float(value)
except ValueError:
fval = 0.0
if source is self.voltageBox:
source.SetValue('%.3f' % fval)
elif source is self.ballastBox:
source.SetValue('%.3e' % fval)
elif source is self.offsetBox:
source.SetValue('%.6e' % fval)
@property
def label(self):
"""Get the panel's label."""
return self.staticpanel.GetLabel()
@label.setter
[docs] def label(self, newLabel):
"""Set the panel's label."""
self.staticpanel.SetLabel(newLabel)
@property
[docs] def address(self):
"""Get the VISA resource address."""
return self.visapanel.value
@property
def outputVoltage(self):
"""Get the output voltage."""
return float(self.voltageBox.GetValue())
@outputVoltage.setter
[docs] def outputVoltage(self, newVoltage):
"""Set the output voltage."""
self.voltageBox.SetValue('%.3f' % newVoltage)
@property
[docs] def outputAction(self):
"""Get the output voltage action."""
return self.voltageMode.GetValue()
@property
[docs] def ballastResistance(self):
"""Get the ballast resistance in ohms."""
return float(self.ballastBox.GetValue())
@property
[docs] def offsetVoltage(self):
"""Get the offset voltage in volts."""
return float(self.offsetBox.GetValue())
[docs]class LockinPanelSlave(wx.Panel):
"""A panel for configuring an SRS 830 lock-in amplifier as a slave.
The `LockinPanelSlave` panel differs from the full `LockinPanel` in the
following ways.
1. Since the voltage and current are sourced by a "master" lock-in, the
reference voltage, the voltage mode, and the ballast resistance are
unnecessary.
2. Since there is another lock-in, which will typically use the same
averaging parameters, including averaging here is unnecessary.
This leaves only the resource address and the offset voltage.
"""
def __init__(self, parent, label):
super(LockinPanelSlave, self).__init__(parent, -1)
self.staticpanel = wx.StaticBox(self, -1, label)
staticsizer = wx.StaticBoxSizer(self.staticpanel, wx.VERTICAL)
self.visapanel = BaseVisaPanel(self)
otherpanel = wx.Panel(self, -1)
othersizer = wx.FlexGridSizer(1, 2, 2, 2)
otherpanel.SetSizer(othersizer)
controlStyle = wx.TE_RIGHT
myCtrl = partial(gh.createLabeledTextControl, otherpanel, othersizer,
wx.ID_ANY, style=controlStyle,
defocusHandler=self._onDefocusText)
self.offsetBox = myCtrl('Offset (V):', '0.000000e+00')
othersizer.AddGrowableCol(1, 1)
staticsizer.Add(self.visapanel, 0, wx.EXPAND|wx.ALL, 5)
staticsizer.Add(otherpanel, 0, wx.EXPAND|wx.ALL, 5)
self.SetSizerAndFit(staticsizer)
def _onDefocusText(self, event):
"""Format a value when its control loses focus."""
source = event.GetEventObject()
value = source.GetValue()
try:
fval = float(value)
except ValueError:
fval = 0.0
if source is self.offsetBox:
source.SetValue('%.6e' % fval)
@property
def label(self):
"""Get the panel's label."""
return self.staticpanel.GetLabel()
@label.setter
[docs] def label(self, newLabel):
"""Set the panel's label."""
self.staticpanel.SetLabel(newLabel)
@property
[docs] def address(self):
"""Get the VISA resource address."""
return self.visapanel.value
@property
[docs] def offsetVoltage(self):
"""Get the offset voltage in volts."""
return float(self.offsetBox.GetValue())
[docs]class AveragingPanel(wx.Panel):
"""A panel for configuring the averaging parameters for some instrument."""
def __init__(self, parent, label='Averaging'):
super(AveragingPanel, self).__init__(parent, -1)
controlStyle = wx.TE_RIGHT
self.staticpanel = gh.Panel(self, 'flex_grid', label, 3, 2, 5, 5)
self.staticpanel.addGrowableColumn(1, 1)
myCtrl = partial(self.staticpanel.addLabeledText, style=controlStyle,
border=0, defocusHandler=self._onDefocusText)
self.averageBox = myCtrl('Averages:', '20')
self.pretimeBox = myCtrl('Pre-time (s):', '1.000')
self.intertimeBox = myCtrl('Inter-time (s):', '1.000')
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.staticpanel, 1, wx.EXPAND | wx.ALL)
self.SetSizerAndFit(sizer)
def _onDefocusText(self, event):
"""Format a value when its control loses focus."""
source = event.GetEventObject()
value = source.GetValue()
try:
fval = float(value)
except ValueError:
fval = 0.0
if source is self.averageBox:
source.SetValue('%d' % fval)
elif source is self.pretimeBox:
source.SetValue('%.3f' % fval)
elif source is self.intertimeBox:
source.SetValue('%.3f' % fval)
@property
def label(self):
"""Get the panel's label."""
return self.staticpanel.GetLabel()
@label.setter
[docs] def label(self, newLabel):
"""Set the panel's label."""
self.staticpanel.SetLabel(newLabel)
@property
[docs] def averages(self):
"""Get the number of averages."""
return int(self.averageBox.GetValue())
@property
[docs] def intertime(self):
"""Get the time between averages."""
return float(self.intertimeBox.GetValue())
@property
[docs] def pretime(self):
"""Get the time before averaging begins in seconds."""
return float(self.pretimeBox.GetValue())