Skip to content

Commit 9b5e089

Browse files
authored
Merge pull request #8254 from fe-dor/feature/keysight_33xxx_improvments
feature: KeysightAgilent_33XXX.py improvements
2 parents e146eee + 54e612e commit 9b5e089

8 files changed

Lines changed: 216 additions & 5 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Referring to the:
2+
3+
- `Keysight Trueform Series Operating and Service Guide`_
4+
- `Agilent 33210A 10 MHz Function / Arbitrary Waveform Generator User's Guide`_
5+
- `Agilent 33250A 80 MHz Function / Arbitrary Waveform Generator`_
6+
7+
Improvements:
8+
9+
- Expanded the list of supported devices for the KeysightAgilent_33XXX driver
10+
- Added implementations of SCPI commands for working with: ARB signals, edges of Pulse function, output termination, voltage autoranging
11+
- Created tests for new commands and update sim file
12+
13+
.. _`Keysight Trueform Series Operating and Service Guide`: https://www.keysight.com/us/en/assets/9018-03714/service-manuals/9018-03714.pdf
14+
.. _`Agilent 33210A 10 MHz Function / Arbitrary Waveform Generator User's Guide`: https://www.keysight.com/us/en/support/33210A/33210a-waveform-and-function-generator.html
15+
.. _`Agilent 33250A 80 MHz Function / Arbitrary Waveform Generator`: https://www.keysight.com/us/en/support/33250A/function--arbitrary-waveform-generator-80-mhz.html

src/qcodes/instrument/sims/Keysight_33xxx.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,47 @@ devices:
4545
setter:
4646
q: "SOURce1:BURSt:NCYCles {}"
4747

48+
chan1 edges:
49+
default: 4.000000000000000E-09
50+
getter:
51+
q: "SOURce1:FUNCtion:PULSe:TRANsition?"
52+
r: "{:.15E}"
53+
setter:
54+
q: "SOURce1:FUNCtion:PULSe:TRANsition {}"
55+
specs:
56+
type: float
57+
58+
chan1 output_load:
59+
default: 5.000000000000000E+01
60+
getter:
61+
q: "OUTPut1:LOAD?"
62+
r: "{:.15E}"
63+
setter:
64+
q: "OUTPut1:LOAD {}"
65+
specs:
66+
type: float
67+
68+
chan1 auto_range:
69+
default: 1
70+
getter:
71+
q: "SOURce1:VOLTage:RANGe:AUTO?"
72+
r: "{}"
73+
setter:
74+
q: "SOURce1:VOLTage:RANGe:AUTO {}"
75+
specs:
76+
type: int
77+
valid: [ 0, 1 ]
78+
79+
chan1 srate:
80+
default: 4.000000000000000E+04
81+
getter:
82+
q: "SOURce1:FUNCtion:ARBitrary:SRATe?"
83+
r: "{:.15E}"
84+
setter:
85+
q: "SOURce1:FUNCtion:ARBitrary:SRATe {}"
86+
specs:
87+
type: float
88+
4889
resources:
4990
GPIB::1::INSTR:
5091
device: device 1

src/qcodes/instrument_drivers/Keysight/KeysightAgilent_33XXX.py

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def val_parser(parser: type, inputstring: str) -> float | int:
119119
vals=vals.Numbers(0, 360),
120120
)
121121
"""Parameter phase"""
122+
122123
self.amplitude_unit: Parameter = self.add_parameter(
123124
"amplitude_unit",
124125
label=f"Channel {channum} amplitude unit",
@@ -148,6 +149,7 @@ def val_parser(parser: type, inputstring: str) -> float | int:
148149
get_parser=float,
149150
)
150151
"""Parameter offset"""
152+
151153
self.output: Parameter = self.add_parameter(
152154
"output",
153155
label=f"Channel {channum} output state",
@@ -174,10 +176,21 @@ def val_parser(parser: type, inputstring: str) -> float | int:
174176
set_cmd=f"SOURce{channum}:FUNCtion:PULSE:WIDTh {{}}",
175177
get_cmd=f"SOURce{channum}:FUNCtion:PULSE:WIDTh?",
176178
get_parser=float,
177-
unit="S",
179+
unit="s",
178180
)
179181
"""Parameter pulse_width"""
180182

