Skip to content

Commit f86ef55

Browse files
Baijualexavicent
authored andcommitted
Add support for Rohde Schwarz RF signal generator SMC100A (alexforencich#1)
Add support for Rohde Schwarz RF signal generator SMC100A
1 parent cfa45ce commit f86ef55

6 files changed

Lines changed: 281 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Instrument standard from the [IVI foundation](http://www.ivifoundation.org/).
5555
* Agilent 8340/1 A/B
5656
* Agilent 8642 A/B
5757
* Agilent ESG E4400B series
58+
* Rohde and Schwarz SMC100A
5859
* Other
5960
* Agilent 8156A optical attenuator
6061
* Agilent 85644/5A tracking source

ivi/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"jdsu",
5353
"lecroy",
5454
"rigol",
55+
"rohdeschwarz",
5556
"tektronix",
5657
"testequity"]
5758

ivi/rohdeschwarz/__init__.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# coding=utf-8
2+
"""
3+
4+
Python Interchangeable Virtual Instrument Library
5+
6+
Copyright (c) Acconeer AB, 2018
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy
9+
of this software and associated documentation files (the "Software"), to deal
10+
in the Software without restriction, including without limitation the rights
11+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
copies of the Software, and to permit persons to whom the Software is
13+
furnished to do so, subject to the following conditions:
14+
15+
The above copyright notice and this permission notice shall be included in
16+
all copies or substantial portions of the Software.
17+
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
20+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
THE SOFTWARE.
25+
26+
"""
27+
28+
# RF Signal generators
29+
# SMC 100A
30+
from .rohdeschwarzSMC100A import rohdeschwarzSMC100A
31+
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# coding=utf-8
2+
"""
3+
4+
Python Interchangeable Virtual Instrument Library
5+
6+
Copyright (c) Acconeer AB, 2018
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy
9+
of this software and associated documentation files (the "Software"), to deal
10+
in the Software without restriction, including without limitation the rights
11+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
copies of the Software, and to permit persons to whom the Software is
13+
furnished to do so, subject to the following conditions:
14+
15+
The above copyright notice and this permission notice shall be included in
16+
all copies or substantial portions of the Software.
17+
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
20+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
THE SOFTWARE.
25+
26+
"""
27+
28+
from .. import ivi
29+
from .. import scpi
30+
from .. import rfsiggen
31+
32+
class rohdeschwarzBaseRFSigGen(scpi.common.IdnCommand, scpi.common.Reset, scpi.common.ErrorQuery,
33+
ivi.Driver, rfsiggen.Base):
34+
35+
def __init__(self, *args, **kwargs):
36+
self.__dict__.setdefault('_instrument_id', '')
37+
38+
super(rohdeschwarzBaseRFSigGen, self).__init__(*args, **kwargs)
39+
40+
self._rf_rms_voltage_level = 0.0
41+
42+
# frequency limit in Hertz
43+
self._frequency_low = 9e3
44+
self._frequency_high = 1100e6
45+
# rf level limit in dBm
46+
self._rf_level_low = -120.0
47+
self._rf_level_high = 19
48+
# rf rms voltage level limit in Volt
49+
self._rf_rms_voltage_level_low = 223.61e-9
50+
self._rf_rms_voltage_level_high = 1.993
51+
52+
self._identity_description = "Rohde&Schwarz generic IVI RF signal generator driver"
53+
self._identity_identifier = ""
54+
self._identity_revision = ""
55+
self._identity_vendor = ""
56+
self._identity_instrument_manufacturer = "Rohde&Schwarz"
57+
self._identity_instrument_model = ""
58+
self._identity_instrument_firmware_revision = ""
59+
self._identity_specification_major_version = 1
60+
self._identity_specification_minor_version = 0
61+
self._identity_supported_instrument_models = list(['SMC100A'])
62+
63+
self._add_property('rf.rms_voltage_level',
64+
self._get_rf_rms_voltage_level,
65+
self._set_rf_rms_voltage_level,
66+
None,
67+
ivi.Doc("""
68+
Rms voltage level of the instrument.
69+
"""))
70+
71+
def _initialize(self, resource = None, id_query = False, reset = False, **keywargs):
72+
"Opens an I/O session to the instrument."
73+
74+
super(rohdeschwarzBaseRFSigGen, self)._initialize(resource, id_query, reset, **keywargs)
75+
76+
# interface clear
77+
if not self._driver_operation_simulate:
78+
self._clear()
79+
80+
# check ID
81+
if id_query and not self._driver_operation_simulate:
82+
id = self.identity.instrument_model
83+
id_check = self._instrument_id
84+
id_short = id[:len(id_check)]
85+
if id_short != id_check:
86+
raise Exception("Instrument ID mismatch, expecting %s, got %s", id_check, id_short)
87+
88+
# reset
89+
if reset:
90+
self.utility.reset()
91+
92+
def _get_rf_frequency(self):
93+
"Reads the frequency of the generated RF output signal. The unit is Hertz"
94+
if not self._driver_operation_simulate and not self._get_cache_valid():
95+
self._rf_frequency = float(self._ask("FREQ?"))
96+
self._set_cache_valid()
97+
return self._rf_frequency
98+
99+
def _set_rf_frequency(self, value):
100+
"Specifies the frequency of the generated RF output signal. The unit is Hertz"
101+
value = float(value)
102+
if value < self._frequency_low or value > self._frequency_high:
103+
raise ivi.OutOfRangeException()
104+
if not self._driver_operation_simulate:
105+
self._write("FREQ %e HZ" % value)
106+
self._rf_frequency = value
107+
self._set_cache_valid()
108+
109+
def _get_rf_level(self):
110+
"""
111+
return set value in dBm of rf output level containing offset.
112+
"""
113+
return self._rf_level
114+
115+
def _set_rf_level(self, value):
116+
"""
117+
Sets the level of the Level display, i.e. the level containing offset. The unit is dBm
118+
"""
119+
value = float(value)
120+
if value < self._rf_level_low or value > self._rf_level_high:
121+
raise ivi.OutOfRangeException()
122+
if not self._driver_operation_simulate:
123+
self._write("POW %e dBm" % value)
124+
self._rf_level = value
125+
self._rf_rms_voltage_level = self._dbm_to_rms(value)
126+
self._set_cache_valid()
127+
128+
def _get_rf_rms_voltage_level(self):
129+
"""
130+
return set value in volt of rf output level containing offset.
131+
"""
132+
return self._rf_rms_voltage_level
133+
134+
def _set_rf_rms_voltage_level(self, value):
135+
"""
136+
Sets the rms voltage level of the Level display, i.e. the level containing offset. The unit is Volt
137+
"""
138+
value = float(value)
139+
if value < self._rf_rms_voltage_level_low or value > self._rf_rms_voltage_level_high:
140+
raise ivi.OutOfRangeException()
141+
if not self._driver_operation_simulate:
142+
self._write("POW %e V" % value)
143+
self._rf_rms_voltage_level = value
144+
self._rf_level = self._rms_to_dbm(value)
145+
self._set_cache_valid()
146+
147+
def _get_rf_output_enabled(self):
148+
"Check if RF output is enabled, Returns True if enabled"
149+
return self._rf_output_enabled
150+
151+
def _set_rf_output_enabled(self, value):
152+
"""
153+
If value is non zero, the signal the RF signal generator produces appears at the output connector.
154+
If it is zero, the signal the RF signal generator produces does not appear at the output connector
155+
"""
156+
value = bool(value)
157+
if not self._driver_operation_simulate:
158+
if value:
159+
self._write("OUTP ON")
160+
else:
161+
self._write("OUTP OFF")
162+
self._rf_output_enabled = value
163+
self._set_cache_valid()
164+
165+
def _rf_disable_all_modulation(self):
166+
"Disables modulation, similar result as pressing MOD on/off."
167+
if not self._driver_operation_simulate:
168+
self._write("MOD OFF")
169+
170+
def _rf_is_settled(self):
171+
"Queries if the RF output signal is currently settled. Returns true if settled"
172+
if not self._driver_operation_simulate:
173+
return self._read_stb() & (1 << 7) == 0
174+
return True
175+
176+
def _rf_wait_until_settled(self, maximum_time):
177+
"This function waits maximumtime(milli seconds) until the state of the RF output signal has settled."
178+
t = 0
179+
while not self._rf_is_settled() and t < maximum_time:
180+
time.sleep(0.001)
181+
t = t + 0.001
182+
183+
def _rms_to_dbm(self, v, r=50):
184+
"This function converts rms volts v to dBm, r is resistance in ohms."
185+
return (10 * ivi.np.log10(ivi.np.abs(v** 2.)/r) + 30)
186+
187+
def _dbm_to_rms(self, p, r=50):
188+
"This function converts dBm to rms volts, r is resistance in ohms."
189+
return (ivi.np.sqrt(r*(10.**(p/10.))/1000))
190+
191+
def _utility_error_query(self):
192+
error_code = 0
193+
error_message = "No error"
194+
if not self._driver_operation_simulate:
195+
error_msg_list = self._ask("system:error?").split(',')
196+
error_code = int(error_msg_list[0])
197+
error_message = ''.join(error_msg_list[1:]).strip(' "')
198+
return (error_code, error_message)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# coding=utf-8
2+
"""
3+
4+
Python Interchangeable Virtual Instrument Library
5+
6+
Copyright (c) Acconeer AB, 2018
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy
9+
of this software and associated documentation files (the "Software"), to deal
10+
in the Software without restriction, including without limitation the rights
11+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
copies of the Software, and to permit persons to whom the Software is
13+
furnished to do so, subject to the following conditions:
14+
15+
The above copyright notice and this permission notice shall be included in
16+
all copies or substantial portions of the Software.
17+
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
20+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
THE SOFTWARE.
25+
26+
"""
27+
28+
from .rohdeschwarzBaseRFSigGen import *
29+
30+
31+
class rohdeschwarzSMC100A(rohdeschwarzBaseRFSigGen):
32+
"Rohde&Schwarz SMC 100A RF Signal Generator"
33+
34+
def __init__(self, *args, **kwargs):
35+
self.__dict__.setdefault('_instrument_id', 'SMC100A')
36+
37+
super(rohdeschwarzSMC100A, self).__init__(*args, **kwargs)
38+
39+
# frequency limit in Hertz
40+
self._frequency_low = 9e3
41+
self._frequency_high = 1100e6
42+
# rf level limit in dBm
43+
self._rf_level_low = -120.0
44+
self._rf_level_high = 19
45+
# rf rms voltage level limit in Volt
46+
self._rf_rms_voltage_level_low = 223.61e-9
47+
self._rf_rms_voltage_level_high = 1.993
48+
49+
self._initialize(*args, **kwargs)

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def run_tests(self):
6868
'ivi.jdsu',
6969
'ivi.lecroy',
7070
'ivi.rigol',
71+
'ivi.rohdeschwarz',
7172
'ivi.tektronix',
7273
'ivi.testequity'],
7374
requires = ['numpy'],

0 commit comments

Comments
 (0)