SA.py 9.34 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: utf-8 -*-
"""
Module for Spectrum Analyzer Measurements

Author: Christian Schneider <c.schneider@uibk.ac.at>
Date: 18.01.2018
"""
import time

from IPLIST import IPList
from .Drivers.RohdeSchwarz.FSV30 import FSV30
from Monitor.main import db, Instruments
import getpass
import numpy as np
from Monitor.functions import retrieve_name
import pickle
from tqdm import tqdm_notebook
18
from DataModule.data_table import data_table
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76


class SA(object):
    """Spectrum Analyzer Instrument Class

    Provides an object to measure with the Spectrum Analyzers of the Kirchmair
    Lab.
    Requires that the device is listed in the IPList. Else the driver has
    to be specified.

    Parameters
    -----------
    id : 'SA1', 'SA2', '192.168.xxx.xxx'
        Name of the Spectrum Analyzer.
        You can list all devices using Instrument.list()
        You can also specify an IP, however then you have to manually specify
        the driver for the chosen IP address.
    Cryostat : str, None
        Name of the Cryostat. Choose between 'Freezer' and 'Cooler'. Use None
        for measurements without cryostat.
    driver : object, optional
        Driver for the SA. Only needed if SA is not already in IPList, or
        you specified it with an IP.
    """

    def __init__(self, id, cryostat, driver=None):
        try:
            # Try to find device in IPList
            self.ip = IPList[id]
        except KeyError:
            # If SA is not specified by valid IPList entry. Try directly ip
            if driver is not None:
                self.ip = id
            else:
                raise Exception('SA not in IPList. Please specify driver')
        self.CryoID = cryostat
        self.ch = 1

        # New for DB
        self.dB_ID = None
        self.id = id
        self.check_db()

        # Load specific drivers driver
        if id[:3] == 'SA1':
            self.driver = FSV30
        elif id[:4] == 'SA2':
            raise Exception('Not Implemented yet')
        else:
            if driver is None:
                raise Exception('DriverError. Specify Driver')
            else:
                self.d = driver

        self.instr = self.driver(self.ip)
        print("Identify: " + self.instr.identify())  # Identify at beginning
        print("IP: " + self.ip)

77
        self.instr.timeout = 10
78
79
80
81
82
83
84
85
86
87
88
89
90
        # Update database
        self.update_db()

    def identify(self):
        """Identify device. Returns a typical string indicating manufacturer
        and firmware version
        """
        return self.instr.identify()

    # Basic functions
    def meas(self, f1, f2, filename, avgs=1, bw_res='auto',
             points=32001, center=False, sweep_time='auto',
             **dm_parameters):
91
        """Take a spectrum and save it as a data_table datamodule
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

        Parameters
        -----------
        f1 : float
            Start frequency in Hz or center frequency in Hz if center flag is
            set to true
        f2 : float
            Stop frequency in Hz or span in Hz if center flag is set to true
        filename : str
            Filename for saving spectrum
        avgs : int
            Number of averages. Set to 0 or 1 for no averages
        bw_res : 'Auto', float
            Resolution bandwidth in Hz. Set to 'auto' for automatic detection
        points : 101 < int < 32001
            Number of points. Choose between 101 and 32001.
        center : bool
            Treat f1 and f2 as center frequency and span in Hz
        sweep_time : 'auto', float
            Set sweep time in s. Set to automatic detection by default
        dm_paramters : kwargs
            Optional parameters which will be saved in the datamodule
        """
        # Calculate frequency settings
        if not center:
            f_c = (f1 + f2) / 2
            f_span = (f2 - f1)
        else:
            f_c = f1
            f_span = f2
122
123
        if avgs == 0:
            avgs = 1
124
        self.instr.clear()
125
        # Set Spec parameters
126
127
128
129
130
131
        if sweep_time == 'auto':
            self.instr.sweep_time_auto('ON')
        else:
            self.instr.sweep_time_auto('OFF')
            self.instr.sweep_time(sweep_time)
        self.instr.continuous('OFF')  # Set to single acquisition
132
133
134
135
136
        self.instr.bw_res(bw_res)
        self.instr.center(f_c)
        self.instr.span(f_span)
        self.instr.points(points)
        # Acquire spectrum