183+
self.edges: Parameter = self.add_parameter(
184+
"edges",
185+
label=f"Channel {channum} edges width",
186+
set_cmd=f"SOURce{channum}:FUNCtion:PULSe:TRANsition {{}}",
187+
get_cmd=f"SOURce{channum}:FUNCtion:PULSe:TRANsition?",
188+
get_parser=float,
189+
unit="s",
190+
vals=vals.MultiType(vals.Numbers(), vals.Enum("MIN", "MAX")),
191+
)
192+
"""Sets the transition times for the leading and trailing edges of the pulse."""
193+
181194
# TRIGGER MENU
182195
self.trigger_source: Parameter = self.add_parameter(
183196
"trigger_source",
@@ -298,7 +311,7 @@ def val_parser(parser: type, inputstring: str) -> float | int:
298311

299312
self.burst_int_period: Parameter = self.add_parameter(
300313
"burst_int_period",
301-
label=(f"Channel {channum} burst internal period"),
314+
label=f"Channel {channum} burst internal period",
302315
set_cmd=f"SOURce{channum}:BURSt:INTernal:PERiod {{}}",
303316
get_cmd=f"SOURce{channum}:BURSt:INTernal:PERiod?",
304317
unit="s",
@@ -312,6 +325,68 @@ def val_parser(parser: type, inputstring: str) -> float | int:
312325
)
313326
"""The burst period is the time between the starts of consecutive bursts when trigger is immediate."""
314327

328+
self.output_load: Parameter = self.add_parameter(
329+
"output_load",
330+
label=f"Channel {channum} output load",
331+
set_cmd=f"OUTPut{channum}:LOAD {{}}",
332+
get_cmd=f"OUTPut{channum}:LOAD?",
333+
get_parser=partial(val_parser, float),
334+
unit="ohms",
335+
vals=vals.MultiType(vals.Numbers(1, 10000), vals.Enum("INF", "MIN", "MAX")),
336+
)
337+
"""Sets expected output termination. Should equal the load impedance attached to the output."""
338+
339+
self.auto_range: Parameter = self.add_parameter(
340+
"auto_range",
341+
label=f"Channel {channum} range mode",
342+
set_cmd=f"SOURce{channum}:VOLTage:RANGe:AUTO {{}}",
343+
get_cmd=f"SOURce{channum}:VOLTage:RANGe:AUTO?",
344+
val_mapping={"ON": 1, "OFF": 0},
345+
vals=vals.Enum("ON", "OFF"),
346+
)
347+
"""Disables or enables voltage autoranging for all functions."""
348+
349+
# Arbitrary waveforms
350+
if self._parent.model[2] in [
351+
"5",
352+
"6",
353+
]: # Older models do not support all arbitrary options
354+
max_srate = self._parent._max_srate[self.model]
355+
self.srate: Parameter = self.add_parameter(
356+
"srate",
357+
label=f"Channel {channum} sample rate",
358+
set_cmd=f"SOURce{channum}:FUNCtion:ARBitrary:SRATe {{}}",
359+
get_cmd=f"SOURce{channum}:FUNCtion:ARBitrary:SRATe?",
360+
get_parser=float,
361+
unit="Sa/s",
362+
vals=vals.MultiType(
363+
vals.Numbers(1e-6, max_srate), vals.Enum("MIN", "MAX", "DEF")
364+
),
365+
)
366+
"""Sets the sample rate for the arbitrary waveform."""
367+
368+
self.add_function(
369+
"load_arb",
370+
call_cmd=f"SOURce{channum}:DATA:ARBitrary {{}}, {{}}",
371+
args=[vals.Strings(), vals.Arrays()],
372+
arg_parser=lambda sig_name, arr: (sig_name, ",".join(map(str, arr))),
373+
)
374+
"""Downloads integer values representing floating point values into waveform volatile memory."""
375+
# TODO: add DAC (Digital-to-Analog Converter) support.
376+
377+
self.add_function(
378+
"set_arb",
379+
call_cmd=f"SOURce{channum}:FUNCtion:ARBitrary {{}}",
380+
args=[vals.Strings()],
381+
)
382+
"""Selects an arbitrary waveform that has previously been loaded into volatile memory."""
383+
384+
self.add_function(
385+
"clear_arb",
386+
call_cmd=f"SOURce{channum}:DATA:VOLatile:CLEar",
387+
)
388+
"""Clears waveform memory and reloads the default waveform."""
389+
315390

316391
OutputChannel = Keysight33xxxOutputChannel
317392

@@ -402,23 +477,44 @@ def __init__(
402477
no_of_channels = {
403478
"33210A": 1,
404479
"33250A": 1,
480+
"33510B": 2,
405481
"33511B": 1,
406482
"33512B": 2,
483+
"33521B": 1,
407484
"33522B": 2,
408485
"33611A": 1,
486+
"33612A": 2,
487+
"33621A": 1,
409488
"33622A": 2,
410-
"33510B": 2,
411489
}
412490

413491
self._max_freqs = {
414492
"33210A": 10e6,
493+
"33250A": 80e6,
494+
"33510B": 20e6,
415495
"33511B": 20e6,
416496
"33512B": 20e6,
417-
"33250A": 80e6,
497+
"33521B": 30e6,
418498
"33522B": 30e6,
419499
"33611A": 80e6,
500+
"33612A": 80e6,
501+
"33621A": 120e6,
420502
"33622A": 120e6,
421-
"33510B": 20e6,
503+
}
504+
505+
# Refer to instruments User's guides
506+
self._max_srate = {
507+
"33210A": 50e6,
508+
"33250A": 200e6,
509+
"33510B": 160e6,
510+
"33511B": 160e6,
511+
"33512B": 160e6,
512+
"33521B": 250e6,
513+
"33522B": 250e6,
514+
"33611A": 660e6,
515+
"33612A": 660e6,
516+
"33621A": 1e9,
517+
"33622A": 1e9,
422518
}
423519

424520
self.num_channels = no_of_channels[self.model]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .KeysightAgilent_33XXX import Keysight33xxxSingleChannel
2+
3+
4+
class Keysight33521B(Keysight33xxxSingleChannel):
5+
"""
6+
QCoDeS driver for the Keysight 33521B waveform generator.
7+
"""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .KeysightAgilent_33XXX import Keysight33xxxDualChannels
2+
3+
4+
class Keysight33612A(Keysight33xxxDualChannels):
5+
"""
6+
QCoDeS driver for the Keysight 33612A waveform generator.
7+
"""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .KeysightAgilent_33XXX import Keysight33xxxSingleChannel
2+
3+
4+
class Keysight33621A(Keysight33xxxSingleChannel):
5+
"""
6+
QCoDeS driver for the Keysight 33621A waveform generator.
7+
"""

src/qcodes/instrument_drivers/Keysight/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
)
99
from .Keysight_33210a import Keysight33210A
1010
from .Keysight_33250a import Keysight33250A
11+
from .Keysight_33510b import Keysight33510B
1112
from .Keysight_33511b import Keysight33511B
1213
from .Keysight_33512b import Keysight33512B
14+
from .Keysight_33521b import Keysight33521B
1315
from .Keysight_33522b import Keysight33522B
1416
from .Keysight_33611a import Keysight33611A
17+
from .Keysight_33612a import Keysight33612A
18+
from .Keysight_33621a import Keysight33621A
1519
from .Keysight_33622a import Keysight33622A
1620
from .Keysight_34410A_submodules import Keysight34410A
1721
from .Keysight_34411A_submodules import Keysight34411A
@@ -86,10 +90,14 @@
8690
"Keysight344xxATrigger",
8791
"Keysight33210A",
8892
"Keysight33250A",
93+
"Keysight33510B",
8994
"Keysight33511B",
9095
"Keysight33512B",
96+
"Keysight33521B",
9197
"Keysight33522B",
9298
"Keysight33611A",
99+
"Keysight33612A",
100+
"Keysight33621A",
93101
"Keysight33622A",
94102
"Keysight34410A",
95103
"Keysight34411A",

tests/drivers/test_Keysight_33XXX.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,36 @@ def test_burst(driver: Keysight33522B) -> None:
7070
# assert driver.ch1.burst_ncycles() == 'INF'
7171

7272

73+
def test_edges(driver: Keysight33522B) -> None:
74+
assert driver.ch1.edges() == 4e-09
75+
driver.ch1.edges(5e-09)
76+
assert driver.ch1.edges() == 5e-09
77+
driver.ch1.edges(4e-09)
78+
79+
80+
def test_output_load(driver: Keysight33522B) -> None:
81+
assert driver.ch1.output_load() == 50
82+
driver.ch1.output_load(100)
83+
assert driver.ch1.output_load() == 100
84+
driver.ch1.output_load("INF")
85+
assert driver.ch1.output_load() == float("inf")
86+
driver.ch1.output_load(50)
87+
88+
89+
def test_auto_range(driver: Keysight33522B) -> None:
90+
assert driver.ch1.auto_range() == "ON"
91+
driver.ch1.auto_range("OFF")
92+
assert driver.ch1.auto_range() == "OFF"
93+
driver.ch1.auto_range("ON")
94+
95+
96+
def test_srate(driver: Keysight33522B) -> None:
97+
assert driver.ch1.srate() == 4e04
98+
driver.ch1.srate(3e04)
99+
assert driver.ch1.srate() == 3e04
100+
driver.ch1.srate(4e04)
101+
102+
73103
def test_wrong_model_warns(
74104
caplog: pytest.LogCaptureFixture, request: pytest.FixtureRequest
75105
) -> None:

0 commit comments

Comments
 (0)