forked from heeres/qtlab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MANUAL
258 lines (198 loc) · 9.6 KB
/
MANUAL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
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
QT Lab Manual
Contents
1. Introduction
1.1. Getting QTLab
1.2. Dependencies
1.3. Contributing
1.4. Supported instruments
2. Components
2.1. Instruments
2.2. Data
2.3. Plots
2.4. Finding a Data, Plot or Window object
2.5. Data analysis
3. Extensions to QTLab
4. Measurement scripts and user specific configuration
5. Performance
1. Introduction
QTLab is a collection of python code to simplify and automatically
document computer-controlled measurements. It provides some basic GUI
functionality, makes scripting easy, and automatically saves a large
amount of instrument settings and other details describing the state
of your measurement setup.
QTLab also provides basic tools for analysing/plotting the measured
data (see 2.5.). However, these features are only loosely integrated
into the measurement UI. This is because, in general, it is a very
good idea to separate your analysis and measurement logic into
separate processes! This is important because you don't want your
measurement to crash/slow down if something goes wrong in
analysis/plotting, and because you almost certainly want to tweak the
analysis/plotting later, during or after the measurement.
1.1. Getting QTLab
You can get the latest version for QTLab from github.
As of 2016, arguably the most active fork is
https://github.com/govenius/qtlab
but you should also check out the level of activity in other forks on
github.
1.2. Dependencies
See the INSTALL file in the qtlab folder.
1.3. Contributing
Get in touch with the person that has committed the most in the last
year or two (see the git(hub) history).
1.4. Supported instruments
See the instrument_plugins subdirectory.
However, adding drivers is rather trivial for simple instruments
(like voltage sources, lockins, etc) so don't be afraid if you
don't see your instruments there. See 2.1.2.
2. Components
2.1. Instruments
2.1.1. Basics
The 'Instrument' and 'Instruments' classes are at the core of QTLab. They
are easy wrappers to create a sort of standardized python driver to talk
to measurement instrumentation. 'Instrument' is a base class for specific
drivers, 'Instruments' is a container class through which specific Instrument
instances can be found and created.
The instruments collection can be accessed easily by typing:
qt.instruments
Create a new instrument is a simple matter:
qt.instruments.create('<name>', '<instrument type>', <parameters>)
For example:
qt.instruments.create('dmm1', 'Keithley_2700', address='GPIB::12')
To get and set properties, you should use the automatically generated
get_prop1() and set_prop1(val) functions. They will eventually call the
lower-level do_get_prop1() and do_set_prop1(val) functions, which you
should only use directly if you know what you're doing.
To facilitate easy reloading of instruments, the actual instrument objects
you normally deal with are 'proxies'. This basically means that you talk to
the real instrument object indirectly. As a result of this, not all functions
that are defined in the instrument driver are available: only functions from
the driver that do not start with an underscore ('_') are included / proxied.
A nice thing is that by doing this a whole bunch of non-relevant functions
that are present in the real instrument object by default are not shown when
typing ins.<tab> in IPython. If you ever need to access the real instrument
object, you can use the '_ins' property (e.g. dmm1._ins).
2.1.2. Writing an instrument driver
There are many instrument drivers available in the standard distribution. They
are quite good examples of most features.
Each instrument driver should contain a class with the same name as the
filename.
The foundation of the Instrument class is formed by the functions 'add_parameter'
and 'add_function'. They provide common functionality for the instrument
parameters and functions, like type-checking (float, int, etc) and maximum
and minimum checking.
Defining such a parameter is done in the __init__ of the instrument plugin.
Example:
self.add_parameter('dac1', flags=Instrument.FLAG_GETSET,
type=types.FloatType, minval=-1, maxval=5)
This specifies the parameter 'dac1' as a floating point parameter that
supports GET and SET. Two functions (get_dac1 and set_dac1) will then
automatically be added to the instrument. They are wrappers around the
actual implementation (which you will have to write yourself).
When calling 'set_dac1(value)' parameter type and range checks are performed
before the parameter is really set.
The actual getting and setting of this parameter needs to be implemented in
the driver in two functions:
def do_set_dac1(self, value):
....
def do_get_dac1(self):
....
return <value>
These functions usually only perform the instrument communication, such as
sending and reading of GPIB commands. Note, once again, that in principle
these functions should not be used directly.
Additional options are available for added parameters; see the documentation
of the add_parameter function for more details.
To expose a function in the user interface, register it with add_function:
self.add_function('reset')
2.1.3 Why use the wrapper?
There are a few advantages of using the wrapper around the 'get' and 'set'
functions for your instrument, although they are more obvious for the
'set' parts. For the 'get' functions:
- Proper casting of return values
- Automatically create functions for different channels
- Inform other components about updated values (only if fast=False,
which is the default).
- Get multiple parameters in one go:
vals = ins.get(('val1', 'val2', 'val3'))
For the 'set' functions:
- Automatically create functions for different channels
- Input type casting
- Checking of minimum and maximum value
- Automatic rate limiting (e.g. 0.5mV / 50msec)
- 'Persistent' values are stored in the config file, which is useful in
the case an instrument cannot be read out.
- Inform other components about updated values (only if fast=False,
which is the default).
Another nice thing is that instruments can be made available to remote
instances of QTLab, e.g. you could you an instrument physically hooked up
to one computer from another machine over the network.
2.1.4. Tags
Instruments and instrument parameters can have tags which can be used to
group them. Some special tags exist as well:
Instruments:
- physical: a physical instrument.
- virtual: a virtual instrument.
- positioner: a motion control instrument, should support move_abs() or
move_rel().
Parameters:
- measure: parameter that can be 'measured' in a loop.
- sweep: parameter that can be 'swept' in a loop.
2.2. Data
Measurement data can be stored in an instance of the Data class. This supports
things such as loading / saving of data and adding meta-data. An example:
d = Data('test.dat') # This will load the file if it exists
d.add_coordinate('x') # Interpret data as data(x,y) = (v1, v2)
d.add_coordinate('y')
d.add_value('v1')
d.add_value('v2')
Although the data is stored internally as a simple array of values, some more
information about these values can be added: each value can be added as either
a 'coordinate' or a 'value' dimension. This extra information will be used
when adding the Data object to a plot.
2.3. Plots
See examples/plots.py.
2.4. Finding a Data, Plot or Window object
The Data, Plot and QTWindow classes store a list of instances inside them.
You can get the list with the <class>.get_named_list() function, but it is
easier to access these lists directly in the qt module. You can see their
contents easily by typing their name in the IPython shell:
qt.data
qt.get_plots()
qt.windows
Getting an item from the list works as follows:
p = plot.get_plot('plot1')
d = qt.data('data1')
2.5. Data analysis
See examples/analysis_with_dataview.py.
3. Extensions to QT Lab
Extensions to QT lab are easy to write. This code should normally be placed
in the 'source/lib/' directory. A few sub-directories are available there to
organize the extensions:
lib/dll_support - Communicating with DLLs (e.g. NI DAQ)
lib/file_support - Reading file types (e.g. SPE files)
lib/gui - Gui classes (e.g. dropdowns)
lib/math - Mathimatical functionality (e.g. fitting)
lib/network - Network functionality (e.g. tcpserver)
lib/ - More generic things (e.g. temporary file handler)
4. Measurement scripts and user specific configuration
Measurements are almost always executed using a script, rather than by
typing in commands directly to the iPython shell.
See examples/basic_measure_script.py for a minimal example.
The most common user-specific settings can be set in the file userconfig.py
The following options are available:
datadir - Default data folder
startdir - path where you like QT lab to start,
i.e. your scripts folder.
startscript - script file you wish to run when QT lab starts
user_insdir - location where you store your user-specific
- (virtual) instrument drivers.
It is good practice to put any user specific scripts and modules in a
folder outside the qtlab folder. It is also a good idea to turn those
into (independent) git repositories.
5. Performance
The overhead of the 'get' and 'set' functions are quite small, but depending
on your needs they could be significant. The following numbers were acquired
on a Inspiron 6400 laptop with a 1.73GHz Core Duo processor under Linux:
do_get_<parameter> directly: ~3.7us
get('parameter', fast=True): ~8.6us
get_<parameter> or get('parameter'): ~11.5us