Skip to content

Commit 1be7d8a

Browse files
authored
Add support for Aim-TTi EL302P power supply (#447)
1 parent e558690 commit 1be7d8a

File tree

7 files changed

+288
-0
lines changed

7 files changed

+288
-0
lines changed

doc/source/apiref/aimtti.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.. currentmodule:: instruments.aimtti
2+
3+
=======
4+
Aim-TTi
5+
=======
6+
7+
:class:`AimTTiEL302P` Power Supply
8+
=========================================
9+
10+
.. autoclass:: AimTTiEL302P
11+
:members:
12+
:undoc-members:

doc/source/apiref/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Contents:
1414
instrument
1515
generic_scpi
1616
agilent
17+
aimtti
1718
comet
1819
dressler
1920
fluke

src/instruments/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .abstract_instruments import Instrument
1313

1414
from . import agilent
15+
from . import aimtti
1516
from . import comet
1617
from . import dressler
1718
from . import generic_scpi

src/instruments/aimtti/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env python
2+
"""
3+
Module containing Aim-TTi power supplies
4+
"""
5+
6+
7+
from .aimttiel302p import AimTTiEL302P
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env python
2+
"""
3+
Provides support for the Aim-TTI EL302P power supply
4+
"""
5+
6+
# IMPORTS #####################################################################
7+
8+
from enum import Enum
9+
10+
from instruments.abstract_instruments import PowerSupply
11+
from instruments.units import ureg as u
12+
from instruments.util_fns import (
13+
bounded_unitful_property,
14+
enum_property,
15+
unitful_property,
16+
)
17+
18+
# CLASSES #####################################################################
19+
20+
21+
class AimTTiEL302P(PowerSupply, PowerSupply.Channel):
22+
"""
23+
The Aim-TTI EL302P is a single output power supply.
24+
25+
Because it is a single channel output, this object inherits from both
26+
PowerSupply and PowerSupply.Channel.
27+
28+
Before this power supply can be remotely operated, remote communication
29+
must be enabled and the unit must be on. Please refer to the manual.
30+
31+
Example usage:
32+
33+
>>> import instruments as ik
34+
>>> psu = ik.aimtti.AimTTiEL302P.open_serial('/dev/ttyUSB0', 9600)
35+
>>> psu.voltage = 10 # Sets output voltage to 10V.
36+
>>> psu.voltage
37+
array(10.0) * V
38+
>>> psu.output = True # Turns on the power supply
39+
"""
40+
41+
# ENUMS ##
42+
43+
class Mode(Enum):
44+
"""
45+
Enum containing the possible modes of operations of the instrument.
46+
"""
47+
48+
#: Constant voltage mode
49+
voltage = "M CV"
50+
#: Constant current mode
51+
current = "M CC"
52+
53+
class Error(Enum):
54+
"""
55+
Enum containing the possible error codes returned by the instrument.
56+
"""
57+
58+
#: No errors
59+
error_none = "ERR 0"
60+
#: Command not recognized
61+
error_not_recognized = "ERR 1"
62+
#: Command value outside instrument limits
63+
error_outside_limits = "ERR 2"
64+
65+
# PROPERTIES ##
66+
67+
voltage, voltage_min, voltage_max = bounded_unitful_property(
68+
"V",
69+
u.volt,
70+
valid_range=(0.0 * u.volt, 30.0 * u.volt),
71+
doc="""
72+
Gets/sets the output voltage of the source. Value must be between
73+
0V and 30V.
74+
75+
:units: As specified, or assumed to be :math:`\\text{V}` otherwise.
76+
:type: `float` or `~pint.Quantity`
77+
""",
78+
input_decoration=lambda x: float(x[2:]),
79+
format_code="{}",
80+
)
81+
82+
voltage_sense = unitful_property(
83+
command="VO",
84+
units=u.volt,
85+
doc="""
86+
Gets the actual output voltage measured by the power supply.
87+
88+
:units: :math:`\\text{V}`
89+
:rtype: `~pint.Quantity`
90+
""",
91+
input_decoration=lambda x: float(x[2:]),
92+
readonly=True,
93+
)
94+
95+
current, current_min, current_max = bounded_unitful_property(
96+
"I",
97+
u.amp,
98+
valid_range=(0.01 * u.amp, 2.0 * u.amp),
99+
doc="""
100+
Gets/sets the output current of the source. Value must be between
101+
0.01A and 2A.
102+
103+
:units: As specified, or assumed to be :math:`\\text{A}` otherwise.
104+
:type: `float` or `~pint.Quantity`
105+
""",
106+
input_decoration=lambda x: float(x[2:]),
107+
format_code="{}",
108+
)
109+
110+
current_sense = unitful_property(
111+
command="IO",
112+
units=u.amp,
113+
doc="""
114+
Gets the actual output current measured by the power supply.
115+
116+
:units: :math:`\\text{A}`
117+
:rtype: `~pint.Quantity`
118+
""",
119+
input_decoration=lambda x: float(x[2:]),
120+
readonly=True,
121+
)
122+
123+
@property
124+
def output(self):
125+
return self.query("OUT?") == "OUT ON"
126+
127+
@output.setter
128+
def output(self, newval):
129+
value = "ON" if newval is True else "OFF"
130+
self.sendcmd(f"{value}")
131+
132+
mode = enum_property(
133+
"M",
134+
Mode,
135+
doc="""
136+
Gets output mode status.
137+
""",
138+
readonly=True,
139+
)
140+
141+
error = enum_property(
142+
"ERR",
143+
Error,
144+
doc="""
145+
Gets the value in the error register.
146+
""",
147+
readonly=True,
148+
)
149+
150+
@property
151+
def name(self):
152+
"""
153+
Gets the name of the connected instrument.
154+
155+
:rtype: `str`
156+
"""
157+
idn_string = self.query("*IDN?")
158+
idn_list = idn_string.split(",")
159+
return " ".join(idn_list[:2])
160+
161+
def reset(self):
162+
"""
163+
Resets the instrument to the default power-up settings
164+
(1.00V, 1.00A, output off).
165+
"""
166+
self.sendcmd("*RST")
167+
168+
@property
169+
def channel(self):
170+
"""
171+
Return the channel (which in this case is the entire instrument, since
172+
there is only 1 channel on the EL302P.)
173+
174+
:rtype: 'tuple' of length 1 containing a reference back to the parent
175+
EL302P object.
176+
"""
177+
return (self,)

tests/test_aimtti/__init__.py

Whitespace-only changes.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
"""
3+
Unit tests for the Aim-TTI EL302P single output power supply
4+
"""
5+
6+
# IMPORTS #####################################################################
7+
8+
import pytest
9+
10+
import instruments as ik
11+
from instruments.units import ureg as u
12+
from tests import expected_protocol, unit_eq
13+
14+
# TESTS #######################################################################
15+
16+
17+
def test_channel():
18+
with expected_protocol(ik.aimtti.AimTTiEL302P, [], [], sep="\n") as psu:
19+
assert psu.channel[0] == psu
20+
assert len(psu.channel) == 1
21+
22+
23+
def test_current():
24+
with expected_protocol(
25+
ik.aimtti.AimTTiEL302P, ["I 1.0", "I?"], ["I 1.00"], sep="\n"
26+
) as psu:
27+
psu.current = 1.0 * u.amp
28+
assert psu.current == 1.0 * u.amp
29+
30+
31+
def test_current_sense():
32+
with expected_protocol(
33+
ik.aimtti.AimTTiEL302P, ["IO?"], ["I 1.00"], sep="\n"
34+
) as psu:
35+
assert psu.current_sense == 1.00 * u.amp
36+
37+
38+
def test_error():
39+
with expected_protocol(
40+
ik.aimtti.AimTTiEL302P, ["ERR?"], ["ERR 0"], sep="\n"
41+
) as psu:
42+
assert psu.error == ik.aimtti.AimTTiEL302P.Error.error_none
43+
44+
45+
def test_mode():
46+
with expected_protocol(ik.aimtti.AimTTiEL302P, ["M?"], ["M CV"], sep="\n") as psu:
47+
assert psu.mode == ik.aimtti.AimTTiEL302P.Mode.voltage
48+
49+
50+
def test_name():
51+
with expected_protocol(
52+
ik.aimtti.AimTTiEL302P, ["*IDN?"], ["Thurlby Thandar,EL302P,0,v2.00"], sep="\n"
53+
) as psu:
54+
assert psu.name == "Thurlby Thandar EL302P"
55+
56+
57+
def test_off():
58+
with expected_protocol(
59+
ik.aimtti.AimTTiEL302P, ["OFF", "OUT?"], ["OUT OFF"], sep="\n"
60+
) as psu:
61+
psu.output = False
62+
assert not psu.output
63+
64+
65+
def test_on():
66+
with expected_protocol(
67+
ik.aimtti.AimTTiEL302P, ["ON", "OUT?"], ["OUT ON"], sep="\n"
68+
) as psu:
69+
psu.output = True
70+
assert psu.output
71+
72+
73+
def test_reset():
74+
with expected_protocol(ik.aimtti.AimTTiEL302P, ["*RST"], [], sep="\n") as psu:
75+
psu.reset()
76+
77+
78+
def test_voltage():
79+
with expected_protocol(
80+
ik.aimtti.AimTTiEL302P, ["V 10.0", "V?"], ["V 10.00"], sep="\n"
81+
) as psu:
82+
psu.voltage = 10.0 * u.volt
83+
assert psu.voltage == 10.0 * u.volt
84+
85+
86+
def test_voltage_sense():
87+
with expected_protocol(
88+
ik.aimtti.AimTTiEL302P, ["VO?"], ["V 24.00"], sep="\n"
89+
) as psu:
90+
assert psu.voltage_sense == 24.00 * u.volt

0 commit comments

Comments
 (0)