|
1
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
|
|
3
|
|
|
""" |
|
4
|
|
|
This file contains the general logic for magnet control. |
|
5
|
|
|
|
|
6
|
|
|
Qudi is free software: you can redistribute it and/or modify |
|
7
|
|
|
it under the terms of the GNU General Public License as published by |
|
8
|
|
|
the Free Software Foundation, either version 3 of the License, or |
|
9
|
|
|
(at your option) any later version. |
|
10
|
|
|
|
|
11
|
|
|
Qudi is distributed in the hope that it will be useful, |
|
12
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14
|
|
|
GNU General Public License for more details. |
|
15
|
|
|
|
|
16
|
|
|
You should have received a copy of the GNU General Public License |
|
17
|
|
|
along with Qudi. If not, see <http://www.gnu.org/licenses/>. |
|
18
|
|
|
|
|
19
|
|
|
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the |
|
20
|
|
|
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/> |
|
21
|
|
|
""" |
|
22
|
|
|
|
|
23
|
|
|
from qtpy import QtCore |
|
24
|
|
|
import numpy as np |
|
25
|
|
|
import time |
|
26
|
|
|
import datetime |
|
27
|
|
|
from collections import OrderedDict |
|
28
|
|
|
|
|
29
|
|
|
from logic.generic_logic import GenericLogic |
|
30
|
|
|
|
|
31
|
|
|
|
|
32
|
|
|
class MagnetLogic(GenericLogic): |
|
33
|
|
|
""" A general magnet logic to control an magnetic stage with an arbitrary |
|
34
|
|
|
set of axis. |
|
35
|
|
|
|
|
36
|
|
|
DISCLAIMER: |
|
37
|
|
|
=========== |
|
38
|
|
|
|
|
39
|
|
|
The current status of the magnet logic is highly experimental and not well |
|
40
|
|
|
tested. The implementation has some considerable imperfections. The state of |
|
41
|
|
|
this module is considered to be UNSTABLE. |
|
42
|
|
|
|
|
43
|
|
|
This module has two major issues: |
|
44
|
|
|
- a lack of proper documentation of all the methods |
|
45
|
|
|
- usage of tasks is not implemented and therefore direct connection to |
|
46
|
|
|
all the modules is used (I tried to compress as good as possible all |
|
47
|
|
|
the part, where access to other modules occurs so that a later |
|
48
|
|
|
replacement would be easier and one does not have to search throughout |
|
49
|
|
|
the whole file.) |
|
50
|
|
|
|
|
51
|
|
|
However, the 'high-level state maschine' for the alignment should be rather |
|
52
|
|
|
general and very powerful to use. The different state were divided in |
|
53
|
|
|
several consecutive methods, where each method can be implemented |
|
54
|
|
|
separately and can be extended for custom needs. (I have drawn a diagram, |
|
55
|
|
|
which is much more telling then the documentation I can write down here.) |
|
56
|
|
|
|
|
57
|
|
|
I am currently working on that and will from time to time improve the status |
|
58
|
|
|
of this module. So if you want to use it, be aware that there might appear |
|
59
|
|
|
drastic changes. |
|
60
|
|
|
|
|
61
|
|
|
--- |
|
62
|
|
|
Alexander Stark |
|
63
|
|
|
""" |
|
64
|
|
|
|
|
65
|
|
|
|
|
66
|
|
|
_modclass = 'MagnetLogic' |
|
67
|
|
|
_modtype = 'logic' |
|
68
|
|
|
|
|
69
|
|
|
## declare connectors |
|
70
|
|
|
_in = {'magnetstage': 'MagnetInterface', |
|
71
|
|
|
'optimizerlogic': 'OptimizerLogic', |
|
72
|
|
|
'counterlogic': 'CounterLogic', |
|
73
|
|
|
'odmrlogic': 'ODMRLogic', |
|
74
|
|
|
'savelogic': 'SaveLogic', |
|
75
|
|
|
'scannerlogic':'ScannerLogic', |
|
76
|
|
|
'traceanalysis':'TraceAnalysisLogic', |
|
77
|
|
|
'gatedcounterlogic': 'GatedCounterLogic', |
|
78
|
|
|
'sequencegeneratorlogic': 'SequenceGeneratorLogic'} |
|
79
|
|
|
_out = {'magnetlogic': 'MagnetLogic'} |
|
80
|
|
|
|
|
81
|
|
|
# General Signals, used everywhere: |
|
82
|
|
|
sigIdleStateChanged = QtCore.Signal(bool) |
|
83
|
|
|
sigPosChanged = QtCore.Signal(dict) |
|
84
|
|
|
sigVelChanged = QtCore.Signal(dict) |
|
85
|
|
|
|
|
86
|
|
|
sigMeasurementStarted = QtCore.Signal() |
|
87
|
|
|
sigMeasurementContinued = QtCore.Signal() |
|
88
|
|
|
sigMeasurementStopped = QtCore.Signal() |
|
89
|
|
|
sigMeasurementFinished = QtCore.Signal() |
|
90
|
|
|
|
|
91
|
|
|
# Signals for making the move_abs, move_rel and abort independent: |
|
92
|
|
|
sigMoveAbs = QtCore.Signal(dict) |
|
93
|
|
|
sigMoveRel = QtCore.Signal(dict) |
|
94
|
|
|
sigAbort = QtCore.Signal() |
|
95
|
|
|
|
|
96
|
|
|
# Alignment Signals, remember do not touch or connect from outer logic or |
|
97
|
|
|
# GUI to the leading underscore signals! |
|
98
|
|
|
_sigStepwiseAlignmentNext = QtCore.Signal() |
|
99
|
|
|
_sigContinuousAlignmentNext = QtCore.Signal() |
|
100
|
|
|
_sigInitializeMeasPos = QtCore.Signal(bool) # signal to go to the initial measurement position |
|
101
|
|
|
sigPosReached = QtCore.Signal() |
|
102
|
|
|
|
|
103
|
|
|
# signals if new data are writen to the data arrays (during measurement): |
|
104
|
|
|
sig1DMatrixChanged = QtCore.Signal() |
|
105
|
|
|
sig2DMatrixChanged = QtCore.Signal() |
|
106
|
|
|
sig3DMatrixChanged = QtCore.Signal() |
|
107
|
|
|
|
|
108
|
|
|
# signals if the axis for the alignment are changed/renewed (before a measurement): |
|
109
|
|
|
sig1DAxisChanged = QtCore.Signal() |
|
110
|
|
|
sig2DAxisChanged = QtCore.Signal() |
|
111
|
|
|
sig3DAxisChanged = QtCore.Signal() |
|
112
|
|
|
|
|
113
|
|
|
# signal for ODMR alignment |
|
114
|
|
|
sigODMRLowFreqChanged = QtCore.Signal() |
|
115
|
|
|
sigODMRHighFreqChanged = QtCore.Signal() |
|
116
|
|
|
|
|
117
|
|
|
sigTest = QtCore.Signal() |
|
118
|
|
|
|
|
119
|
|
|
def __init__(self, config, **kwargs): |
|
120
|
|
|
super().__init__(config=config, **kwargs) |
|
121
|
|
|
|
|
122
|
|
|
self._stop_measure = False |
|
123
|
|
|
|
|
124
|
|
|
def on_activate(self, e): |
|
125
|
|
|
""" Definition and initialisation of the GUI. |
|
126
|
|
|
|
|
127
|
|
|
@param object e: Fysom.event object from Fysom class. |
|
128
|
|
|
An object created by the state machine module Fysom, |
|
129
|
|
|
which is connected to a specific event (have a look in |
|
130
|
|
|
the Base Class). This object contains the passed event, |
|
131
|
|
|
the state before the event happened and the destination |
|
132
|
|
|
of the state which should be reached after the event |
|
133
|
|
|
had happened. |
|
134
|
|
|
""" |
|
135
|
|
|
self._magnet_device = self.get_in_connector('magnetstage') |
|
136
|
|
|
self._save_logic = self.get_in_connector('savelogic') |
|
137
|
|
|
|
|
138
|
|
|
self.log.info('The following configuration was found.') |
|
139
|
|
|
# checking for the right configuration |
|
140
|
|
|
config = self.getConfiguration() |
|
141
|
|
|
for key in config.keys(): |
|
142
|
|
|
self.log.info('{0}: {1}'.format(key,config[key])) |
|
143
|
|
|
|
|
144
|
|
|
#FIXME: THAT IS JUST A TEMPORARY SOLUTION! Implement the access on the |
|
145
|
|
|
# needed methods via the TaskRunner! |
|
146
|
|
|
self._optimizer_logic = self.get_in_connector('optimizerlogic') |
|
147
|
|
|
self._confocal_logic = self.get_in_connector('scannerlogic') |
|
148
|
|
|
self._counter_logic = self.get_in_connector('counterlogic') |
|
149
|
|
|
self._odmr_logic = self.get_in_connector('odmrlogic') |
|
150
|
|
|
|
|
151
|
|
|
self._gc_logic = self.get_in_connector('gatedcounterlogic') |
|
152
|
|
|
self._ta_logic = self.get_in_connector('traceanalysis') |
|
153
|
|
|
self._odmr_logic = self.get_in_connector('odmrlogic') |
|
154
|
|
|
|
|
155
|
|
|
self._seq_gen_logic = self.get_in_connector('sequencegeneratorlogic') |
|
156
|
|
|
|
|
157
|
|
|
# EXPERIMENTAL: |
|
158
|
|
|
# connect now directly signals to the interface methods, so that |
|
159
|
|
|
# the logic object will be not blocks and can react on changes or abort |
|
160
|
|
|
self.sigMoveAbs.connect(self._magnet_device.move_abs) |
|
161
|
|
|
self.sigMoveRel.connect(self._magnet_device.move_rel) |
|
162
|
|
|
self.sigAbort.connect(self._magnet_device.abort) |
|
163
|
|
|
|
|
164
|
|
|
# signal connect for alignment: |
|
165
|
|
|
|
|
166
|
|
|
self._sigInitializeMeasPos.connect(self._move_to_curr_pathway_index) |
|
167
|
|
|
self._sigStepwiseAlignmentNext.connect(self._stepwise_loop_body, |
|
168
|
|
|
QtCore.Qt.QueuedConnection) |
|
169
|
|
|
|
|
170
|
|
|
self.pathway_modes = ['spiral-in', 'spiral-out', 'snake-wise', 'diagonal-snake-wise'] |
|
171
|
|
|
|
|
172
|
|
|
if 'curr_2d_pathway_mode' in self._statusVariables: |
|
173
|
|
|
self.curr_2d_pathway_mode = self._statusVariables['curr_2d_pathway_mode'] |
|
174
|
|
|
else: |
|
175
|
|
|
self.curr_2d_pathway_mode = 'snake-wise' # choose that as default |
|
176
|
|
|
|
|
177
|
|
|
if '_checktime' in self._statusVariables: |
|
178
|
|
|
self._checktime = self._statusVariables['_checktime'] |
|
179
|
|
|
else: |
|
180
|
|
|
self._checktime = 2.5 # in seconds |
|
181
|
|
|
|
|
182
|
|
|
self.sigTest.connect(self._do_premeasurement_proc) |
|
183
|
|
|
|
|
184
|
|
|
if '_1D_axis0_data' in self._statusVariables: |
|
185
|
|
|
self._1D_axis0_data = self._statusVariables['_1D_axis0_data'] |
|
186
|
|
|
else: |
|
187
|
|
|
self._1D_axis0_data = np.zeros(2) |
|
188
|
|
|
|
|
189
|
|
|
if '_2D_axis0_data' in self._statusVariables: |
|
190
|
|
|
self._2D_axis0_data = self._statusVariables['_2D_axis0_data'] |
|
191
|
|
|
else: |
|
192
|
|
|
self._2D_axis0_data = np.zeros(2) |
|
193
|
|
|
|
|
194
|
|
|
if '_2D_axis1_data' in self._statusVariables: |
|
195
|
|
|
self._2D_axis1_data = self._statusVariables['_2D_axis1_data'] |
|
196
|
|
|
else: |
|
197
|
|
|
self._2D_axis1_data = np.zeros(2) |
|
198
|
|
|
|
|
199
|
|
|
if '_3D_axis0_data' in self._statusVariables: |
|
200
|
|
|
self._3D_axis0_data = self._statusVariables['_3D_axis0_data'] |
|
201
|
|
|
else: |
|
202
|
|
|
self._3D_axis0_data = np.zeros(2) |
|
203
|
|
|
|
|
204
|
|
|
if '_3D_axis1_data' in self._statusVariables: |
|
205
|
|
|
self._3D_axis1_data = self._statusVariables['_3D_axis1_data'] |
|
206
|
|
|
else: |
|
207
|
|
|
self._3D_axis1_data = np.zeros(2) |
|
208
|
|
|
|
|
209
|
|
|
if '_3D_axis2_data' in self._statusVariables: |
|
210
|
|
|
self._3D_axis2_data = self._statusVariables['_3D_axis2_data'] |
|
211
|
|
|
else: |
|
212
|
|
|
self._3D_axis2_data = np.zeros(2) |
|
213
|
|
|
|
|
214
|
|
|
if '_1D_add_data_matrix' in self._statusVariables: |
|
215
|
|
|
self._1D_add_data_matrix = self._statusVariables['_1D_add_data_matrix'] |
|
216
|
|
|
else: |
|
217
|
|
|
self._1D_add_data_matrix = np.zeros(shape=np.shape(self._1D_axis0_data), dtype=object) |
|
218
|
|
|
|
|
219
|
|
|
|
|
220
|
|
|
if '_2D_data_matrix' in self._statusVariables: |
|
221
|
|
|
self._2D_data_matrix = self._statusVariables['_2D_data_matrix'] |
|
222
|
|
|
else: |
|
223
|
|
|
self._2D_data_matrix = np.zeros((2, 2)) |
|
224
|
|
|
|
|
225
|
|
|
if '_2D_add_data_matrix' in self._statusVariables: |
|
226
|
|
|
self._2D_add_data_matrix = self._statusVariables['_2D_add_data_matrix'] |
|
227
|
|
|
else: |
|
228
|
|
|
self._2D_add_data_matrix = np.zeros(shape=np.shape(self._2D_data_matrix), dtype=object) |
|
229
|
|
|
|
|
230
|
|
|
if '_3D_data_matrix' in self._statusVariables: |
|
231
|
|
|
self._3D_data_matrix = self._statusVariables['_3D_data_matrix'] |
|
232
|
|
|
else: |
|
233
|
|
|
self._3D_data_matrix = np.zeros((2, 2, 2)) |
|
234
|
|
|
|
|
235
|
|
|
if '_3D_add_data_matrix' in self._statusVariables: |
|
236
|
|
|
self._3D_add_data_matrix = self._statusVariables['_3D_add_data_matrix'] |
|
237
|
|
|
else: |
|
238
|
|
|
self._3D_add_data_matrix = np.zeros(shape=np.shape(self._3D_data_matrix), dtype=object) |
|
239
|
|
|
|
|
240
|
|
|
if 'curr_alignment_method' in self._statusVariables: |
|
241
|
|
|
self.curr_alignment_method = self._statusVariables['curr_alignment_method'] |
|
242
|
|
|
else: |
|
243
|
|
|
self.curr_alignment_method = '2d_fluorescence' |
|
244
|
|
|
|
|
245
|
|
|
self.alignment_methods = ['2d_fluorescence', '2d_odmr', '2d_nuclear'] |
|
246
|
|
|
|
|
247
|
|
|
# Fluorescence alignment settings: |
|
248
|
|
|
if '_optimize_pos' in self._statusVariables: |
|
249
|
|
|
self._optimize_pos = self._statusVariables['_optimize_pos'] |
|
250
|
|
|
else: |
|
251
|
|
|
self._optimize_pos = False |
|
252
|
|
|
|
|
253
|
|
|
if 'fluorescence_integration_time' in self._statusVariables: |
|
254
|
|
|
self.fluorescence_integration_time = self._statusVariables['fluorescence_integration_time'] |
|
255
|
|
|
else: |
|
256
|
|
|
self.fluorescence_integration_time = 5 # integration time in s |
|
257
|
|
|
|
|
258
|
|
|
# ODMR alignment settings (ALL IN SI!!!): |
|
259
|
|
|
|
|
260
|
|
|
if 'odmr_2d_low_center_freq' in self._statusVariables: |
|
261
|
|
|
self.odmr_2d_low_center_freq = self._statusVariables['odmr_2d_low_center_freq'] |
|
262
|
|
|
else: |
|
263
|
|
|
self.odmr_2d_low_center_freq = 11028e6 |
|
264
|
|
|
|
|
265
|
|
|
if 'odmr_2d_low_step_freq' in self._statusVariables: |
|
266
|
|
|
self.odmr_2d_low_step_freq = self._statusVariables['odmr_2d_low_step_freq'] |
|
267
|
|
|
else: |
|
268
|
|
|
self.odmr_2d_low_step_freq = 0.15e6 |
|
269
|
|
|
|
|
270
|
|
|
if 'odmr_2d_low_range_freq' in self._statusVariables: |
|
271
|
|
|
self.odmr_2d_low_range_freq = self._statusVariables['odmr_2d_low_range_freq'] |
|
272
|
|
|
else: |
|
273
|
|
|
self.odmr_2d_low_range_freq = 25e6 |
|
274
|
|
|
|
|
275
|
|
|
if 'odmr_2d_low_power' in self._statusVariables: |
|
276
|
|
|
self.odmr_2d_low_power = self._statusVariables['odmr_2d_low_power'] |
|
277
|
|
|
else: |
|
278
|
|
|
self.odmr_2d_low_power = 4 |
|
279
|
|
|
|
|
280
|
|
|
if 'odmr_2d_low_runtime' in self._statusVariables: |
|
281
|
|
|
self.odmr_2d_low_runtime = self._statusVariables['odmr_2d_low_runtime'] |
|
282
|
|
|
else: |
|
283
|
|
|
self.odmr_2d_low_runtime = 40 |
|
284
|
|
|
|
|
285
|
|
|
self.odmr_2d_low_fitfunction_list = self._odmr_logic.get_fit_functions() |
|
286
|
|
|
|
|
287
|
|
|
if 'odmr_2d_low_fitfunction' in self._statusVariables: |
|
288
|
|
|
self.odmr_2d_low_fitfunction = self._statusVariables['odmr_2d_low_fitfunction'] |
|
289
|
|
|
else: |
|
290
|
|
|
self.odmr_2d_low_fitfunction = self.odmr_2d_low_fitfunction_list[1] |
|
291
|
|
|
|
|
292
|
|
|
|
|
293
|
|
|
|
|
294
|
|
|
if 'odmr_2d_high_center_freq' in self._statusVariables: |
|
295
|
|
|
self.odmr_2d_high_center_freq = self._statusVariables['odmr_2d_high_center_freq'] |
|
296
|
|
|
else: |
|
297
|
|
|
self.odmr_2d_high_center_freq = 16768e6 |
|
298
|
|
|
|
|
299
|
|
|
if 'odmr_2d_high_step_freq' in self._statusVariables: |
|
300
|
|
|
self.odmr_2d_high_step_freq = self._statusVariables['odmr_2d_high_step_freq'] |
|
301
|
|
|
else: |
|
302
|
|
|
self.odmr_2d_high_step_freq = 0.15e6 |
|
303
|
|
|
|
|
304
|
|
|
if 'odmr_2d_high_range_freq' in self._statusVariables: |
|
305
|
|
|
self.odmr_2d_high_range_freq = self._statusVariables['odmr_2d_high_range_freq'] |
|
306
|
|
|
else: |
|
307
|
|
|
self.odmr_2d_high_range_freq = 25e6 |
|
308
|
|
|
|
|
309
|
|
|
if 'odmr_2d_high_power' in self._statusVariables: |
|
310
|
|
|
self.odmr_2d_high_power = self._statusVariables['odmr_2d_high_power'] |
|
311
|
|
|
else: |
|
312
|
|
|
self.odmr_2d_high_power = 2 |
|
313
|
|
|
|
|
314
|
|
|
if 'odmr_2d_high_runtime' in self._statusVariables: |
|
315
|
|
|
self.odmr_2d_high_runtime = self._statusVariables['odmr_2d_high_runtime'] |
|
316
|
|
|
else: |
|
317
|
|
|
self.odmr_2d_high_runtime = 40 |
|
318
|
|
|
|
|
319
|
|
|
self.odmr_2d_high_fitfunction_list = self._odmr_logic.get_fit_functions() |
|
320
|
|
|
|
|
321
|
|
|
if 'odmr_2d_high_fitfunction' in self._statusVariables: |
|
322
|
|
|
self.odmr_2d_high_fitfunction = self._statusVariables['odmr_2d_high_fitfunction'] |
|
323
|
|
|
else: |
|
324
|
|
|
self.odmr_2d_high_fitfunction = self.odmr_2d_high_fitfunction_list[1] |
|
325
|
|
|
|
|
326
|
|
|
if 'odmr_2d_save_after_measure' in self._statusVariables: |
|
327
|
|
|
self.odmr_2d_save_after_measure = self._statusVariables['odmr_2d_save_after_measure'] |
|
328
|
|
|
else: |
|
329
|
|
|
self.odmr_2d_save_after_measure = True |
|
330
|
|
|
|
|
331
|
|
|
if 'odmr_2d_peak_axis0_move_ratio' in self._statusVariables: |
|
332
|
|
|
self.odmr_2d_peak_axis0_move_ratio = self._statusVariables['odmr_2d_peak_axis0_move_ratio'] |
|
333
|
|
|
else: |
|
334
|
|
|
self.odmr_2d_peak_axis0_move_ratio = 0 # -13e6/ 0.01e-3 # in Hz/m |
|
335
|
|
|
|
|
336
|
|
|
if 'odmr_2d_peak_axis1_move_ratio' in self._statusVariables: |
|
337
|
|
|
self.odmr_2d_peak_axis1_move_ratio = self._statusVariables['odmr_2d_peak_axis1_move_ratio'] |
|
338
|
|
|
else: |
|
339
|
|
|
self.odmr_2d_peak_axis1_move_ratio = 0 # -6e6/0.05e-3 # in Hz/m |
|
340
|
|
|
|
|
341
|
|
|
# that is just a normalization value, which is needed for the ODMR |
|
342
|
|
|
# alignment, since the colorbar cannot display values greater (2**32)/2. |
|
343
|
|
|
# A solution has to found for that! |
|
344
|
|
|
self.norm = 1000 |
|
345
|
|
|
|
|
346
|
|
|
self.odmr_2d_single_trans = False # use that if only one ODMR |
|
347
|
|
|
# transition is available. |
|
348
|
|
|
|
|
349
|
|
|
# single shot alignment on nuclear spin settings (ALL IN SI!!!): |
|
350
|
|
|
if 'nuclear_2d_rabi_periode' in self._statusVariables: |
|
351
|
|
|
self.nuclear_2d_rabi_periode = self._statusVariables['nuclear_2d_rabi_periode'] |
|
352
|
|
|
else: |
|
353
|
|
|
self.nuclear_2d_rabi_periode = 1000e-9 |
|
354
|
|
|
|
|
355
|
|
|
if 'nuclear_2d_mw_freq' in self._statusVariables: |
|
356
|
|
|
self.nuclear_2d_mw_freq = self._statusVariables['nuclear_2d_mw_freq'] |
|
357
|
|
|
else: |
|
358
|
|
|
self.nuclear_2d_mw_freq = 100e6 |
|
359
|
|
|
|
|
360
|
|
|
if 'nuclear_2d_mw_channel' in self._statusVariables: |
|
361
|
|
|
self.nuclear_2d_mw_channel = self._statusVariables['nuclear_2d_mw_channel'] |
|
362
|
|
|
else: |
|
363
|
|
|
self.nuclear_2d_mw_channel = -1 |
|
364
|
|
|
|
|
365
|
|
|
if 'nuclear_2d_mw_power' in self._statusVariables: |
|
366
|
|
|
self.nuclear_2d_mw_power = self._statusVariables['nuclear_2d_mw_power'] |
|
367
|
|
|
else: |
|
368
|
|
|
self.nuclear_2d_mw_power = -30 |
|
369
|
|
|
|
|
370
|
|
|
if 'nuclear_2d_laser_time' in self._statusVariables: |
|
371
|
|
|
self.nuclear_2d_laser_time = self._statusVariables['nuclear_2d_laser_time'] |
|
372
|
|
|
else: |
|
373
|
|
|
self.nuclear_2d_laser_time = 900e-9 |
|
374
|
|
|
|
|
375
|
|
|
if 'nuclear_2d_laser_channel' in self._statusVariables: |
|
376
|
|
|
self.nuclear_2d_laser_channel = self._statusVariables['nuclear_2d_laser_channel'] |
|
377
|
|
|
else: |
|
378
|
|
|
self.nuclear_2d_laser_channel = 2 |
|
379
|
|
|
|
|
380
|
|
|
if 'nuclear_2d_detect_channel' in self._statusVariables: |
|
381
|
|
|
self.nuclear_2d_detect_channel = self._statusVariables['nuclear_2d_detect_channel'] |
|
382
|
|
|
else: |
|
383
|
|
|
self.nuclear_2d_detect_channel = 1 |
|
384
|
|
|
|
|
385
|
|
|
if 'nuclear_2d_idle_time' in self._statusVariables: |
|
386
|
|
|
self.nuclear_2d_idle_time = self._statusVariables['nuclear_2d_idle_time'] |
|
387
|
|
|
else: |
|
388
|
|
|
self.nuclear_2d_idle_time = 1500e-9 |
|
389
|
|
|
|
|
390
|
|
|
if 'nuclear_2d_reps_within_ssr' in self._statusVariables: |
|
391
|
|
|
self.nuclear_2d_reps_within_ssr = self._statusVariables['nuclear_2d_reps_within_ssr'] |
|
392
|
|
|
else: |
|
393
|
|
|
self.nuclear_2d_reps_within_ssr = 1000 |
|
394
|
|
|
|
|
395
|
|
|
if 'nuclear_2d_num_ssr' in self._statusVariables: |
|
396
|
|
|
self.nuclear_2d_num_ssr = self._statusVariables['nuclear_2d_num_ssr'] |
|
397
|
|
|
else: |
|
398
|
|
|
self.nuclear_2d_num_ssr = 3000 |
|
399
|
|
|
|
|
400
|
|
|
|
|
401
|
|
|
def on_deactivate(self, e): |
|
402
|
|
|
""" Deactivate the module properly. |
|
403
|
|
|
|
|
404
|
|
|
@param object e: Fysom.event object from Fysom class. A more detailed |
|
405
|
|
|
explanation can be found in the method activation. |
|
406
|
|
|
""" |
|
407
|
|
|
self._statusVariables['optimize_pos'] = self._optimize_pos |
|
408
|
|
|
self._statusVariables['fluorescence_integration_time'] = self.fluorescence_integration_time |
|
409
|
|
|
|
|
410
|
|
|
self._statusVariables['odmr_2d_low_center_freq'] = self.odmr_2d_low_center_freq |
|
411
|
|
|
self._statusVariables['odmr_2d_low_step_freq'] = self.odmr_2d_low_step_freq |
|
412
|
|
|
self._statusVariables['odmr_2d_low_range_freq'] = self.odmr_2d_low_range_freq |
|
413
|
|
|
self._statusVariables['odmr_2d_low_power'] = self.odmr_2d_low_power |
|
414
|
|
|
self._statusVariables['odmr_2d_low_runtime'] = self.odmr_2d_low_runtime |
|
415
|
|
|
self._statusVariables['odmr_2d_low_fitfunction'] = self.odmr_2d_low_fitfunction |
|
416
|
|
|
|
|
417
|
|
|
self._statusVariables['odmr_2d_high_center_freq'] = self.odmr_2d_high_center_freq |
|
418
|
|
|
self._statusVariables['odmr_2d_high_step_freq'] = self.odmr_2d_high_step_freq |
|
419
|
|
|
self._statusVariables['odmr_2d_high_range_freq'] = self.odmr_2d_high_range_freq |
|
420
|
|
|
self._statusVariables['odmr_2d_high_power'] = self.odmr_2d_high_power |
|
421
|
|
|
self._statusVariables['odmr_2d_high_runtime'] = self.odmr_2d_high_runtime |
|
422
|
|
|
self._statusVariables['odmr_2d_high_fitfunction'] = self.odmr_2d_high_fitfunction |
|
423
|
|
|
self._statusVariables['odmr_2d_save_after_measure'] = self.odmr_2d_save_after_measure |
|
424
|
|
|
self._statusVariables['odmr_2d_peak_axis0_move_ratio'] = self.odmr_2d_peak_axis0_move_ratio |
|
425
|
|
|
self._statusVariables['odmr_2d_peak_axis1_move_ratio'] = self.odmr_2d_peak_axis1_move_ratio |
|
426
|
|
|
|
|
427
|
|
|
self._statusVariables['nuclear_2d_rabi_periode'] = self.nuclear_2d_rabi_periode |
|
428
|
|
|
self._statusVariables['nuclear_2d_mw_freq'] = self.nuclear_2d_mw_freq |
|
429
|
|
|
self._statusVariables['nuclear_2d_mw_channel'] = self.nuclear_2d_mw_channel |
|
430
|
|
|
self._statusVariables['nuclear_2d_mw_power'] = self.nuclear_2d_mw_power |
|
431
|
|
|
self._statusVariables['nuclear_2d_laser_time'] = self.nuclear_2d_laser_time |
|
432
|
|
|
self._statusVariables['nuclear_2d_laser_channel'] = self.nuclear_2d_laser_channel |
|
433
|
|
|
self._statusVariables['nuclear_2d_detect_channel'] = self.nuclear_2d_detect_channel |
|
434
|
|
|
self._statusVariables['nuclear_2d_idle_time'] = self.nuclear_2d_idle_time |
|
435
|
|
|
self._statusVariables['nuclear_2d_reps_within_ssr'] = self.nuclear_2d_reps_within_ssr |
|
436
|
|
|
self._statusVariables['nuclear_2d_num_ssr'] = self.nuclear_2d_num_ssr |
|
437
|
|
|
|
|
438
|
|
|
def get_hardware_constraints(self): |
|
439
|
|
|
""" Retrieve the hardware constraints. |
|
440
|
|
|
|
|
441
|
|
|
@return dict: dict with constraints for the magnet hardware. The keys |
|
442
|
|
|
are the labels for the axis and the items are again dicts |
|
443
|
|
|
which contain all the limiting parameters. |
|
444
|
|
|
""" |
|
445
|
|
|
|
|
446
|
|
|
return self._magnet_device.get_constraints() |
|
447
|
|
|
|
|
448
|
|
|
def move_rel(self, param_dict): |
|
449
|
|
|
""" Move the specified axis in the param_dict relative with an assigned |
|
450
|
|
|
value. |
|
451
|
|
|
|
|
452
|
|
|
@param dict param_dict: dictionary, which passes all the relevant |
|
453
|
|
|
parameters. E.g., for a movement of an axis |
|
454
|
|
|
labeled with 'x' by 23 the dict should have the |
|
455
|
|
|
form: |
|
456
|
|
|
param_dict = { 'x' : 23 } |
|
457
|
|
|
""" |
|
458
|
|
|
|
|
459
|
|
|
# self._magnet_device.move_rel(param_dict) |
|
460
|
|
|
# start_pos = self.get_pos(list(param_dict)) |
|
461
|
|
|
# end_pos = dict() |
|
462
|
|
|
# |
|
463
|
|
|
# for axis_name in param_dict: |
|
464
|
|
|
# end_pos[axis_name] = start_pos[axis_name] + param_dict[axis_name] |
|
465
|
|
|
|
|
466
|
|
|
# if the magnet is moving, then the move_rel command will be neglected. |
|
467
|
|
|
status_dict = self.get_status(list(param_dict)) |
|
468
|
|
|
for axis_name in status_dict: |
|
469
|
|
|
if status_dict[axis_name][0] != 0: |
|
470
|
|
|
return |
|
471
|
|
|
|
|
472
|
|
|
self.sigMoveRel.emit(param_dict) |
|
473
|
|
|
# self._check_position_reached_loop(start_pos, end_pos) |
|
474
|
|
|
self.sigPosChanged.emit(param_dict) |
|
475
|
|
|
|
|
476
|
|
|
|
|
477
|
|
|
def get_pos(self, param_list=None): |
|
478
|
|
|
""" Gets current position of the stage. |
|
479
|
|
|
|
|
480
|
|
|
@param list param_list: optional, if a specific position of an axis |
|
481
|
|
|
is desired, then the labels of the needed |
|
482
|
|
|
axis should be passed as the param_list. |
|
483
|
|
|
If nothing is passed, then from each axis the |
|
484
|
|
|
position is asked. |
|
485
|
|
|
|
|
486
|
|
|
@return dict: with keys being the axis labels and item the current |
|
487
|
|
|
position. |
|
488
|
|
|
""" |
|
489
|
|
|
|
|
490
|
|
|
pos_dict = self._magnet_device.get_pos(param_list) |
|
491
|
|
|
return pos_dict |
|
492
|
|
|
|
|
493
|
|
|
def get_status(self, param_list=None): |
|
494
|
|
|
""" Get the status of the position |
|
495
|
|
|
|
|
496
|
|
|
@param list param_list: optional, if a specific status of an axis |
|
497
|
|
|
is desired, then the labels of the needed |
|
498
|
|
|
axis should be passed in the param_list. |
|
499
|
|
|
If nothing is passed, then from each axis the |
|
500
|
|
|
status is asked. |
|
501
|
|
|
|
|
502
|
|
|
@return dict: with the axis label as key and a tuple of a status |
|
503
|
|
|
number and a status dict as the item. |
|
504
|
|
|
""" |
|
505
|
|
|
status = self._magnet_device.get_status(param_list) |
|
506
|
|
|
return status |
|
507
|
|
|
|
|
508
|
|
|
def move_abs(self, param_dict): |
|
509
|
|
|
""" Moves stage to absolute position (absolute movement) |
|
510
|
|
|
|
|
511
|
|
|
@param dict param_dict: dictionary, which passes all the relevant |
|
512
|
|
|
parameters, which should be changed. Usage: |
|
513
|
|
|
{'axis_label': <a-value>}. |
|
514
|
|
|
'axis_label' must correspond to a label given |
|
515
|
|
|
to one of the axis. |
|
516
|
|
|
""" |
|
517
|
|
|
# self._magnet_device.move_abs(param_dict) |
|
518
|
|
|
start_pos = self.get_pos(list(param_dict)) |
|
519
|
|
|
self.sigMoveAbs.emit(param_dict) |
|
520
|
|
|
|
|
521
|
|
|
# self._check_position_reached_loop(start_pos, param_dict) |
|
522
|
|
|
|
|
523
|
|
|
self.sigPosChanged.emit(param_dict) |
|
524
|
|
|
|
|
525
|
|
|
def stop_movement(self): |
|
526
|
|
|
""" Stops movement of the stage. """ |
|
527
|
|
|
self._stop_measure = True |
|
528
|
|
|
self.sigAbort.emit() |
|
529
|
|
|
# self._magnet_device.abort() |
|
530
|
|
|
|
|
531
|
|
|
|
|
532
|
|
|
def set_velocity(self, param_dict=None): |
|
533
|
|
|
""" Write new value for velocity. |
|
534
|
|
|
|
|
535
|
|
|
@param dict param_dict: dictionary, which passes all the relevant |
|
536
|
|
|
parameters, which should be changed. Usage: |
|
537
|
|
|
{'axis_label': <the-velocity-value>}. |
|
538
|
|
|
'axis_label' must correspond to a label given |
|
539
|
|
|
to one of the axis. |
|
540
|
|
|
""" |
|
541
|
|
|
self._magnet_device.set_velocity(param_dict) |
|
542
|
|
|
|
|
543
|
|
|
|
|
544
|
|
|
|
|
545
|
|
|
def _create_1d_pathway(self, axis_name, axis_range, axis_step, axis_vel): |
|
546
|
|
|
""" Create a path along with the magnet should move with one axis |
|
547
|
|
|
|
|
548
|
|
|
@param str axis_name: |
|
549
|
|
|
@param float axis_range: |
|
550
|
|
|
@param float axis_step: |
|
551
|
|
|
|
|
552
|
|
|
@return: |
|
553
|
|
|
|
|
554
|
|
|
Here you can also create fancy 1D pathways, not only linear but also |
|
555
|
|
|
in any kind on nonlinear fashion. |
|
556
|
|
|
""" |
|
557
|
|
|
pass |
|
558
|
|
|
|
|
559
|
|
|
def _create_2d_pathway(self, axis0_name, axis0_range, axis0_step, |
|
560
|
|
|
axis1_name, axis1_range, axis1_step, init_pos, |
|
561
|
|
|
axis0_vel=None, axis1_vel=None): |
|
562
|
|
|
""" Create a path along with the magnet should move. |
|
563
|
|
|
|
|
564
|
|
|
@param str axis0_name: |
|
565
|
|
|
@param float axis0_range: |
|
566
|
|
|
@param float axis0_step: |
|
567
|
|
|
@param str axis1_name: |
|
568
|
|
|
@param float axis1_range: |
|
569
|
|
|
@param float axis1_step: |
|
570
|
|
|
|
|
571
|
|
|
@return array: 1D np.array, which has dictionary as entries. In this |
|
572
|
|
|
dictionary, it will be specified, how the magnet is going |
|
573
|
|
|
from the present point to the next. |
|
574
|
|
|
|
|
575
|
|
|
That should be quite a general function, which maps from a given matrix |
|
576
|
|
|
and axes information a 2D array into a 1D path with steps being the |
|
577
|
|
|
relative movements. |
|
578
|
|
|
|
|
579
|
|
|
All kind of standard and fancy pathways through the array should be |
|
580
|
|
|
implemented here! |
|
581
|
|
|
The movement is not restricted to relative movements! |
|
582
|
|
|
The entry dicts have the following structure: |
|
583
|
|
|
|
|
584
|
|
|
pathway = [ dict1, dict2, dict3, ...] |
|
585
|
|
|
|
|
586
|
|
|
whereas the dictionary can only have one or two key entries: |
|
587
|
|
|
dict1[axis0_name] = {'move_rel': 123, 'move_vel': 3 } |
|
588
|
|
|
dict1[axis1_name] = {'move_abs': 29.5} |
|
589
|
|
|
|
|
590
|
|
|
Note that the entries may either have a relative OR an absolute movement! |
|
591
|
|
|
Never both! Absolute movement will be taken always before relative |
|
592
|
|
|
movement. Moreover you can specify in each movement step the velocity |
|
593
|
|
|
and the acceleration of the movement. |
|
594
|
|
|
E.g. if no velocity is specified, then nothing will be changed in terms |
|
595
|
|
|
of speed during the move. |
|
596
|
|
|
""" |
|
597
|
|
|
|
|
598
|
|
|
# calculate number of steps (those are NOT the number of points!) |
|
599
|
|
|
axis0_num_of_steps = int(axis0_range//axis0_step) |
|
600
|
|
|
axis1_num_of_steps = int(axis1_range//axis1_step) |
|
601
|
|
|
|
|
602
|
|
|
# make an array of movement steps |
|
603
|
|
|
axis0_steparray = [axis0_step] * axis0_num_of_steps |
|
604
|
|
|
axis1_steparray = [axis1_step] * axis1_num_of_steps |
|
605
|
|
|
|
|
606
|
|
|
pathway = [] |
|
607
|
|
|
|
|
608
|
|
|
#FIXME: create these path modes: |
|
609
|
|
|
if self.curr_2d_pathway_mode == 'spiral-in': |
|
610
|
|
|
self.log.error('The pathway creation method "{0}" through the ' |
|
611
|
|
|
'matrix is not implemented yet!\nReturn an empty ' |
|
612
|
|
|
'patharray.'.format(self.curr_2d_pathway_mode)) |
|
613
|
|
|
return [], [] |
|
614
|
|
|
|
|
615
|
|
|
elif self.curr_2d_pathway_mode == 'spiral-out': |
|
616
|
|
|
self.log.error('The pathway creation method "{0}" through the ' |
|
617
|
|
|
'matrix is not implemented yet!\nReturn an empty ' |
|
618
|
|
|
'patharray.'.format(self.curr_2d_pathway_mode)) |
|
619
|
|
|
return [], [] |
|
620
|
|
|
|
|
621
|
|
|
elif self.curr_2d_pathway_mode == 'diagonal-snake-wise': |
|
622
|
|
|
self.log.error('The pathway creation method "{0}" through the ' |
|
623
|
|
|
'matrix is not implemented yet!\nReturn an empty ' |
|
624
|
|
|
'patharray.'.format(self.current_2d_pathway_mode)) |
|
625
|
|
|
return [], [] |
|
626
|
|
|
|
|
627
|
|
|
elif self.curr_2d_pathway_mode == 'selected-points': |
|
628
|
|
|
self.log.error('The pathway creation method "{0}" through the ' |
|
629
|
|
|
'matrix is not implemented yet!\nReturn an empty ' |
|
630
|
|
|
'patharray.'.format(self.current_2d_pathway_mode)) |
|
631
|
|
|
return [], [] |
|
632
|
|
|
|
|
633
|
|
|
# choose the snake-wise as default for now. |
|
634
|
|
|
else: |
|
635
|
|
|
|
|
636
|
|
|
# create a snake-wise stepping procedure through the matrix: |
|
637
|
|
|
axis0_pos = round(init_pos[axis0_name] - axis0_range/2, 7) |
|
638
|
|
|
axis1_pos = round(init_pos[axis1_name] - axis1_range/2, 7) |
|
639
|
|
|
|
|
640
|
|
|
# append again so that the for loop later will run once again |
|
641
|
|
|
# through the axis0 array but the last value of axis1_steparray will |
|
642
|
|
|
# not be performed. |
|
643
|
|
|
axis1_steparray.append(axis1_num_of_steps) |
|
644
|
|
|
|
|
645
|
|
|
# step_config is the dict containing the commands for one pathway |
|
646
|
|
|
# entry. Move at first to start position: |
|
647
|
|
|
step_config = dict() |
|
648
|
|
|
|
|
649
|
|
|
if axis0_vel is None: |
|
650
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos} |
|
651
|
|
|
else: |
|
652
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos, 'move_vel': axis0_vel} |
|
653
|
|
|
|
|
654
|
|
|
if axis1_vel is None: |
|
655
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos} |
|
656
|
|
|
else: |
|
657
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos, 'move_vel': axis1_vel} |
|
658
|
|
|
|
|
659
|
|
|
pathway.append(step_config) |
|
660
|
|
|
|
|
661
|
|
|
path_index = 0 |
|
662
|
|
|
|
|
663
|
|
|
# these indices should be used to facilitate the mapping to a 2D |
|
664
|
|
|
# array, since the |
|
665
|
|
|
axis0_index = 0 |
|
666
|
|
|
axis1_index = 0 |
|
667
|
|
|
|
|
668
|
|
|
# that is a map to transform a pathway index value back to an |
|
669
|
|
|
# absolute position and index. That will be important for saving the |
|
670
|
|
|
# data corresponding to a certain path_index value. |
|
671
|
|
|
back_map = dict() |
|
672
|
|
|
back_map[path_index] = {axis0_name: axis0_pos, |
|
673
|
|
|
axis1_name: axis1_pos, |
|
674
|
|
|
'index': (axis0_index, axis1_index)} |
|
675
|
|
|
|
|
676
|
|
|
path_index += 1 |
|
677
|
|
|
# axis0_index += 1 |
|
678
|
|
|
|
|
679
|
|
|
go_pos_dir = True |
|
680
|
|
|
for step_in_axis1 in axis1_steparray: |
|
681
|
|
|
|
|
682
|
|
|
if go_pos_dir: |
|
683
|
|
|
go_pos_dir = False |
|
684
|
|
|
direction = +1 |
|
685
|
|
|
else: |
|
686
|
|
|
go_pos_dir = True |
|
687
|
|
|
direction = -1 |
|
688
|
|
|
|
|
689
|
|
|
for step_in_axis0 in axis0_steparray: |
|
690
|
|
|
|
|
691
|
|
|
axis0_index += direction |
|
692
|
|
|
# make move along axis0: |
|
693
|
|
|
step_config = dict() |
|
694
|
|
|
|
|
695
|
|
|
# relative movement: |
|
696
|
|
|
# step_config[axis0_name] = {'move_rel': direction*step_in_axis0} |
|
697
|
|
|
|
|
698
|
|
|
# absolute movement: |
|
699
|
|
|
axis0_pos =round(axis0_pos + direction*step_in_axis0, 7) |
|
700
|
|
|
|
|
701
|
|
|
# if axis0_vel is None: |
|
702
|
|
|
# step_config[axis0_name] = {'move_abs': axis0_pos} |
|
703
|
|
|
# step_config[axis1_name] = {'move_abs': axis1_pos} |
|
704
|
|
|
# else: |
|
705
|
|
|
# step_config[axis0_name] = {'move_abs': axis0_pos, |
|
706
|
|
|
# 'move_vel': axis0_vel} |
|
707
|
|
View Code Duplication |
if axis1_vel is None and axis0_vel is None: |
|
|
|
|
|
|
708
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos} |
|
709
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos} |
|
710
|
|
|
else: |
|
711
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos} |
|
712
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos} |
|
713
|
|
|
|
|
714
|
|
|
if axis0_vel is not None: |
|
715
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos, 'move_vel': axis0_vel} |
|
716
|
|
|
|
|
717
|
|
|
if axis1_vel is not None: |
|
718
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos, 'move_vel': axis1_vel} |
|
719
|
|
|
|
|
720
|
|
|
# append to the pathway |
|
721
|
|
|
pathway.append(step_config) |
|
722
|
|
|
back_map[path_index] = {axis0_name: axis0_pos, |
|
723
|
|
|
axis1_name: axis1_pos, |
|
724
|
|
|
'index': (axis0_index, axis1_index)} |
|
725
|
|
|
path_index += 1 |
|
726
|
|
|
|
|
727
|
|
|
if (axis1_index+1) >= len(axis1_steparray): |
|
728
|
|
|
break |
|
729
|
|
|
|
|
730
|
|
|
# make a move along axis1: |
|
731
|
|
|
step_config = dict() |
|
732
|
|
|
|
|
733
|
|
|
# relative movement: |
|
734
|
|
|
# step_config[axis1_name] = {'move_rel' : step_in_axis1} |
|
735
|
|
|
|
|
736
|
|
|
# absolute movement: |
|
737
|
|
|
axis1_pos = round(axis1_pos + step_in_axis1, 7) |
|
738
|
|
|
|
|
739
|
|
View Code Duplication |
if axis1_vel is None and axis0_vel is None: |
|
|
|
|
|
|
740
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos} |
|
741
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos} |
|
742
|
|
|
else: |
|
743
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos} |
|
744
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos} |
|
745
|
|
|
|
|
746
|
|
|
if axis0_vel is not None: |
|
747
|
|
|
step_config[axis0_name] = {'move_abs': axis0_pos, 'move_vel': axis0_vel} |
|
748
|
|
|
|
|
749
|
|
|
if axis1_vel is not None: |
|
750
|
|
|
step_config[axis1_name] = {'move_abs': axis1_pos, 'move_vel': axis1_vel} |
|
751
|
|
|
|
|
752
|
|
|
pathway.append(step_config) |
|
753
|
|
|
axis1_index += 1 |
|
754
|
|
|
back_map[path_index] = {axis0_name: axis0_pos, |
|
755
|
|
|
axis1_name: axis1_pos, |
|
756
|
|
|
'index': (axis0_index, axis1_index)} |
|
757
|
|
|
path_index += 1 |
|
758
|
|
|
|
|
759
|
|
|
|
|
760
|
|
|
|
|
761
|
|
|
return pathway, back_map |
|
762
|
|
|
|
|
763
|
|
|
|
|
764
|
|
|
def _create_2d_cont_pathway(self, pathway): |
|
765
|
|
|
|
|
766
|
|
|
# go through the passed 1D path and reduce the whole movement just to |
|
767
|
|
|
# corner points |
|
768
|
|
|
|
|
769
|
|
|
pathway_cont = dict() |
|
770
|
|
|
|
|
771
|
|
|
return pathway_cont |
|
772
|
|
|
|
|
773
|
|
|
def _prepare_2d_graph(self, axis0_start, axis0_range, axis0_step, |
|
774
|
|
|
axis1_start, axis1_range, axis1_step): |
|
775
|
|
|
# set up a matrix where measurement points are save to |
|
776
|
|
|
# general method to prepare 2d images, and their axes. |
|
777
|
|
|
|
|
778
|
|
|
# that is for the matrix image. +1 because number of points and not |
|
779
|
|
|
# number of steps are needed: |
|
780
|
|
|
num_points_axis0 = (axis0_range//axis0_step) + 1 |
|
781
|
|
|
num_points_axis1 = (axis1_range//axis1_step) + 1 |
|
782
|
|
|
matrix = np.zeros((num_points_axis0, num_points_axis1)) |
|
783
|
|
|
|
|
784
|
|
|
# data axis0: |
|
785
|
|
|
|
|
786
|
|
|
data_axis0 = np.arange(axis0_start, axis0_start + ((axis0_range//axis0_step)+1)*axis0_step, axis0_step) |
|
787
|
|
|
|
|
788
|
|
|
# data axis1: |
|
789
|
|
|
data_axis1 = np.arange(axis1_start, axis1_start + ((axis1_range//axis1_step)+1)*axis1_step, axis1_step) |
|
790
|
|
|
|
|
791
|
|
|
return matrix, data_axis0, data_axis1 |
|
792
|
|
|
|
|
793
|
|
|
|
|
794
|
|
|
|
|
795
|
|
|
|
|
796
|
|
|
def _prepare_1d_graph(self, axis_range, axis_step): |
|
797
|
|
|
pass |
|
798
|
|
|
|
|
799
|
|
|
|
|
800
|
|
|
|
|
801
|
|
|
|
|
802
|
|
|
|
|
803
|
|
|
def start_1d_alignment(self, axis_name, axis_range, axis_step, axis_vel, |
|
804
|
|
|
stepwise_meas=True, continue_meas=False): |
|
805
|
|
|
|
|
806
|
|
|
|
|
807
|
|
|
# actual measurement routine, which is called to start the measurement |
|
808
|
|
|
|
|
809
|
|
|
|
|
810
|
|
|
if not continue_meas: |
|
811
|
|
|
|
|
812
|
|
|
# to perform the '_do_measure_after_stop' routine from the beginning |
|
813
|
|
|
# (which means e.g. an optimize pos) |
|
814
|
|
|
|
|
815
|
|
|
self._prepare_1d_graph() |
|
816
|
|
|
|
|
817
|
|
|
self._pathway = self._create_1d_pathway() |
|
818
|
|
|
|
|
819
|
|
|
if stepwise_meas: |
|
820
|
|
|
# just make it to an empty dict |
|
821
|
|
|
self._pathway_cont = dict() |
|
822
|
|
|
|
|
823
|
|
|
else: |
|
824
|
|
|
# create from the path_points the continoues points |
|
825
|
|
|
self._pathway_cont = self._create_1d_cont_pathway(self._pathway) |
|
826
|
|
|
|
|
827
|
|
|
else: |
|
828
|
|
|
# tell all the connected instances that measurement is continuing: |
|
829
|
|
|
self.sigMeasurementContinued.emit() |
|
830
|
|
|
|
|
831
|
|
|
# run at first the _move_to_curr_pathway_index method to go to the |
|
832
|
|
|
# index position: |
|
833
|
|
|
self._sigInitializeMeasPos.emit(stepwise_meas) |
|
834
|
|
|
|
|
835
|
|
|
|
|
836
|
|
|
|
|
837
|
|
|
def start_2d_alignment(self, axis0_name, axis0_range, axis0_step, |
|
838
|
|
|
axis1_name, axis1_range, axis1_step, |
|
839
|
|
|
axis0_vel=None, axis1_vel=None, |
|
840
|
|
|
stepwise_meas=True, continue_meas=False): |
|
841
|
|
|
|
|
842
|
|
|
# before starting the measurement you should convince yourself that the |
|
843
|
|
|
# passed traveling range is possible. Otherwise the measurement will be |
|
844
|
|
|
# aborted and an error is raised. |
|
845
|
|
|
# |
|
846
|
|
|
# actual measurement routine, which is called to start the measurement |
|
847
|
|
|
|
|
848
|
|
|
self._start_measurement_time = datetime.datetime.now() |
|
849
|
|
|
self._stop_measurement_time = None |
|
850
|
|
|
|
|
851
|
|
|
self._stop_measure = False |
|
852
|
|
|
|
|
853
|
|
|
self._axis0_name = axis0_name |
|
854
|
|
|
self._axis1_name = axis1_name |
|
855
|
|
|
|
|
856
|
|
|
# save only the position of the axis, which are going to be moved |
|
857
|
|
|
# during alignment, the return will be a dict! |
|
858
|
|
|
self._saved_pos_before_align = self.get_pos([axis0_name, axis1_name]) |
|
859
|
|
|
|
|
860
|
|
|
|
|
861
|
|
|
if not continue_meas: |
|
862
|
|
|
|
|
863
|
|
|
self.sigMeasurementStarted.emit() |
|
864
|
|
|
|
|
865
|
|
|
# the index, which run through the _pathway list and selects the |
|
866
|
|
|
# current measurement point |
|
867
|
|
|
self._pathway_index = 0 |
|
868
|
|
|
|
|
869
|
|
|
self._pathway, self._backmap = self._create_2d_pathway(axis0_name, axis0_range, |
|
870
|
|
|
axis0_step, axis1_name, axis1_range, |
|
871
|
|
|
axis1_step, self._saved_pos_before_align, |
|
872
|
|
|
axis0_vel, axis1_vel) |
|
873
|
|
|
|
|
874
|
|
|
# determine the start point, either relative or absolute! |
|
875
|
|
|
# Now the absolute position will be used: |
|
876
|
|
|
axis0_start = self._backmap[0][axis0_name] |
|
877
|
|
|
axis1_start = self._backmap[0][axis1_name] |
|
878
|
|
|
|
|
879
|
|
|
self._2D_data_matrix, \ |
|
880
|
|
|
self._2D_axis0_data,\ |
|
881
|
|
|
self._2D_axis1_data = self._prepare_2d_graph(axis0_start, axis0_range, |
|
882
|
|
|
axis0_step, axis1_start, |
|
883
|
|
|
axis1_range, axis1_step) |
|
884
|
|
|
|
|
885
|
|
|
self._2D_add_data_matrix = np.zeros(shape=np.shape(self._2D_data_matrix), dtype=object) |
|
886
|
|
|
|
|
887
|
|
|
|
|
888
|
|
|
if stepwise_meas: |
|
889
|
|
|
# just make it to an empty dict |
|
890
|
|
|
self._pathway_cont = dict() |
|
891
|
|
|
|
|
892
|
|
|
else: |
|
893
|
|
|
# create from the path_points the continuous points |
|
894
|
|
|
self._pathway_cont = self._create_2d_cont_pathway(self._pathway) |
|
895
|
|
|
|
|
896
|
|
|
# TODO: include here another mode, where a new defined pathway can be |
|
897
|
|
|
# created, along which the measurement should be repeated. |
|
898
|
|
|
# You have to follow the procedure: |
|
899
|
|
|
# - Create for continuing the measurement just a proper |
|
900
|
|
|
# pathway and a proper back_map in self._create_2d_pathway, |
|
901
|
|
|
# => Then the whole measurement can be just run with the new |
|
902
|
|
|
# pathway and back_map, and you do not have to adjust other |
|
903
|
|
|
# things. |
|
904
|
|
|
|
|
905
|
|
|
else: |
|
906
|
|
|
# tell all the connected instances that measurement is continuing: |
|
907
|
|
|
self.sigMeasurementContinued.emit() |
|
908
|
|
|
|
|
909
|
|
|
# run at first the _move_to_curr_pathway_index method to go to the |
|
910
|
|
|
# index position: |
|
911
|
|
|
self._sigInitializeMeasPos.emit(stepwise_meas) |
|
912
|
|
|
|
|
913
|
|
|
|
|
914
|
|
|
def _move_to_curr_pathway_index(self, stepwise_meas): |
|
915
|
|
|
|
|
916
|
|
|
# move to the passed pathway index in the list _pathway and start the |
|
917
|
|
|
# proper loop for that: |
|
918
|
|
|
|
|
919
|
|
|
# move absolute to the index position, which is currently given |
|
920
|
|
|
|
|
921
|
|
|
move_dict_vel, \ |
|
922
|
|
|
move_dict_abs, \ |
|
923
|
|
|
move_dict_rel = self._move_to_index(self._pathway_index, self._pathway) |
|
924
|
|
|
|
|
925
|
|
|
self.set_velocity(move_dict_vel) |
|
926
|
|
|
self.move_abs(move_dict_abs) |
|
927
|
|
|
# self.move_rel(move_dict_rel) |
|
928
|
|
|
|
|
929
|
|
|
|
|
930
|
|
|
|
|
931
|
|
|
# this function will return to this function if position is reached: |
|
932
|
|
|
start_pos = self._saved_pos_before_align |
|
933
|
|
|
end_pos = dict() |
|
934
|
|
|
for axis_name in self._saved_pos_before_align: |
|
935
|
|
|
end_pos[axis_name] = self._backmap[self._pathway_index][axis_name] |
|
936
|
|
|
|
|
937
|
|
|
while self._check_is_moving(): |
|
938
|
|
|
time.sleep(self._checktime) |
|
939
|
|
|
self.log.debug("Went into while loop in _move_to_curr_pathway_index") |
|
940
|
|
|
|
|
941
|
|
|
self.log.debug("(first movement) magnet moving ? {0}".format(self._check_is_moving())) |
|
942
|
|
|
|
|
943
|
|
|
|
|
944
|
|
|
if stepwise_meas: |
|
945
|
|
|
# start the Stepwise alignment loop body self._stepwise_loop_body: |
|
946
|
|
|
self._sigStepwiseAlignmentNext.emit() |
|
947
|
|
|
else: |
|
948
|
|
|
# start the continuous alignment loop body self._continuous_loop_body: |
|
949
|
|
|
self._sigContinuousAlignmentNext.emit() |
|
950
|
|
|
|
|
951
|
|
|
|
|
952
|
|
|
def _stepwise_loop_body(self): |
|
953
|
|
|
""" Go one by one through the created path |
|
954
|
|
|
@return: |
|
955
|
|
|
The loop body goes through the 1D array |
|
956
|
|
|
""" |
|
957
|
|
|
|
|
958
|
|
|
if self._stop_measure: |
|
959
|
|
|
return |
|
960
|
|
|
|
|
961
|
|
|
self._do_premeasurement_proc() |
|
962
|
|
|
pos = self._magnet_device.get_pos() |
|
963
|
|
|
self.log.debug("Current magnetic field before alignment measurement rho:{0}".format(pos['rho']) |
|
964
|
|
|
+ "phi: {0}".format(pos['phi']) + "theta: {0}".format(pos['theta'])) |
|
965
|
|
|
# perform here one of the chosen alignment measurements |
|
966
|
|
|
meas_val, add_meas_val = self._do_alignment_measurement() |
|
967
|
|
|
|
|
968
|
|
|
# set the measurement point to the proper array and the proper position: |
|
969
|
|
|
# save also all additional measurement information, which have been |
|
970
|
|
|
# done during the measurement in add_meas_val. |
|
971
|
|
|
self._set_meas_point(meas_val, add_meas_val, self._pathway_index, self._backmap) |
|
972
|
|
|
|
|
973
|
|
|
# increase the index |
|
974
|
|
|
self._pathway_index += 1 |
|
975
|
|
|
|
|
976
|
|
|
if (self._pathway_index) < len(self._pathway): |
|
977
|
|
|
|
|
978
|
|
|
# |
|
979
|
|
|
self._do_postmeasurement_proc() |
|
980
|
|
|
move_dict_vel, \ |
|
981
|
|
|
move_dict_abs, \ |
|
982
|
|
|
move_dict_rel = self._move_to_index(self._pathway_index, self._pathway) |
|
983
|
|
|
|
|
984
|
|
|
self.set_velocity(move_dict_vel) |
|
985
|
|
|
self.move_abs(move_dict_abs) |
|
986
|
|
|
|
|
987
|
|
|
# this function will return to this function if position is reached: |
|
988
|
|
|
start_pos = dict() |
|
989
|
|
|
end_pos = dict() |
|
990
|
|
|
for axis_name in self._saved_pos_before_align: |
|
991
|
|
|
start_pos[axis_name] = self._backmap[self._pathway_index - 1][axis_name] |
|
992
|
|
|
end_pos[axis_name] = self._backmap[self._pathway_index][axis_name] |
|
993
|
|
|
|
|
994
|
|
|
while self._check_is_moving(): |
|
995
|
|
|
time.sleep(self._checktime) |
|
996
|
|
|
self.log.debug("Went into while loop in stepwise_loop_body") |
|
997
|
|
|
|
|
998
|
|
|
self.log.debug("stepwise_loop_body reports magnet moving ? {0}".format(self._check_is_moving())) |
|
999
|
|
|
|
|
1000
|
|
|
# rerun this loop again |
|
1001
|
|
|
self._sigStepwiseAlignmentNext.emit() |
|
1002
|
|
|
|
|
1003
|
|
|
else: |
|
1004
|
|
|
self._end_alignment_procedure() |
|
1005
|
|
|
|
|
1006
|
|
|
|
|
1007
|
|
|
def _continuous_loop_body(self): |
|
1008
|
|
|
""" Go as much as possible in one direction |
|
1009
|
|
|
|
|
1010
|
|
|
@return: |
|
1011
|
|
|
|
|
1012
|
|
|
The loop body goes through the 1D array |
|
1013
|
|
|
""" |
|
1014
|
|
|
pass |
|
1015
|
|
|
|
|
1016
|
|
|
|
|
1017
|
|
|
|
|
1018
|
|
|
def stop_alignment(self): |
|
1019
|
|
|
""" Stops any kind of ongoing alignment measurement by setting a flag. |
|
1020
|
|
|
""" |
|
1021
|
|
|
|
|
1022
|
|
|
self._stop_measure = True |
|
1023
|
|
|
|
|
1024
|
|
|
# abort the movement or check whether immediate abortion of measurement |
|
1025
|
|
|
# was needed. |
|
1026
|
|
|
|
|
1027
|
|
|
# check whether an alignment measurement is currently going on and send |
|
1028
|
|
|
# a signal to stop that. |
|
1029
|
|
|
|
|
1030
|
|
|
def _end_alignment_procedure(self): |
|
1031
|
|
|
|
|
1032
|
|
|
# 1 check if magnet is moving and stop it |
|
1033
|
|
|
|
|
1034
|
|
|
# move back to the first position before the alignment has started: |
|
1035
|
|
|
# |
|
1036
|
|
|
constraints = self.get_hardware_constraints() |
|
1037
|
|
|
|
|
1038
|
|
|
last_pos = dict() |
|
1039
|
|
|
for axis_name in self._saved_pos_before_align: |
|
1040
|
|
|
last_pos[axis_name] = self._backmap[self._pathway_index-1][axis_name] |
|
1041
|
|
|
|
|
1042
|
|
|
self.move_abs(self._saved_pos_before_align) |
|
1043
|
|
|
|
|
1044
|
|
|
while self._check_is_moving(): |
|
1045
|
|
|
time.sleep(self._checktime) |
|
1046
|
|
|
|
|
1047
|
|
|
self.sigMeasurementFinished.emit() |
|
1048
|
|
|
|
|
1049
|
|
|
self._pathway_index = 0 |
|
1050
|
|
|
self._stop_measurement_time = datetime.datetime.now() |
|
1051
|
|
|
|
|
1052
|
|
|
self.log.info('Alignment Complete!') |
|
1053
|
|
|
|
|
1054
|
|
|
pass |
|
1055
|
|
|
|
|
1056
|
|
|
|
|
1057
|
|
|
def _check_position_reached_loop(self, start_pos_dict, end_pos_dict): |
|
1058
|
|
|
""" Perform just a while loop, which checks everytime the conditions |
|
1059
|
|
|
|
|
1060
|
|
|
@param dict start_pos_dict: the position in this dictionary must be |
|
1061
|
|
|
absolute positions! |
|
1062
|
|
|
@param dict end_pos_dict: |
|
1063
|
|
|
@param float checktime: the checktime in seconds |
|
1064
|
|
|
|
|
1065
|
|
|
@return: |
|
1066
|
|
|
|
|
1067
|
|
|
Whenever the magnet has passed 95% of the way, the method will return. |
|
1068
|
|
|
|
|
1069
|
|
|
Check also whether the difference in position increases again, and if so |
|
1070
|
|
|
stop the measurement and raise an error, since either the velocity was |
|
1071
|
|
|
too fast or the magnet does not move further. |
|
1072
|
|
|
""" |
|
1073
|
|
|
|
|
1074
|
|
|
|
|
1075
|
|
|
distance_init = 0.0 |
|
1076
|
|
|
constraints = self.get_hardware_constraints() |
|
1077
|
|
|
minimal_distance = 0.0 |
|
1078
|
|
|
for axis_label in start_pos_dict: |
|
1079
|
|
|
distance_init = (end_pos_dict[axis_label] - start_pos_dict[axis_label])**2 |
|
1080
|
|
|
minimal_distance = minimal_distance + (constraints[axis_label]['pos_step'])**2 |
|
1081
|
|
|
distance_init = np.sqrt(distance_init) |
|
1082
|
|
|
minimal_distance = np.sqrt(minimal_distance) |
|
1083
|
|
|
|
|
1084
|
|
|
# take 97% distance tolerance: |
|
1085
|
|
|
distance_tolerance = 0.03 * distance_init |
|
1086
|
|
|
|
|
1087
|
|
|
current_dist = 0.0 |
|
1088
|
|
|
|
|
1089
|
|
|
while True: |
|
1090
|
|
|
time.sleep(self._checktime) |
|
1091
|
|
|
|
|
1092
|
|
|
curr_pos = self.get_pos(list(end_pos_dict)) |
|
1093
|
|
|
|
|
1094
|
|
|
for axis_label in start_pos_dict: |
|
1095
|
|
|
current_dist = (end_pos_dict[axis_label] - curr_pos[axis_label])**2 |
|
1096
|
|
|
|
|
1097
|
|
|
current_dist = np.sqrt(current_dist) |
|
1098
|
|
|
|
|
1099
|
|
|
self.sigPosChanged.emit(curr_pos) |
|
1100
|
|
|
|
|
1101
|
|
|
if (current_dist <= distance_tolerance) or (current_dist <= minimal_distance) or self._stop_measure: |
|
1102
|
|
|
self.sigPosReached.emit() |
|
1103
|
|
|
|
|
1104
|
|
|
break |
|
1105
|
|
|
|
|
1106
|
|
|
#return either pos reached signal of check position |
|
1107
|
|
|
|
|
1108
|
|
|
def _check_is_moving(self): |
|
1109
|
|
|
""" |
|
1110
|
|
|
|
|
1111
|
|
|
@return bool: True indicates the magnet is moving, False the magnet stopped movement |
|
1112
|
|
|
""" |
|
1113
|
|
|
# get axis names |
|
1114
|
|
|
axes = [i for i in self._magnet_device.get_constraints()] |
|
1115
|
|
|
state = self._magnet_device.get_status() |
|
1116
|
|
|
|
|
1117
|
|
|
return (state[axes[0]][0] or state[axes[1]][0] or state[axes[2]][0]) is (1 or -1) |
|
1118
|
|
|
|
|
1119
|
|
|
|
|
1120
|
|
|
def _set_meas_point(self, meas_val, add_meas_val, pathway_index, back_map): |
|
1121
|
|
|
|
|
1122
|
|
|
# is it point for 1d meas or 2d meas? |
|
1123
|
|
|
|
|
1124
|
|
|
# map the point back to the position in the measurement array |
|
1125
|
|
|
index_array = back_map[pathway_index]['index'] |
|
1126
|
|
|
|
|
1127
|
|
|
# then index_array is actually no array, but just a number. That is the |
|
1128
|
|
|
# 1D case: |
|
1129
|
|
|
if np.shape(index_array) == (): |
|
1130
|
|
|
|
|
1131
|
|
|
#FIXME: Implement the 1D save |
|
1132
|
|
|
|
|
1133
|
|
|
self.sig1DMatrixChanged.emit() |
|
1134
|
|
|
|
|
1135
|
|
|
elif np.shape(index_array)[0] == 2: |
|
1136
|
|
|
|
|
1137
|
|
|
self._2D_data_matrix[index_array] = meas_val |
|
1138
|
|
|
self._2D_add_data_matrix[index_array] = add_meas_val |
|
1139
|
|
|
|
|
1140
|
|
|
# self.log.debug('Data "{0}", saved at intex "{1}"'.format(meas_val, index_array)) |
|
1141
|
|
|
|
|
1142
|
|
|
self.sig2DMatrixChanged.emit() |
|
1143
|
|
|
|
|
1144
|
|
|
elif np.shape(index_array)[0] == 3: |
|
1145
|
|
|
|
|
1146
|
|
|
|
|
1147
|
|
|
#FIXME: Implement the 3D save |
|
1148
|
|
|
self.sig3DMatrixChanged.emit() |
|
1149
|
|
|
else: |
|
1150
|
|
|
self.log.error('The measurement point "{0}" could not be set in ' |
|
1151
|
|
|
'the _set_meas_point routine, since either a 1D, a 2D or ' |
|
1152
|
|
|
'a 3D index array was expected, but an index array "{1}" ' |
|
1153
|
|
|
'was given in the passed back_map. Correct the ' |
|
1154
|
|
|
'back_map creation in the routine ' |
|
1155
|
|
|
'_create_2d_pathway!'.format(meas_val, index_array)) |
|
1156
|
|
|
|
|
1157
|
|
|
|
|
1158
|
|
|
|
|
1159
|
|
|
|
|
1160
|
|
|
pass |
|
1161
|
|
|
|
|
1162
|
|
|
def _do_premeasurement_proc(self): |
|
1163
|
|
|
# do a selected pre measurement procedure, like e.g. optimize position. |
|
1164
|
|
|
|
|
1165
|
|
|
|
|
1166
|
|
|
# first attempt of an optimizer usage: |
|
1167
|
|
|
if self._optimize_pos: |
|
1168
|
|
|
self._do_optimize_pos() |
|
1169
|
|
|
|
|
1170
|
|
|
return |
|
1171
|
|
|
|
|
1172
|
|
|
def _do_optimize_pos(self): |
|
1173
|
|
|
|
|
1174
|
|
|
curr_pos = self._confocal_logic.get_position() |
|
1175
|
|
|
|
|
1176
|
|
|
self._optimizer_logic.start_refocus(curr_pos, caller_tag='magnet_logic') |
|
1177
|
|
|
|
|
1178
|
|
|
# check just the state of the optimizer |
|
1179
|
|
|
while self._optimizer_logic.getState() != 'idle' and not self._stop_measure: |
|
1180
|
|
|
time.sleep(0.5) |
|
1181
|
|
|
|
|
1182
|
|
|
# use the position to move the scanner |
|
1183
|
|
|
self._confocal_logic.set_position('magnet_logic', |
|
1184
|
|
|
self._optimizer_logic.optim_pos_x, |
|
1185
|
|
|
self._optimizer_logic.optim_pos_y, |
|
1186
|
|
|
self._optimizer_logic.optim_pos_z) |
|
1187
|
|
|
|
|
1188
|
|
|
def _do_alignment_measurement(self): |
|
1189
|
|
|
""" That is the main method which contains all functions with measurement routines. |
|
1190
|
|
|
|
|
1191
|
|
|
Each measurement routine has to output the measurement value, but can |
|
1192
|
|
|
also provide a dictionary with additional measurement parameters, which |
|
1193
|
|
|
have been measured either as a pre-requisition for the measurement or |
|
1194
|
|
|
are results of the measurement. |
|
1195
|
|
|
|
|
1196
|
|
|
Save each measured value as an item to a keyword string, i.e. |
|
1197
|
|
|
{'ODMR frequency (MHz)': <the_parameter>, ...} |
|
1198
|
|
|
The save routine will handle the additional information and save them |
|
1199
|
|
|
properly. |
|
1200
|
|
|
|
|
1201
|
|
|
|
|
1202
|
|
|
@return tuple(float, dict): the measured value is of type float and the |
|
1203
|
|
|
additional parameters are saved in a |
|
1204
|
|
|
dictionary form. |
|
1205
|
|
|
""" |
|
1206
|
|
|
|
|
1207
|
|
|
# perform here one of the selected alignment measurements and return to |
|
1208
|
|
|
# the loop body the measured values. |
|
1209
|
|
|
|
|
1210
|
|
|
|
|
1211
|
|
|
# self.alignment_methods = ['fluorescence_pointwise', |
|
1212
|
|
|
# 'fluorescence_continuous', |
|
1213
|
|
|
# 'odmr_splitting', |
|
1214
|
|
|
# 'odmr_hyperfine_splitting', |
|
1215
|
|
|
# 'nuclear_spin_measurement'] |
|
1216
|
|
|
|
|
1217
|
|
|
if self.curr_alignment_method == '2d_fluorescence': |
|
1218
|
|
|
data, add_data = self._perform_fluorescence_measure() |
|
1219
|
|
|
|
|
1220
|
|
|
elif self.curr_alignment_method == '2d_odmr': |
|
1221
|
|
|
if self.odmr_2d_single_trans: |
|
1222
|
|
|
data, add_data = self._perform_single_trans_contrast_measure() |
|
1223
|
|
|
else: |
|
1224
|
|
|
data, add_data = self._perform_odmr_measure() |
|
1225
|
|
|
|
|
1226
|
|
|
elif self.curr_alignment_method == '2d_nuclear': |
|
1227
|
|
|
data, add_data = self._perform_nuclear_measure() |
|
1228
|
|
|
# data, add_data = self._perform_odmr_measure(11100e6, 1e6, 11200e6, 5, 10, 'Lorentzian', False,'') |
|
1229
|
|
|
|
|
1230
|
|
|
|
|
1231
|
|
|
return data, add_data |
|
1232
|
|
|
|
|
1233
|
|
|
|
|
1234
|
|
|
def _perform_fluorescence_measure(self): |
|
1235
|
|
|
|
|
1236
|
|
|
#FIXME: that should be run through the TaskRunner! Implement the call |
|
1237
|
|
|
# by not using this connection! |
|
1238
|
|
|
|
|
1239
|
|
|
if self._counter_logic.get_counting_mode != 'continuous': |
|
1240
|
|
|
self._counter_logic.set_counting_mode(mode='continuous') |
|
1241
|
|
|
|
|
1242
|
|
|
self._counter_logic.start_saving() |
|
1243
|
|
|
time.sleep(self.fluorescence_integration_time) |
|
1244
|
|
|
data_array, parameters = self._counter_logic.save_data(to_file=False) |
|
1245
|
|
|
|
|
1246
|
|
|
data_array = np.array(data_array)[:, 1] |
|
1247
|
|
|
|
|
1248
|
|
|
return data_array.mean(), parameters |
|
1249
|
|
|
|
|
1250
|
|
|
def _perform_odmr_measure(self): |
|
1251
|
|
|
""" Perform the odmr measurement. |
|
1252
|
|
|
|
|
1253
|
|
|
@return: |
|
1254
|
|
|
""" |
|
1255
|
|
|
|
|
1256
|
|
|
store_dict = {} |
|
1257
|
|
|
|
|
1258
|
|
|
# optimize at first the position: |
|
1259
|
|
|
self._do_optimize_pos() |
|
1260
|
|
|
|
|
1261
|
|
|
|
|
1262
|
|
|
# correct the ODMR alignment the shift of the ODMR lines due to movement |
|
1263
|
|
|
# in axis0 and axis1, therefore find out how much you will move in each |
|
1264
|
|
|
# distance: |
|
1265
|
|
|
if self._pathway_index == 0: |
|
1266
|
|
|
axis0_pos_start = self._saved_pos_before_align[self._axis0_name] |
|
1267
|
|
|
axis0_pos_stop = self._backmap[self._pathway_index][self._axis0_name] |
|
1268
|
|
|
|
|
1269
|
|
|
axis1_pos_start = self._saved_pos_before_align[self._axis1_name] |
|
1270
|
|
|
axis1_pos_stop = self._backmap[self._pathway_index][self._axis1_name] |
|
1271
|
|
|
else: |
|
1272
|
|
|
axis0_pos_start = self._backmap[self._pathway_index-1][self._axis0_name] |
|
1273
|
|
|
axis0_pos_stop = self._backmap[self._pathway_index][self._axis0_name] |
|
1274
|
|
|
|
|
1275
|
|
|
axis1_pos_start = self._backmap[self._pathway_index-1][self._axis1_name] |
|
1276
|
|
|
axis1_pos_stop = self._backmap[self._pathway_index][self._axis1_name] |
|
1277
|
|
|
|
|
1278
|
|
|
# that is the current distance the magnet has moved: |
|
1279
|
|
View Code Duplication |
axis0_move = axis0_pos_stop - axis0_pos_start |
|
|
|
|
|
|
1280
|
|
|
axis1_move = axis1_pos_stop - axis1_pos_start |
|
1281
|
|
|
print('axis0_move', axis0_move, 'axis1_move', axis1_move) |
|
1282
|
|
|
|
|
1283
|
|
|
# in essence, get the last measurement value for odmr freq and calculate |
|
1284
|
|
|
# the odmr peak shift for axis0 and axis1 based on the already measured |
|
1285
|
|
|
# peaks and update the values odmr_2d_peak_axis0_move_ratio and |
|
1286
|
|
|
# odmr_2d_peak_axis1_move_ratio: |
|
1287
|
|
|
if self._pathway_index > 1: |
|
1288
|
|
|
# in essence, get the last measurement value for odmr freq: |
|
1289
|
|
View Code Duplication |
if self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']].get('low_freq_Frequency') is not None: |
|
|
|
|
|
|
1290
|
|
|
low_odmr_freq1 = self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']]['low_freq_Frequency']['value']*1e6 |
|
1291
|
|
|
low_odmr_freq2 = self._2D_add_data_matrix[self._backmap[self._pathway_index-2]['index']]['low_freq_Frequency']['value']*1e6 |
|
1292
|
|
|
elif self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']].get('low_freq_Freq. 1') is not None: |
|
1293
|
|
|
low_odmr_freq1 = self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']]['low_freq_Freq. 1']['value']*1e6 |
|
1294
|
|
|
low_odmr_freq2 = self._2D_add_data_matrix[self._backmap[self._pathway_index-2]['index']]['low_freq_Freq. 1']['value']*1e6 |
|
1295
|
|
|
else: |
|
1296
|
|
|
self.log.error('No previous saved lower odmr freq found in ' |
|
1297
|
|
|
'ODMR alignment data! Cannot do the ODMR Alignment!') |
|
1298
|
|
|
|
|
1299
|
|
|
if self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']].get('high_freq_Frequency') is not None: |
|
1300
|
|
|
high_odmr_freq1 = self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']]['high_freq_Frequency']['value']*1e6 |
|
1301
|
|
|
high_odmr_freq2 = self._2D_add_data_matrix[self._backmap[self._pathway_index-2]['index']]['high_freq_Frequency']['value']*1e6 |
|
1302
|
|
|
elif self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']].get('high_freq_Freq. 1') is not None: |
|
1303
|
|
|
high_odmr_freq1 = self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']]['high_freq_Freq. 1']['value']*1e6 |
|
1304
|
|
|
high_odmr_freq2 = self._2D_add_data_matrix[self._backmap[self._pathway_index-2]['index']]['high_freq_Freq. 1']['value']*1e6 |
|
1305
|
|
|
else: |
|
1306
|
|
|
self.log.error('No previous saved higher odmr freq found in ' |
|
1307
|
|
|
'ODMR alignment data! Cannot do the ODMR Alignment!') |
|
1308
|
|
|
|
|
1309
|
|
|
# only if there was a non zero movement, the if make sense to |
|
1310
|
|
|
# calculate the shift for either the axis0 or axis1. |
|
1311
|
|
|
# BE AWARE THAT FOR A MOVEMENT IN AXIS0 AND AXIS1 AT THE SAME TIME |
|
1312
|
|
|
# NO PROPER CALCULATION OF THE OMDR LINES CAN BE PROVIDED! |
|
1313
|
|
|
if not np.isclose(axis0_move, 0.0): |
|
1314
|
|
|
# update the correction ratio: |
|
1315
|
|
|
low_peak_axis0_move_ratio = (low_odmr_freq1 - low_odmr_freq2)/axis0_move |
|
1316
|
|
|
high_peak_axis0_move_ratio = (high_odmr_freq1 - high_odmr_freq2)/axis0_move |
|
1317
|
|
|
|
|
1318
|
|
|
# print('low_odmr_freq2', low_odmr_freq2, 'low_odmr_freq1', low_odmr_freq1) |
|
1319
|
|
|
# print('high_odmr_freq2', high_odmr_freq2, 'high_odmr_freq1', high_odmr_freq1) |
|
1320
|
|
|
|
|
1321
|
|
|
# calculate the average shift of the odmr lines for the lower |
|
1322
|
|
|
# and the upper transition: |
|
1323
|
|
|
self.odmr_2d_peak_axis0_move_ratio = (low_peak_axis0_move_ratio +high_peak_axis0_move_ratio)/2 |
|
1324
|
|
|
|
|
1325
|
|
|
# print('new odmr_2d_peak_axis0_move_ratio', self.odmr_2d_peak_axis0_move_ratio/1e12) |
|
1326
|
|
|
if not np.isclose(axis1_move, 0.0): |
|
1327
|
|
|
# update the correction ratio: |
|
1328
|
|
|
low_peak_axis1_move_ratio = (low_odmr_freq1 - low_odmr_freq2)/axis1_move |
|
1329
|
|
|
high_peak_axis1_move_ratio = (high_odmr_freq1 - high_odmr_freq2)/axis1_move |
|
1330
|
|
|
|
|
1331
|
|
|
# calculate the average shift of the odmr lines for the lower |
|
1332
|
|
|
# and the upper transition: |
|
1333
|
|
|
self.odmr_2d_peak_axis1_move_ratio = (low_peak_axis1_move_ratio + high_peak_axis1_move_ratio)/2 |
|
1334
|
|
|
|
|
1335
|
|
|
# print('new odmr_2d_peak_axis1_move_ratio', self.odmr_2d_peak_axis1_move_ratio/1e12) |
|
1336
|
|
|
|
|
1337
|
|
|
# Measurement of the lower transition: |
|
1338
|
|
|
# ------------------------------------- |
|
1339
|
|
|
|
|
1340
|
|
|
freq_shift_low_axis0 = axis0_move * self.odmr_2d_peak_axis0_move_ratio |
|
1341
|
|
|
freq_shift_low_axis1 = axis1_move * self.odmr_2d_peak_axis1_move_ratio |
|
1342
|
|
|
|
|
1343
|
|
|
# correct here the center freq with the estimated corrections: |
|
1344
|
|
|
self.odmr_2d_low_center_freq += (freq_shift_low_axis0 + freq_shift_low_axis1) |
|
1345
|
|
|
# print('self.odmr_2d_low_center_freq',self.odmr_2d_low_center_freq) |
|
1346
|
|
|
|
|
1347
|
|
|
# create a unique nametag for the current measurement: |
|
1348
|
|
|
name_tag = 'low_trans_index_'+str(self._backmap[self._pathway_index]['index'][0]) \ |
|
1349
|
|
|
+'_'+ str(self._backmap[self._pathway_index]['index'][1]) |
|
1350
|
|
|
|
|
1351
|
|
|
# of course the shift of the ODMR peak is not linear for a movement in |
|
1352
|
|
|
# axis0 and axis1, but we need just an estimate how to set the boundary |
|
1353
|
|
|
# conditions for the first scan, since the first scan will move to a |
|
1354
|
|
|
# start position and then it need to know where to search for the ODMR |
|
1355
|
|
|
# peak(s). |
|
1356
|
|
|
|
|
1357
|
|
|
# calculate the parameters for the odmr scan: |
|
1358
|
|
|
low_start_freq = self.odmr_2d_low_center_freq - self.odmr_2d_low_range_freq/2 |
|
1359
|
|
|
low_step_freq = self.odmr_2d_low_step_freq |
|
1360
|
|
|
low_stop_freq = self.odmr_2d_low_center_freq + self.odmr_2d_low_range_freq/2 |
|
1361
|
|
|
|
|
1362
|
|
|
param = self._odmr_logic.perform_odmr_measurement(low_start_freq, |
|
1363
|
|
|
low_step_freq, |
|
1364
|
|
|
low_stop_freq, |
|
1365
|
|
|
self.odmr_2d_low_power, |
|
1366
|
|
|
self.odmr_2d_low_runtime, |
|
1367
|
|
|
self.odmr_2d_low_fitfunction, |
|
1368
|
|
|
self.odmr_2d_save_after_measure, |
|
1369
|
|
|
name_tag) |
|
1370
|
|
|
|
|
1371
|
|
|
# restructure the output parameters: |
|
1372
|
|
|
for entry in param: |
|
1373
|
|
|
store_dict['low_freq_'+str(entry)] = param[entry] |
|
1374
|
|
|
|
|
1375
|
|
|
# extract the frequency meausure: |
|
1376
|
|
|
if param.get('Frequency') is not None: |
|
1377
|
|
|
odmr_low_freq_meas = param['Frequency']['value']*1e6 |
|
1378
|
|
|
elif param.get('Freq. 1') is not None: |
|
1379
|
|
|
odmr_low_freq_meas = param['Freq. 1']['value']*1e6 |
|
1380
|
|
|
else: |
|
1381
|
|
|
# a default value for testing and debugging: |
|
1382
|
|
|
odmr_low_freq_meas = 1000e6 |
|
1383
|
|
|
|
|
1384
|
|
|
self.odmr_2d_low_center_freq = odmr_low_freq_meas |
|
1385
|
|
|
# Measurement of the higher transition: |
|
1386
|
|
|
# ------------------------------------- |
|
1387
|
|
|
|
|
1388
|
|
|
|
|
1389
|
|
|
freq_shift_high_axis0 = axis0_move * self.odmr_2d_peak_axis0_move_ratio |
|
1390
|
|
|
freq_shift_high_axis1 = axis1_move * self.odmr_2d_peak_axis1_move_ratio |
|
1391
|
|
|
|
|
1392
|
|
|
# correct here the center freq with the estimated corrections: |
|
1393
|
|
|
self.odmr_2d_high_center_freq += (freq_shift_high_axis0 + freq_shift_high_axis1) |
|
1394
|
|
|
|
|
1395
|
|
|
# create a unique nametag for the current measurement: |
|
1396
|
|
|
name_tag = 'high_trans_index_'+str(self._backmap[self._pathway_index]['index'][0]) \ |
|
1397
|
|
|
+'_'+ str(self._backmap[self._pathway_index]['index'][1]) |
|
1398
|
|
|
|
|
1399
|
|
|
# of course the shift of the ODMR peak is not linear for a movement in |
|
1400
|
|
|
# axis0 and axis1, but we need just an estimate how to set the boundary |
|
1401
|
|
|
# conditions for the first scan, since the first scan will move to a |
|
1402
|
|
|
# start position and then it need to know where to search for the ODMR |
|
1403
|
|
|
# peak(s). |
|
1404
|
|
|
|
|
1405
|
|
|
# calculate the parameters for the odmr scan: |
|
1406
|
|
|
high_start_freq = self.odmr_2d_high_center_freq - self.odmr_2d_high_range_freq/2 |
|
1407
|
|
|
high_step_freq = self.odmr_2d_high_step_freq |
|
1408
|
|
|
high_stop_freq = self.odmr_2d_high_center_freq + self.odmr_2d_high_range_freq/2 |
|
1409
|
|
|
|
|
1410
|
|
|
param = self._odmr_logic.perform_odmr_measurement(high_start_freq, |
|
1411
|
|
|
high_step_freq, |
|
1412
|
|
|
high_stop_freq, |
|
1413
|
|
|
self.odmr_2d_high_power, |
|
1414
|
|
|
self.odmr_2d_high_runtime, |
|
1415
|
|
|
self.odmr_2d_high_fitfunction, |
|
1416
|
|
|
self.odmr_2d_save_after_measure, |
|
1417
|
|
|
name_tag) |
|
1418
|
|
|
# restructure the output parameters: |
|
1419
|
|
|
for entry in param: |
|
1420
|
|
|
store_dict['high_freq_'+str(entry)] = param[entry] |
|
1421
|
|
|
|
|
1422
|
|
|
# extract the frequency meausure: |
|
1423
|
|
|
if param.get('Frequency') is not None: |
|
1424
|
|
|
odmr_high_freq_meas = param['Frequency']['value']*1e6 |
|
1425
|
|
|
elif param.get('Freq. 1') is not None: |
|
1426
|
|
|
odmr_high_freq_meas = param['Freq. 1']['value']*1e6 |
|
1427
|
|
|
else: |
|
1428
|
|
|
# a default value for testing and debugging: |
|
1429
|
|
|
odmr_high_freq_meas = 2000e6 |
|
1430
|
|
|
|
|
1431
|
|
|
# correct the estimated center frequency by the actual measured one. |
|
1432
|
|
|
self.odmr_2d_high_center_freq = odmr_high_freq_meas |
|
1433
|
|
|
|
|
1434
|
|
|
#FIXME: the normalization is just done for the display to view the |
|
1435
|
|
|
# value properly! There is right now a bug in the colorbad |
|
1436
|
|
|
# display, which need to be solved. |
|
1437
|
|
|
diff = (abs(odmr_high_freq_meas - odmr_low_freq_meas)/2)/self.norm |
|
1438
|
|
|
|
|
1439
|
|
|
while self._odmr_logic.getState() != 'idle' and not self._stop_measure: |
|
1440
|
|
|
time.sleep(0.5) |
|
1441
|
|
|
|
|
1442
|
|
|
return diff, store_dict |
|
1443
|
|
|
|
|
1444
|
|
|
def _perform_single_trans_contrast_measure(self): |
|
1445
|
|
|
""" Make an ODMR measurement on one single transition and use the |
|
1446
|
|
|
contrast as a measure. |
|
1447
|
|
|
""" |
|
1448
|
|
|
|
|
1449
|
|
|
store_dict = {} |
|
1450
|
|
|
|
|
1451
|
|
|
# optimize at first the position: |
|
1452
|
|
|
self._do_optimize_pos() |
|
1453
|
|
|
|
|
1454
|
|
|
# correct the ODMR alignment the shift of the ODMR lines due to movement |
|
1455
|
|
|
# in axis0 and axis1, therefore find out how much you will move in each |
|
1456
|
|
|
# distance: |
|
1457
|
|
|
if self._pathway_index == 0: |
|
1458
|
|
|
axis0_pos_start = self._saved_pos_before_align[self._axis0_name] |
|
1459
|
|
|
axis0_pos_stop = self._backmap[self._pathway_index][self._axis0_name] |
|
1460
|
|
|
|
|
1461
|
|
|
axis1_pos_start = self._saved_pos_before_align[self._axis1_name] |
|
1462
|
|
|
axis1_pos_stop = self._backmap[self._pathway_index][self._axis1_name] |
|
1463
|
|
|
else: |
|
1464
|
|
|
axis0_pos_start = self._backmap[self._pathway_index-1][self._axis0_name] |
|
1465
|
|
|
axis0_pos_stop = self._backmap[self._pathway_index][self._axis0_name] |
|
1466
|
|
|
|
|
1467
|
|
|
axis1_pos_start = self._backmap[self._pathway_index-1][self._axis1_name] |
|
1468
|
|
|
axis1_pos_stop = self._backmap[self._pathway_index][self._axis1_name] |
|
1469
|
|
|
|
|
1470
|
|
|
# that is the current distance the magnet has moved: |
|
1471
|
|
View Code Duplication |
axis0_move = axis0_pos_stop - axis0_pos_start |
|
|
|
|
|
|
1472
|
|
|
axis1_move = axis1_pos_stop - axis1_pos_start |
|
1473
|
|
|
# print('axis0_move', axis0_move, 'axis1_move', axis1_move) |
|
1474
|
|
|
|
|
1475
|
|
|
# in essence, get the last measurement value for odmr freq and calculate |
|
1476
|
|
|
# the odmr peak shift for axis0 and axis1 based on the already measured |
|
1477
|
|
|
# peaks and update the values odmr_2d_peak_axis0_move_ratio and |
|
1478
|
|
|
# odmr_2d_peak_axis1_move_ratio: |
|
1479
|
|
|
if self._pathway_index > 1: |
|
1480
|
|
|
# in essence, get the last measurement value for odmr freq: |
|
1481
|
|
|
if self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']].get('Frequency') is not None: |
|
1482
|
|
|
odmr_freq1 = self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']]['Frequency']['value']*1e6 |
|
1483
|
|
|
odmr_freq2 = self._2D_add_data_matrix[self._backmap[self._pathway_index-2]['index']]['Frequency']['value']*1e6 |
|
1484
|
|
|
elif self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']].get('Freq. 1') is not None: |
|
1485
|
|
|
odmr_freq1 = self._2D_add_data_matrix[self._backmap[self._pathway_index-1]['index']]['Freq. 1']['value']*1e6 |
|
1486
|
|
|
odmr_freq2 = self._2D_add_data_matrix[self._backmap[self._pathway_index-2]['index']]['Freq. 1']['value']*1e6 |
|
1487
|
|
|
else: |
|
1488
|
|
|
self.log.error('No previous saved lower odmr freq found in ' |
|
1489
|
|
|
'ODMR alignment data! Cannot do the ODMR ' |
|
1490
|
|
|
'Alignment!') |
|
1491
|
|
|
|
|
1492
|
|
|
|
|
1493
|
|
|
# only if there was a non zero movement, the if make sense to |
|
1494
|
|
|
# calculate the shift for either the axis0 or axis1. |
|
1495
|
|
|
# BE AWARE THAT FOR A MOVEMENT IN AXIS0 AND AXIS1 AT THE SAME TIME |
|
1496
|
|
|
# NO PROPER CALCULATION OF THE OMDR LINES CAN BE PROVIDED! |
|
1497
|
|
|
if not np.isclose(axis0_move, 0.0): |
|
1498
|
|
|
# update the correction ratio: |
|
1499
|
|
|
peak_axis0_move_ratio = (odmr_freq1 - odmr_freq2)/axis0_move |
|
1500
|
|
|
|
|
1501
|
|
|
# calculate the average shift of the odmr lines for the lower |
|
1502
|
|
|
# and the upper transition: |
|
1503
|
|
|
self.odmr_2d_peak_axis0_move_ratio = peak_axis0_move_ratio |
|
1504
|
|
|
|
|
1505
|
|
|
print('new odmr_2d_peak_axis0_move_ratio', self.odmr_2d_peak_axis0_move_ratio/1e12) |
|
1506
|
|
|
if not np.isclose(axis1_move, 0.0): |
|
1507
|
|
|
# update the correction ratio: |
|
1508
|
|
|
peak_axis1_move_ratio = (odmr_freq1 - odmr_freq2)/axis1_move |
|
1509
|
|
|
|
|
1510
|
|
|
|
|
1511
|
|
|
# calculate the shift of the odmr lines for the transition: |
|
1512
|
|
|
self.odmr_2d_peak_axis1_move_ratio = peak_axis1_move_ratio |
|
1513
|
|
|
|
|
1514
|
|
|
# Measurement of one transition: |
|
1515
|
|
|
# ------------------------------------- |
|
1516
|
|
|
|
|
1517
|
|
|
freq_shift_axis0 = axis0_move * self.odmr_2d_peak_axis0_move_ratio |
|
1518
|
|
|
freq_shift_axis1 = axis1_move * self.odmr_2d_peak_axis1_move_ratio |
|
1519
|
|
|
|
|
1520
|
|
|
# correct here the center freq with the estimated corrections: |
|
1521
|
|
|
self.odmr_2d_low_center_freq += (freq_shift_axis0 + freq_shift_axis1) |
|
1522
|
|
|
# print('self.odmr_2d_low_center_freq',self.odmr_2d_low_center_freq) |
|
1523
|
|
|
|
|
1524
|
|
|
# create a unique nametag for the current measurement: |
|
1525
|
|
|
name_tag = 'trans_index_'+str(self._backmap[self._pathway_index]['index'][0]) \ |
|
1526
|
|
|
+'_'+ str(self._backmap[self._pathway_index]['index'][1]) |
|
1527
|
|
|
|
|
1528
|
|
|
# of course the shift of the ODMR peak is not linear for a movement in |
|
1529
|
|
|
# axis0 and axis1, but we need just an estimate how to set the boundary |
|
1530
|
|
|
# conditions for the first scan, since the first scan will move to a |
|
1531
|
|
|
# start position and then it need to know where to search for the ODMR |
|
1532
|
|
|
# peak(s). |
|
1533
|
|
|
|
|
1534
|
|
|
# calculate the parameters for the odmr scan: |
|
1535
|
|
|
start_freq = self.odmr_2d_low_center_freq - self.odmr_2d_low_range_freq/2 |
|
1536
|
|
|
step_freq = self.odmr_2d_low_step_freq |
|
1537
|
|
|
stop_freq = self.odmr_2d_low_center_freq + self.odmr_2d_low_range_freq/2 |
|
1538
|
|
|
|
|
1539
|
|
|
param = self._odmr_logic.perform_odmr_measurement(start_freq, |
|
1540
|
|
|
step_freq, |
|
1541
|
|
|
stop_freq, |
|
1542
|
|
|
self.odmr_2d_low_power, |
|
1543
|
|
|
self.odmr_2d_low_runtime, |
|
1544
|
|
|
self.odmr_2d_low_fitfunction, |
|
1545
|
|
|
self.odmr_2d_save_after_measure, |
|
1546
|
|
|
name_tag) |
|
1547
|
|
|
|
|
1548
|
|
|
param['ODMR peak/Magnet move ratio axis0'] = self.odmr_2d_peak_axis0_move_ratio |
|
1549
|
|
|
param['ODMR peak/Magnet move ratio axis1'] = self.odmr_2d_peak_axis1_move_ratio |
|
1550
|
|
|
|
|
1551
|
|
|
# extract the frequency meausure: |
|
1552
|
|
|
if param.get('Frequency') is not None: |
|
1553
|
|
|
odmr_freq_meas = param['Frequency']['value']*1e6 |
|
1554
|
|
|
cont_meas = param['Contrast']['value'] |
|
1555
|
|
|
elif param.get('Freq. 1') is not None: |
|
1556
|
|
|
odmr_freq_meas = param['Freq. 1']['value']*1e6 |
|
1557
|
|
|
cont_meas = param['Contrast 0']['value'] + param['Contrast 1']['value'] + param['Contrast 2']['value'] |
|
1558
|
|
|
else: |
|
1559
|
|
|
# a default value for testing and debugging: |
|
1560
|
|
|
odmr_freq_meas = 1000e6 |
|
1561
|
|
|
cont_meas = 0.0 |
|
1562
|
|
|
|
|
1563
|
|
|
self.odmr_2d_low_center_freq = odmr_freq_meas |
|
1564
|
|
|
|
|
1565
|
|
|
while self._odmr_logic.getState() != 'idle' and not self._stop_measure: |
|
1566
|
|
|
time.sleep(0.5) |
|
1567
|
|
|
|
|
1568
|
|
|
return cont_meas, param |
|
1569
|
|
|
|
|
1570
|
|
|
def _perform_nuclear_measure(self): |
|
1571
|
|
|
""" Make a single shot alignment. """ |
|
1572
|
|
|
|
|
1573
|
|
|
# possible parameters for the nuclear measurement: |
|
1574
|
|
|
# self.nuclear_2d_rabi_periode |
|
1575
|
|
|
# self.nuclear_2d_mw_freq |
|
1576
|
|
|
# self.nuclear_2d_mw_channel |
|
1577
|
|
|
# self.nuclear_2d_mw_power |
|
1578
|
|
|
# self.nuclear_2d_laser_time |
|
1579
|
|
|
# self.nuclear_2d_laser_channel |
|
1580
|
|
|
# self.nuclear_2d_detect_channel |
|
1581
|
|
|
# self.nuclear_2d_idle_time |
|
1582
|
|
|
# self.nuclear_2d_reps_within_ssr |
|
1583
|
|
|
# self.nuclear_2d_num_ssr |
|
1584
|
|
|
self._load_pulsed_odmr() |
|
1585
|
|
|
self._pulser_on() |
|
1586
|
|
|
|
|
1587
|
|
|
# self.odmr_2d_low_center_freq |
|
1588
|
|
|
# self.odmr_2d_low_step_freq |
|
1589
|
|
|
# self.odmr_2d_low_range_freq |
|
1590
|
|
|
# |
|
1591
|
|
|
# self.odmr_2d_low_power, |
|
1592
|
|
|
# self.odmr_2d_low_runtime, |
|
1593
|
|
|
# self.odmr_2d_low_fitfunction, |
|
1594
|
|
|
# self.odmr_2d_save_after_measure, |
|
1595
|
|
|
|
|
1596
|
|
|
# Use the parameters from the ODMR alignment! |
|
1597
|
|
|
cont_meas, param = self._perform_single_trans_contrast_measure() |
|
1598
|
|
|
|
|
1599
|
|
|
odmr_freq = param['Freq. ' + str(self.nuclear_2d_mw_on_peak-1)]['value']*1e6 |
|
1600
|
|
|
|
|
1601
|
|
|
self._set_cw_mw(switch_on=True, freq=odmr_freq, power=self.nuclear_2d_mw_power) |
|
1602
|
|
|
self._load_nuclear_spin_readout() |
|
1603
|
|
|
self._pulser_on() |
|
1604
|
|
|
|
|
1605
|
|
|
# Check whether proper mode is active and if not activated that: |
|
1606
|
|
|
if self._gc_logic.get_counting_mode() != 'finite-gated': |
|
1607
|
|
|
self._gc_logic.set_counting_mode(mode='finite-gated') |
|
1608
|
|
|
|
|
1609
|
|
|
# Set the count length for the single shot and start counting: |
|
1610
|
|
|
self._gc_logic.set_count_length(self.nuclear_2d_num_ssr) |
|
1611
|
|
|
|
|
1612
|
|
|
self._run_gated_counter() |
|
1613
|
|
|
|
|
1614
|
|
|
self._set_cw_mw(switch_on=False) |
|
1615
|
|
|
|
|
1616
|
|
|
# try with single poissonian: |
|
1617
|
|
|
|
|
1618
|
|
|
|
|
1619
|
|
|
num_bins = (self._gc_logic.countdata.max() - self._gc_logic.countdata.min()) |
|
1620
|
|
|
self._ta_logic.set_num_bins_histogram(num_bins) |
|
1621
|
|
|
|
|
1622
|
|
|
hist_fit_x, hist_fit_y, param_single_poisson = self._ta_logic.do_fit('Poisson') |
|
1623
|
|
|
|
|
1624
|
|
|
|
|
1625
|
|
|
param['chi_sqr_single'] = param_single_poisson['chi_sqr']['value'] |
|
1626
|
|
|
|
|
1627
|
|
|
|
|
1628
|
|
|
# try with normal double poissonian: |
|
1629
|
|
|
|
|
1630
|
|
|
# better performance by starting with half of number of bins: |
|
1631
|
|
|
num_bins = int((self._gc_logic.countdata.max() - self._gc_logic.countdata.min())/2) |
|
1632
|
|
|
self._ta_logic.set_num_bins_histogram(num_bins) |
|
1633
|
|
|
|
|
1634
|
|
|
flip_prob, param2 = self._ta_logic.analyze_flip_prob(self._gc_logic.countdata, num_bins) |
|
1635
|
|
|
|
|
1636
|
|
|
# self._pulser_off() |
|
1637
|
|
|
# |
|
1638
|
|
|
# self._load_pulsed_odmr() |
|
1639
|
|
|
# self._pulser_on() |
|
1640
|
|
|
|
|
1641
|
|
|
out_of_range = (param2['\u03BB0']['value'] < self._gc_logic.countdata.min() or param2['\u03BB0']['value'] > self._gc_logic.countdata.max()) or \ |
|
1642
|
|
|
(param2['\u03BB1']['value'] < self._gc_logic.countdata.min() or param2['\u03BB1']['value'] > self._gc_logic.countdata.max()) |
|
1643
|
|
|
|
|
1644
|
|
|
while (np.isnan(param2['fidelity'] or out_of_range) and num_bins > 4): |
|
1645
|
|
|
# Reduce the number of bins if the calculation yields an invalid |
|
1646
|
|
|
# number |
|
1647
|
|
|
num_bins = int(num_bins/2) |
|
1648
|
|
|
self._ta_logic.set_num_bins_histogram(num_bins) |
|
1649
|
|
|
flip_prob, param2 = self._ta_logic.analyze_flip_prob(self._gc_logic.countdata, num_bins) |
|
1650
|
|
|
|
|
1651
|
|
|
|
|
1652
|
|
|
# reduce the number of bins by one, so that the fitting algorithm |
|
1653
|
|
|
# work. Eventually, that has to go in the fit constaints of the |
|
1654
|
|
|
# algorithm. |
|
1655
|
|
|
|
|
1656
|
|
|
out_of_range = (param2['\u03BB0']['value'] < self._gc_logic.countdata.min() or param2['\u03BB0']['value'] > self._gc_logic.countdata.max()) or \ |
|
1657
|
|
|
(param2['\u03BB1']['value'] < self._gc_logic.countdata.min() or param2['\u03BB1']['value'] > self._gc_logic.countdata.max()) |
|
1658
|
|
|
|
|
1659
|
|
|
if out_of_range: |
|
1660
|
|
|
num_bins = num_bins-1 |
|
1661
|
|
|
self._ta_logic.set_num_bins_histogram(num_bins) |
|
1662
|
|
|
self.log.warning('Fitted values {0},{1} are out of range [{2},{3}]! ' |
|
1663
|
|
|
'Change the histogram a ' |
|
1664
|
|
|
'bit.'.format(param2['\u03BB0']['value'], |
|
1665
|
|
|
param2['\u03BB1']['value'], |
|
1666
|
|
|
self._gc_logic.countdata.min(), |
|
1667
|
|
|
self._gc_logic.countdata.max())) |
|
1668
|
|
|
|
|
1669
|
|
|
flip_prob, param2 = self._ta_logic.analyze_flip_prob(self._gc_logic.countdata, num_bins) |
|
1670
|
|
|
|
|
1671
|
|
|
# run the lifetime calculatiion: |
|
1672
|
|
|
# In order to calculate the T1 time one needs the length of one SingleShot readout |
|
1673
|
|
|
dt = (self.nuclear_2d_rabi_periode/2 + self.nuclear_2d_laser_time + self.nuclear_2d_idle_time) * self.nuclear_2d_reps_within_ssr |
|
1674
|
|
|
# param_lifetime = self._ta_logic.analyze_lifetime(self._gc_logic.countdata, dt, self.nuclear_2d_estimated_lifetime) |
|
1675
|
|
|
# param.update(param_lifetime) |
|
1676
|
|
|
|
|
1677
|
|
|
|
|
1678
|
|
|
# If everything went wrong, then put at least a reasonable number: |
|
1679
|
|
|
if np.isnan(param2['fidelity']): |
|
1680
|
|
|
param2['fidelity'] = 0.5 # that fidelity means that |
|
1681
|
|
|
|
|
1682
|
|
|
# add the flip probability as a parameter to the parameter dict and add |
|
1683
|
|
|
# also all the other parameters to that dict: |
|
1684
|
|
|
param['flip_probability'] = flip_prob |
|
1685
|
|
|
param.update(param2) |
|
1686
|
|
|
|
|
1687
|
|
|
if self.nuclear_2d_use_single_poisson: |
|
1688
|
|
|
# print(param) |
|
1689
|
|
|
# print(param['chi_sqr']) |
|
1690
|
|
|
return param['chi_sqr_single'], param |
|
1691
|
|
|
|
|
1692
|
|
|
else: |
|
1693
|
|
|
return param['fidelity'], param |
|
1694
|
|
|
|
|
1695
|
|
|
def _run_gated_counter(self): |
|
1696
|
|
|
|
|
1697
|
|
|
self._gc_logic.startCount() |
|
1698
|
|
|
time.sleep(2) |
|
1699
|
|
|
|
|
1700
|
|
|
# wait until the gated counter is done |
|
1701
|
|
|
while self._gc_logic.getState() != 'idle' and not self._stop_measure: |
|
1702
|
|
|
# print('in SSR measure') |
|
1703
|
|
|
time.sleep(1) |
|
1704
|
|
|
|
|
1705
|
|
|
|
|
1706
|
|
|
def _set_cw_mw(self, switch_on, freq=2.87e9, power=-40): |
|
1707
|
|
|
|
|
1708
|
|
|
if switch_on: |
|
1709
|
|
|
self._odmr_logic.set_frequency(freq) |
|
1710
|
|
|
self._odmr_logic.set_power(power) |
|
1711
|
|
|
self._odmr_logic.MW_on() |
|
1712
|
|
|
else: |
|
1713
|
|
|
self._odmr_logic.MW_off() |
|
1714
|
|
|
|
|
1715
|
|
|
def _load_pulsed_odmr(self): |
|
1716
|
|
|
""" Load a pulsed ODMR asset. """ |
|
1717
|
|
|
#FIXME: Move this creation routine to the tasks! |
|
1718
|
|
|
|
|
1719
|
|
|
self._seq_gen_logic.load_asset(asset_name='PulsedODMR') |
|
1720
|
|
|
|
|
1721
|
|
|
def _load_nuclear_spin_readout(self): |
|
1722
|
|
|
""" Load a nuclear spin readout asset. """ |
|
1723
|
|
|
#FIXME: Move this creation routine to the tasks! |
|
1724
|
|
|
|
|
1725
|
|
|
self._seq_gen_logic.load_asset(asset_name='SSR') |
|
1726
|
|
|
|
|
1727
|
|
|
def _pulser_on(self): |
|
1728
|
|
|
""" Switch on the pulser output. """ |
|
1729
|
|
View Code Duplication |
|
|
|
|
|
|
|
1730
|
|
|
self._set_channel_activation(active=True, apply_to_device=True) |
|
1731
|
|
|
self._seq_gen_logic.pulser_on() |
|
1732
|
|
|
|
|
1733
|
|
|
def _pulser_off(self): |
|
1734
|
|
|
""" Switch off the pulser output. """ |
|
1735
|
|
|
|
|
1736
|
|
|
self._set_channel_activation(active=False, apply_to_device=False) |
|
1737
|
|
|
self._seq_gen_logic.pulser_off() |
|
1738
|
|
|
|
|
1739
|
|
|
def _set_channel_activation(self, active=True, apply_to_device=False): |
|
1740
|
|
|
""" Set the channels according to the current activation config to be either active or not. |
|
1741
|
|
|
|
|
1742
|
|
|
@param bool active: the activation according to the current activation |
|
1743
|
|
|
config will be checked and if channel |
|
1744
|
|
|
is not active and active=True, then channel will be |
|
1745
|
|
|
activated. Otherwise if channel is active and |
|
1746
|
|
|
active=False channel will be deactivated. |
|
1747
|
|
|
All other channels, which are not in activation |
|
1748
|
|
|
config will be deactivated if they are not already |
|
1749
|
|
|
deactivated. |
|
1750
|
|
|
@param bool apply_to_device: Apply the activation or deactivation of the |
|
1751
|
|
|
current activation_config either to the |
|
1752
|
|
|
device and the viewboxes, or just to the |
|
1753
|
|
|
viewboxes. |
|
1754
|
|
|
""" |
|
1755
|
|
|
|
|
1756
|
|
|
pulser_const = self._seq_gen_logic.get_hardware_constraints() |
|
1757
|
|
|
|
|
1758
|
|
|
curr_config_name = self._seq_gen_logic.current_activation_config_name |
|
1759
|
|
|
activation_config = pulser_const['activation_config'][curr_config_name] |
|
1760
|
|
|
|
|
1761
|
|
|
# here is the current activation pattern of the pulse device: |
|
1762
|
|
|
active_ch = self._seq_gen_logic.get_active_channels() |
|
1763
|
|
|
|
|
1764
|
|
|
ch_to_change = {} # create something like a_ch = {1:True, 2:True} to switch |
|
1765
|
|
|
|
|
1766
|
|
|
# check whether the correct channels are already active, and if not |
|
1767
|
|
|
# correct for that and activate and deactivate the appropriate ones: |
|
1768
|
|
|
available_ch = self._get_available_ch() |
|
1769
|
|
|
for ch_name in available_ch: |
|
1770
|
|
|
|
|
1771
|
|
|
# if the channel is in the activation, check whether it is active: |
|
1772
|
|
|
if ch_name in activation_config: |
|
1773
|
|
|
|
|
1774
|
|
|
if apply_to_device: |
|
1775
|
|
|
# if channel is not active but activation is needed (active=True), |
|
1776
|
|
|
# then add that to ch_to_change to change the state of the channels: |
|
1777
|
|
|
if not active_ch[ch_name] and active: |
|
1778
|
|
|
ch_to_change[ch_name] = active |
|
1779
|
|
|
|
|
1780
|
|
|
# if channel is active but deactivation is needed (active=False), |
|
1781
|
|
|
# then add that to ch_to_change to change the state of the channels: |
|
1782
|
|
|
if active_ch[ch_name] and not active: |
|
1783
|
|
View Code Duplication |
ch_to_change[ch_name] = active |
|
|
|
|
|
|
1784
|
|
|
|
|
1785
|
|
|
|
|
1786
|
|
|
else: |
|
1787
|
|
|
# all other channel which are active should be deactivated: |
|
1788
|
|
|
if active_ch[ch_name]: |
|
1789
|
|
|
ch_to_change[ch_name] = False |
|
1790
|
|
|
|
|
1791
|
|
|
self._seq_gen_logic.set_active_channels(ch_to_change) |
|
1792
|
|
|
|
|
1793
|
|
|
def _get_available_ch(self): |
|
1794
|
|
|
""" Helper method to get a list of all available channels. |
|
1795
|
|
|
|
|
1796
|
|
|
@return list: entries are the generic string names of the channels. |
|
1797
|
|
|
""" |
|
1798
|
|
|
config = self._seq_gen_logic.get_hardware_constraints()['activation_config'] |
|
1799
|
|
|
|
|
1800
|
|
|
available_ch = [] |
|
1801
|
|
|
all_a_ch = [] |
|
1802
|
|
|
all_d_ch = [] |
|
1803
|
|
|
for conf in config: |
|
1804
|
|
|
|
|
1805
|
|
|
# extract all analog channels from the config |
|
1806
|
|
|
curr_a_ch = [entry for entry in config[conf] if 'a_ch' in entry] |
|
1807
|
|
|
curr_d_ch = [entry for entry in config[conf] if 'd_ch' in entry] |
|
1808
|
|
|
|
|
1809
|
|
|
# append all new analog channels to a temporary array |
|
1810
|
|
|
for a_ch in curr_a_ch: |
|
1811
|
|
|
if a_ch not in all_a_ch: |
|
1812
|
|
|
all_a_ch.append(a_ch) |
|
1813
|
|
|
|
|
1814
|
|
|
# append all new digital channels to a temporary array |
|
1815
|
|
|
for d_ch in curr_d_ch: |
|
1816
|
|
|
if d_ch not in all_d_ch: |
|
1817
|
|
|
all_d_ch.append(d_ch) |
|
1818
|
|
|
|
|
1819
|
|
|
all_a_ch.sort() |
|
1820
|
|
|
all_d_ch.sort() |
|
1821
|
|
|
available_ch.extend(all_a_ch) |
|
1822
|
|
|
available_ch.extend(all_d_ch) |
|
1823
|
|
|
|
|
1824
|
|
|
return available_ch |
|
1825
|
|
|
|
|
1826
|
|
|
def _do_postmeasurement_proc(self): |
|
1827
|
|
|
|
|
1828
|
|
|
# do a selected post measurement procedure, |
|
1829
|
|
|
|
|
1830
|
|
|
return |
|
1831
|
|
|
|
|
1832
|
|
|
|
|
1833
|
|
|
def get_available_odmr_peaks(self): |
|
1834
|
|
|
""" Retrieve the information on which odmr peak the microwave can be |
|
1835
|
|
|
applied. |
|
1836
|
|
|
|
|
1837
|
|
|
@return list: with string entries denoting the peak number |
|
1838
|
|
|
""" |
|
1839
|
|
|
return [1, 2, 3] |
|
1840
|
|
|
|
|
1841
|
|
|
def save_1d_data(self): |
|
1842
|
|
|
|
|
1843
|
|
|
|
|
1844
|
|
|
# save also all kinds of data, which are the results during the |
|
1845
|
|
|
# alignment measurements |
|
1846
|
|
|
|
|
1847
|
|
|
pass |
|
1848
|
|
|
|
|
1849
|
|
|
|
|
1850
|
|
|
def save_2d_data(self, tag=None, timestamp=None): |
|
1851
|
|
|
""" Save the data of the """ |
|
1852
|
|
|
|
|
1853
|
|
|
filepath = self._save_logic.get_path_for_module(module_name='Magnet') |
|
1854
|
|
|
|
|
1855
|
|
|
if timestamp is None: |
|
1856
|
|
|
timestamp = datetime.datetime.now() |
|
1857
|
|
|
|
|
1858
|
|
|
# if tag is not None and len(tag) > 0: |
|
1859
|
|
|
# filelabel = tag + '_magnet_alignment_data' |
|
1860
|
|
|
# filelabel2 = tag + '_magnet_alignment_add_data' |
|
1861
|
|
|
# else: |
|
1862
|
|
|
# filelabel = 'magnet_alignment_data' |
|
1863
|
|
|
# filelabel2 = 'magnet_alignment_add_data' |
|
1864
|
|
|
|
|
1865
|
|
|
if tag is not None and len(tag) > 0: |
|
1866
|
|
|
filelabel = tag + '_magnet_alignment_data' |
|
1867
|
|
|
filelabel2 = tag + '_magnet_alignment_add_data' |
|
1868
|
|
|
filelabel3 = tag + '_magnet_alignment_data_table' |
|
1869
|
|
|
else: |
|
1870
|
|
|
filelabel = 'magnet_alignment_data' |
|
1871
|
|
|
filelabel2 = 'magnet_alignment_add_data' |
|
1872
|
|
|
filelabel3 = 'magnet_alignment_data_table' |
|
1873
|
|
|
|
|
1874
|
|
|
# prepare the data in a dict or in an OrderedDict: |
|
1875
|
|
|
|
|
1876
|
|
|
# here is the matrix saved |
|
1877
|
|
|
matrix_data = OrderedDict() |
|
1878
|
|
|
|
|
1879
|
|
|
# here are all the parameters, which are saved for a certain matrix |
|
1880
|
|
|
# entry, mainly coming from all the other logic modules except the magnet logic: |
|
1881
|
|
|
add_matrix_data = OrderedDict() |
|
1882
|
|
|
|
|
1883
|
|
|
# here are all supplementary information about the measurement, mainly |
|
1884
|
|
|
# from the magnet logic |
|
1885
|
|
|
supplementary_data = OrderedDict() |
|
1886
|
|
|
|
|
1887
|
|
|
axes_names = list(self._saved_pos_before_align) |
|
1888
|
|
|
|
|
1889
|
|
|
|
|
1890
|
|
|
matrix_data['Alignment Matrix'] = self._2D_data_matrix |
|
1891
|
|
|
|
|
1892
|
|
|
parameters = OrderedDict() |
|
1893
|
|
|
parameters['Measurement start time'] = self._start_measurement_time |
|
1894
|
|
|
if self._stop_measurement_time is not None: |
|
1895
|
|
|
parameters['Measurement stop time'] = self._stop_measurement_time |
|
1896
|
|
|
parameters['Time at Data save'] = timestamp |
|
1897
|
|
|
parameters['Pathway of the magnet alignment'] = 'Snake-wise steps' |
|
1898
|
|
|
|
|
1899
|
|
|
for index, entry in enumerate(self._pathway): |
|
1900
|
|
|
parameters['index_'+str(index)] = entry |
|
1901
|
|
|
|
|
1902
|
|
|
parameters['Backmap of the magnet alignment'] = 'Index wise display' |
|
1903
|
|
|
|
|
1904
|
|
|
for entry in self._backmap: |
|
1905
|
|
|
parameters['related_intex_'+str(entry)] = self._backmap[entry] |
|
1906
|
|
|
|
|
1907
|
|
|
|
|
1908
|
|
|
|
|
1909
|
|
|
self._save_logic.save_data(matrix_data, filepath, parameters=parameters, |
|
1910
|
|
|
filelabel=filelabel, timestamp=timestamp, |
|
1911
|
|
|
as_text=True) |
|
1912
|
|
|
|
|
1913
|
|
|
self.log.debug('Magnet 2D data saved to:\n{0}'.format(filepath)) |
|
1914
|
|
|
|
|
1915
|
|
|
# prepare the data in a dict or in an OrderedDict: |
|
1916
|
|
|
add_data = OrderedDict() |
|
1917
|
|
|
axis0_data = np.zeros(len(self._backmap)) |
|
1918
|
|
|
axis1_data = np.zeros(len(self._backmap)) |
|
1919
|
|
|
param_data = np.zeros(len(self._backmap), dtype='object') |
|
1920
|
|
|
|
|
1921
|
|
|
for backmap_index in self._backmap: |
|
1922
|
|
|
axis0_data[backmap_index] = self._backmap[backmap_index][self._axis0_name] |
|
1923
|
|
|
axis1_data[backmap_index] = self._backmap[backmap_index][self._axis1_name] |
|
1924
|
|
|
param_data[backmap_index] = str(self._2D_add_data_matrix[self._backmap[backmap_index]['index']]) |
|
1925
|
|
|
|
|
1926
|
|
|
constr = self.get_hardware_constraints() |
|
1927
|
|
|
units_axis0 = constr[self._axis0_name]['unit'] |
|
1928
|
|
|
units_axis1 = constr[self._axis1_name]['unit'] |
|
1929
|
|
|
|
|
1930
|
|
|
add_data['{0} values ({1})'.format(self._axis0_name, units_axis0)] = axis0_data |
|
1931
|
|
|
add_data['{0} values ({1})'.format(self._axis1_name, units_axis1)] = axis1_data |
|
1932
|
|
|
add_data['all measured additional parameter'] = param_data |
|
1933
|
|
|
|
|
1934
|
|
|
|
|
1935
|
|
|
|
|
1936
|
|
|
self._save_logic.save_data(add_data, filepath, |
|
1937
|
|
|
filelabel=filelabel2, timestamp=timestamp, |
|
1938
|
|
|
as_text=True) |
|
1939
|
|
|
# save the data table |
|
1940
|
|
|
|
|
1941
|
|
|
count_data = self._2D_data_matrix |
|
1942
|
|
|
x_val = self._2D_axis0_data |
|
1943
|
|
|
y_val = self._2D_axis1_data |
|
1944
|
|
|
save_dict = OrderedDict() |
|
1945
|
|
|
axis0_key = '{0} values ({1})'.format(self._axis0_name, units_axis0) |
|
1946
|
|
|
axis1_key = '{0} values ({1})'.format(self._axis1_name, units_axis1) |
|
1947
|
|
|
counts_key = 'counts (c/s)' |
|
1948
|
|
|
save_dict[axis0_key] = [] |
|
1949
|
|
|
save_dict[axis1_key] = [] |
|
1950
|
|
|
save_dict[counts_key] = [] |
|
1951
|
|
|
|
|
1952
|
|
|
for ii, columns in enumerate(count_data): |
|
1953
|
|
|
for jj, col_counts in enumerate(columns): |
|
1954
|
|
|
# x_list = [x_val[ii]] * len(countlist) |
|
1955
|
|
|
save_dict[axis0_key].append(x_val[ii]) |
|
1956
|
|
|
save_dict[axis1_key].append(y_val[jj]) |
|
1957
|
|
|
save_dict[counts_key].append(col_counts) |
|
1958
|
|
|
|
|
1959
|
|
|
self._save_logic.save_data(save_dict, filepath, |
|
1960
|
|
|
filelabel=filelabel3, timestamp=timestamp, |
|
1961
|
|
|
as_text=True) |
|
1962
|
|
|
|
|
1963
|
|
|
|
|
1964
|
|
|
def _move_to_index(self, pathway_index, pathway): |
|
1965
|
|
|
|
|
1966
|
|
|
# make here the move and set also for the move the velocity, if |
|
1967
|
|
|
# specified! |
|
1968
|
|
|
|
|
1969
|
|
|
move_commmands = pathway[pathway_index] |
|
1970
|
|
|
|
|
1971
|
|
|
move_dict_abs = dict() |
|
1972
|
|
|
move_dict_rel = dict() |
|
1973
|
|
|
move_dict_vel = dict() |
|
1974
|
|
|
|
|
1975
|
|
|
for axis_name in move_commmands: |
|
1976
|
|
|
|
|
1977
|
|
|
if move_commmands[axis_name].get('vel') is not None: |
|
1978
|
|
|
move_dict_vel[axis_name] = move_commmands[axis_name]['vel'] |
|
1979
|
|
|
|
|
1980
|
|
|
if move_commmands[axis_name].get('move_abs') is not None: |
|
1981
|
|
|
move_dict_abs[axis_name] = move_commmands[axis_name]['move_abs'] |
|
1982
|
|
|
elif move_commmands[axis_name].get('move_rel') is not None: |
|
1983
|
|
|
move_dict_rel[axis_name] = move_commmands[axis_name]['move_rel'] |
|
1984
|
|
|
|
|
1985
|
|
|
return move_dict_vel, move_dict_abs, move_dict_rel |
|
1986
|
|
|
|
|
1987
|
|
|
def set_pos_checktime(self, checktime): |
|
1988
|
|
|
if not np.isclose(0, checktime) and checktime>0: |
|
1989
|
|
|
self._checktime = checktime |
|
1990
|
|
|
else: |
|
1991
|
|
|
self.log.warning('Could not set a new value for checktime, since ' |
|
1992
|
|
|
'the passed value "{0}" is either zero or negative!\n' |
|
1993
|
|
|
'Choose a proper checktime value in seconds, the old ' |
|
1994
|
|
|
'value will be kept!') |
|
1995
|
|
|
|
|
1996
|
|
|
|
|
1997
|
|
|
def get_2d_data_matrix(self): |
|
1998
|
|
|
return self._2D_data_matrix |
|
1999
|
|
|
|
|
2000
|
|
|
def get_2d_axis_arrays(self): |
|
2001
|
|
|
return self._2D_axis0_data, self._2D_axis1_data |
|
2002
|
|
|
|
|
2003
|
|
|
def set_optimize_pos(self, state=True): |
|
2004
|
|
|
""" Activate the optimize position option. """ |
|
2005
|
|
|
self._optimize_pos = state |
|
2006
|
|
|
|
|
2007
|
|
|
def get_optimize_pos(self): |
|
2008
|
|
|
""" Retrieve whether the optimize position is set. |
|
2009
|
|
|
|
|
2010
|
|
|
@return bool: whether the optimize_pos is set or not. |
|
2011
|
|
|
""" |
|
2012
|
|
|
return self._optimize_pos |
|
2013
|
|
|
|