137
138
139
        while int(self.instr.ask('*OPC?')) != 1:
            # Wait for device to be ready
            time.sleep(0.5)
140
        self.instr.averages(avgs)
141
        self.instr.run()  # Start data acquisition
142
143
144
145
146
147
        sweep_time = self.instr.sweep_time()
        for i in tqdm_notebook(range(avgs), unit="Sweep"):
            time.sleep(sweep_time)
        # Ensure that averaging finished
        while self.instr.count() != avgs:
            time.sleep(1)
148
149
150
151
152
153
154
155
        # Read spectrum
        trace = self.instr.read_trace()

        # Create datamodule
        f_start = f_c - f_span/2
        f_stop = f_c + f_span/2
        f = np.linspace(f_start, f_stop, points)

Christian Schneider's avatar
Christian Schneider committed
156
        data = data_table([f, trace], ['Frequency (Hz)', 'PSD (dB)'])
157
158
159
160
161
162
163
164
165
        data.insert_par(frange=[f_start, f_stop], npoints=points, navg=avgs,
                        BW=self.instr.bw_res(),
                        sweep_time=self.instr.sweep_time(),
                        **dm_parameters)
        # Save
        if filename:
            data.save(filename)
            self.update_db()
        else:
166
            self.update_db()
167
            data.plot()
168
169
170
171
172
            return data

    # Database functions #######################################################
    def get_pars(self):
        """Query current set parameters"""
173
174
        center = float(self.instr.center())
        span = float(self.instr.span())
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
        f_start = center - span/2
        f_stop = center + span/2
        dct = {'Resolution Bandwidth (Hz)': '{:.2e}'.format(
                self.instr.bw_res()),
               'f_start': '{:.3e} Hz'.format(f_start),
               'f_stop': '{:.3e} Hz'.format(f_stop),
               'f_center': '{:.3e} Hz'.format(center),
               'span': '{:.3e} Hz'.format(span),
               'averages': self.instr.averages(),
               'points': self.instr.points(),
               'Sweep time': '{:.3e} s'.format(self.instr.sweep_time()),
               'Continous Sweep': self.instr.continuous()
               }
        return dct

    def check_db(self):
        """A check if device is already in database and used by someone else
        """
        try:
            d = Instruments.query.filter_by(ip=self.ip).filter_by(
                channel=self.ch).first()
            if d:
                if d.user != getpass.getuser():
                    # If you are not the user print Error
                    user = d.user
                    db.session.commit()
                    raise Exception(
                        'Device already used by {user}. Please talk to'
                        ' him and then delete the device from the '
                        'Device Monitor'.format(user=user))
                else:
                    # If you are the user and the device is already in db,
                    # extract the id
                    self.dB_ID = d.id
                    db.session.commit()
        except:
            return None

    def update_db(self, update_fromWeb=False):
        """Update parameters in database value. Handles events from the
        Device Monitor WebApp by the flag update_fromWeb=True
        """
        if self.dB_ID:
            try:
                # To ensure that the library is working even if there is no
                # connection to the database
                d = Instruments.query.get(int(self.dB_ID))
                if not update_fromWeb:
                    # Only Update if flag is not set. Useful for flask server
                    # who would rename it to an unreadable name
                    d.varname = retrieve_name(self)
                    d.user = getpass.getuser()
                    d.pckle = pickle.dumps(self)
                d.parameters = self.get_pars()
                db.session.add(d)
                db.session.commit()
                db.session.close()
            except:
                return None

        else:
            # Create db entry
            # Create check to warn if the device is already used and demand
            # to delete it
            # Socket is not pickleable, close connection and remove socket
            pars = self.get_pars()
            idn = self.identify()
            self.instr.close()
            self.instr = None
            try:
                d = Instruments(ip=self.ip,
                                devtype='SA',
                                name=self.id,
                                varname=self.id,
                                parameters=pars,
                                pckle=pickle.dumps(self),
                                user=getpass.getuser(),
                                idn=idn,
                                channel=self.ch)
                # Store to database
                db.session.add(d)
                db.session.commit()
                # Acquire ID
                self.dB_ID = d.id
                # Save Object with self.dB_ID tag
                d.pckle = pickle.dumps(self)
                db.session.commit()
                db.session.close()
                # Reinit device
                self.instr = self.driver(self.ip)
            except:
                return None