Completed
Push — master ( f73b00...0f9f1e )
by Jan
01:12
created

ODMRGui.update_colorbar()   A

Complexity

Conditions 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
"""
3
This file contains the Qudi GUI module for ODMR control.
4
5
Qudi is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Qudi is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with Qudi. If not, see <http://www.gnu.org/licenses/>.
17
18
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the
19
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/>
20
"""
21
22
23
import numpy as np
24
import os
25
import pyqtgraph as pg
26
27
from core.module import Connector
28
from core.util import units
29
from gui.guibase import GUIBase
30
from gui.guiutils import ColorBar
31
from gui.colordefs import ColorScaleInferno
32
from gui.colordefs import QudiPalettePale as palette
33
from gui.fitsettings import FitSettingsDialog, FitSettingsComboBox
34
from qtpy import QtCore
35
from qtpy import QtWidgets
36
from qtpy import uic
37
38
39
class ODMRMainWindow(QtWidgets.QMainWindow):
40
    """ The main window for the ODMR measurement GUI.
41
    """
42
    def __init__(self):
43
        # Get the path to the *.ui file
44
        this_dir = os.path.dirname(__file__)
45
        ui_file = os.path.join(this_dir, 'ui_odmrgui.ui')
46
47
        # Load it
48
        super(ODMRMainWindow, self).__init__()
49
        uic.loadUi(ui_file, self)
50
        self.show()
51
52
53
class ODMRSettingDialog(QtWidgets.QDialog):
54
    """ The settings dialog for ODMR measurements.
55
    """
56
    def __init__(self):
57
        # Get the path to the *.ui file
58
        this_dir = os.path.dirname(__file__)
59
        ui_file = os.path.join(this_dir, 'ui_odmr_settings.ui')
60
61
        # Load it
62
        super(ODMRSettingDialog, self).__init__()
63
        uic.loadUi(ui_file, self)
64
65
66
class ODMRGui(GUIBase):
67
    """
68
    This is the GUI Class for ODMR measurements
69
    """
70
71
    _modclass = 'ODMRGui'
72
    _modtype = 'gui'
73
74
    # declare connectors
75
    odmrlogic1 = Connector(interface='ODMRLogic')
76
    savelogic = Connector(interface='SaveLogic')
77
78
    sigStartOdmrScan = QtCore.Signal()
79
    sigStopOdmrScan = QtCore.Signal()
80
    sigContinueOdmrScan = QtCore.Signal()
81
    sigClearData = QtCore.Signal()
82
    sigCwMwOn = QtCore.Signal()
83
    sigMwOff = QtCore.Signal()
84
    sigMwPowerChanged = QtCore.Signal(float)
85
    sigMwCwParamsChanged = QtCore.Signal(float, float)
86
    sigMwSweepParamsChanged = QtCore.Signal(float, float, float, float)
87
    sigClockFreqChanged = QtCore.Signal(float)
88
    sigFitChanged = QtCore.Signal(str)
89
    sigNumberOfLinesChanged = QtCore.Signal(int)
90
    sigRuntimeChanged = QtCore.Signal(float)
91
    sigDoFit = QtCore.Signal(str, object, object, int)
92
    sigSaveMeasurement = QtCore.Signal(str, list, list)
93
94
    def __init__(self, config, **kwargs):
95
        super().__init__(config=config, **kwargs)
96
97
    def on_activate(self):
98
        """ Definition, configuration and initialisation of the ODMR GUI.
99
100
        This init connects all the graphic modules, which were created in the
101
        *.ui file and configures the event handling between the modules.
102
        """
103
104
        self._odmr_logic = self.odmrlogic1()
105
106
        # Use the inherited class 'Ui_ODMRGuiUI' to create now the GUI element:
107
        self._mw = ODMRMainWindow()
108
        self._sd = ODMRSettingDialog()
109
110
        # Create a QSettings object for the mainwindow and store the actual GUI layout
111
        self.mwsettings = QtCore.QSettings("QUDI", "ODMR")
112
        self.mwsettings.setValue("geometry", self._mw.saveGeometry())
113
        self.mwsettings.setValue("windowState", self._mw.saveState())
114
115
        # Get hardware constraints to set limits for input widgets
116
        constraints = self._odmr_logic.get_hw_constraints()
117
118
        # Adjust range of scientific spinboxes above what is possible in Qt Designer
119
        self._mw.cw_frequency_DoubleSpinBox.setMaximum(constraints.max_frequency)
120
        self._mw.cw_frequency_DoubleSpinBox.setMinimum(constraints.min_frequency)
121
        self._mw.start_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
122
        self._mw.start_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
123
        self._mw.step_freq_DoubleSpinBox.setMaximum(100e9)
124
        self._mw.stop_freq_DoubleSpinBox.setMaximum(constraints.max_frequency)
125
        self._mw.stop_freq_DoubleSpinBox.setMinimum(constraints.min_frequency)
126
        self._mw.cw_power_DoubleSpinBox.setMaximum(constraints.max_power)
127
        self._mw.cw_power_DoubleSpinBox.setMinimum(constraints.min_power)
128
        self._mw.sweep_power_DoubleSpinBox.setMaximum(constraints.max_power)
129
        self._mw.sweep_power_DoubleSpinBox.setMinimum(constraints.min_power)
130
131
        # Add save file tag input box
132
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit(self._mw)
133
        self._mw.save_tag_LineEdit.setMaximumWidth(500)
134
        self._mw.save_tag_LineEdit.setMinimumWidth(200)
135
        self._mw.save_tag_LineEdit.setToolTip('Enter a nametag which will be\n'
136
                                              'added to the filename.')
137
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)
138
139
        # add a clear button to clear the ODMR plots:
140
        self._mw.clear_odmr_PushButton = QtWidgets.QPushButton(self._mw)
141
        self._mw.clear_odmr_PushButton.setText('Clear ODMR')
142
        self._mw.clear_odmr_PushButton.setToolTip('Clear the data of the\n'
143
                                                  'current ODMR measurements.')
144
        self._mw.clear_odmr_PushButton.setEnabled(False)
145
        self._mw.toolBar.addWidget(self._mw.clear_odmr_PushButton)
146
147
        # Set up and connect channel combobox
148
        self.display_channel = 0
149
        odmr_channels = self._odmr_logic.get_odmr_channels()
150
        for n, ch in enumerate(odmr_channels):
151
            self._mw.odmr_channel_ComboBox.addItem(str(ch), n)
152
153
        self._mw.odmr_channel_ComboBox.activated.connect(self.update_channel)
154
155
        # Get the image from the logic
156
        self.odmr_matrix_image = pg.ImageItem(
157
            self._odmr_logic.odmr_plot_xy[:, self.display_channel],
158
            axisOrder='row-major')
159
        self.odmr_matrix_image.setRect(QtCore.QRectF(
160
                self._odmr_logic.mw_start,
161
                0,
162
                self._odmr_logic.mw_stop - self._odmr_logic.mw_start,
163
                self._odmr_logic.number_of_lines
164
            ))
165
166
        self.odmr_image = pg.PlotDataItem(self._odmr_logic.odmr_plot_x,
167
                                          self._odmr_logic.odmr_plot_y[self.display_channel],
168
                                          pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
169
                                          symbol='o',
170
                                          symbolPen=palette.c1,
171
                                          symbolBrush=palette.c1,
172
                                          symbolSize=7)
173
174
        self.odmr_fit_image = pg.PlotDataItem(self._odmr_logic.odmr_fit_x,
175
                                              self._odmr_logic.odmr_fit_y,
176
                                              pen=pg.mkPen(palette.c2))
177
178
        # Add the display item to the xy and xz ViewWidget, which was defined in the UI file.
179
        self._mw.odmr_PlotWidget.addItem(self.odmr_image)
180
        self._mw.odmr_PlotWidget.setLabel(axis='left', text='Counts', units='Counts/s')
181
        self._mw.odmr_PlotWidget.setLabel(axis='bottom', text='Frequency', units='Hz')
182
        self._mw.odmr_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
183
184
        self._mw.odmr_matrix_PlotWidget.addItem(self.odmr_matrix_image)
185
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='left', text='Matrix Lines', units='#')
186
        self._mw.odmr_matrix_PlotWidget.setLabel(axis='bottom', text='Frequency', units='Hz')
187
188
        # Get the colorscales at set LUT
189
        my_colors = ColorScaleInferno()
190
        self.odmr_matrix_image.setLookupTable(my_colors.lut)
191
192
        ########################################################################
193
        #                  Configuration of the Colorbar                       #
194
        ########################################################################
195
        self.odmr_cb = ColorBar(my_colors.cmap_normed, 100, 0, 100000)
196
197
        # adding colorbar to ViewWidget
198
        self._mw.odmr_cb_PlotWidget.addItem(self.odmr_cb)
199
        self._mw.odmr_cb_PlotWidget.hideAxis('bottom')
200
        self._mw.odmr_cb_PlotWidget.hideAxis('left')
201
        self._mw.odmr_cb_PlotWidget.setLabel('right', 'Fluorescence', units='counts/s')
202
203
        ########################################################################
204
        #          Configuration of the various display Widgets                #
205
        ########################################################################
206
        # Take the default values from logic:
207
        self._mw.cw_frequency_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_frequency)
208
        self._mw.start_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_start)
209
        self._mw.stop_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_stop)
210
        self._mw.step_freq_DoubleSpinBox.setValue(self._odmr_logic.mw_step)
211
        self._mw.cw_power_DoubleSpinBox.setValue(self._odmr_logic.cw_mw_power)
212
        self._mw.sweep_power_DoubleSpinBox.setValue(self._odmr_logic.sweep_mw_power)
213
214
        self._mw.runtime_DoubleSpinBox.setValue(self._odmr_logic.run_time)
215
        self._mw.elapsed_time_DisplayWidget.display(int(np.rint(self._odmr_logic.elapsed_time)))
216
        self._mw.elapsed_sweeps_DisplayWidget.display(self._odmr_logic.elapsed_sweeps)
217
218
        self._sd.matrix_lines_SpinBox.setValue(self._odmr_logic.number_of_lines)
219
        self._sd.clock_frequency_DoubleSpinBox.setValue(self._odmr_logic.clock_frequency)
220
221
        # fit settings
222
        self._fsd = FitSettingsDialog(self._odmr_logic.fc)
223
        self._fsd.sigFitsUpdated.connect(self._mw.fit_methods_ComboBox.setFitFunctions)
224
        self._fsd.applySettings()
225
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)
226
227
        ########################################################################
228
        #                       Connect signals                                #
229
        ########################################################################
230
        # Internal user input changed signals
231
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.connect(self.change_cw_params)
232
        self._mw.start_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
233
        self._mw.step_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
234
        self._mw.stop_freq_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
235
        self._mw.sweep_power_DoubleSpinBox.editingFinished.connect(self.change_sweep_params)
236
        self._mw.cw_power_DoubleSpinBox.editingFinished.connect(self.change_cw_params)
237
        self._mw.runtime_DoubleSpinBox.editingFinished.connect(self.change_runtime)
238
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
239
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
240
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
241
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.connect(self.colorscale_changed)
242
        # Internal trigger signals
243
        self._mw.odmr_cb_manual_RadioButton.clicked.connect(self.colorscale_changed)
244
        self._mw.odmr_cb_centiles_RadioButton.clicked.connect(self.colorscale_changed)
245
        self._mw.clear_odmr_PushButton.clicked.connect(self.clear_odmr_data)
246
        self._mw.action_run_stop.triggered.connect(self.run_stop_odmr)
247
        self._mw.action_resume_odmr.triggered.connect(self.resume_odmr)
248
        self._mw.action_toggle_cw.triggered.connect(self.toggle_cw_mode)
249
        self._mw.action_Save.triggered.connect(self.save_data)
250
        self._mw.action_RestoreDefault.triggered.connect(self.restore_defaultview)
251
        self._mw.do_fit_PushButton.clicked.connect(self.do_fit)
252
253
        # Control/values-changed signals to logic
254
        self.sigCwMwOn.connect(self._odmr_logic.mw_cw_on, QtCore.Qt.QueuedConnection)
255
        self.sigMwOff.connect(self._odmr_logic.mw_off, QtCore.Qt.QueuedConnection)
256
        self.sigClearData.connect(self._odmr_logic.clear_odmr_data, QtCore.Qt.QueuedConnection)
257
        self.sigStartOdmrScan.connect(self._odmr_logic.start_odmr_scan, QtCore.Qt.QueuedConnection)
258
        self.sigStopOdmrScan.connect(self._odmr_logic.stop_odmr_scan, QtCore.Qt.QueuedConnection)
259
        self.sigContinueOdmrScan.connect(self._odmr_logic.continue_odmr_scan,
260
                                         QtCore.Qt.QueuedConnection)
261
        self.sigDoFit.connect(self._odmr_logic.do_fit, QtCore.Qt.QueuedConnection)
262
        self.sigMwCwParamsChanged.connect(self._odmr_logic.set_cw_parameters,
263
                                          QtCore.Qt.QueuedConnection)
264
        self.sigMwSweepParamsChanged.connect(self._odmr_logic.set_sweep_parameters,
265
                                             QtCore.Qt.QueuedConnection)
266
        self.sigRuntimeChanged.connect(self._odmr_logic.set_runtime, QtCore.Qt.QueuedConnection)
267
        self.sigNumberOfLinesChanged.connect(self._odmr_logic.set_matrix_line_number,
268
                                             QtCore.Qt.QueuedConnection)
269
        self.sigClockFreqChanged.connect(self._odmr_logic.set_clock_frequency,
270
                                         QtCore.Qt.QueuedConnection)
271
        self.sigSaveMeasurement.connect(self._odmr_logic.save_odmr_data, QtCore.Qt.QueuedConnection)
272
273
        # Update signals coming from logic:
274
        self._odmr_logic.sigParameterUpdated.connect(self.update_parameter,
275
                                                     QtCore.Qt.QueuedConnection)
276
        self._odmr_logic.sigOutputStateUpdated.connect(self.update_status,
277
                                                       QtCore.Qt.QueuedConnection)
278
        self._odmr_logic.sigOdmrPlotsUpdated.connect(self.update_plots, QtCore.Qt.QueuedConnection)
279
        self._odmr_logic.sigOdmrFitUpdated.connect(self.update_fit, QtCore.Qt.QueuedConnection)
280
        self._odmr_logic.sigOdmrElapsedTimeUpdated.connect(self.update_elapsedtime,
281
                                                           QtCore.Qt.QueuedConnection)
282
283
        # connect settings signals
284
        self._mw.action_Settings.triggered.connect(self._menu_settings)
285
        self._sd.accepted.connect(self.update_settings)
286
        self._sd.rejected.connect(self.reject_settings)
287
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
288
            self.update_settings)
289
        self.reject_settings()
290
291
        # Show the Main ODMR GUI:
292
        self.show()
293
294
    def on_deactivate(self):
295
        """ Reverse steps of activation
296
297
        @return int: error code (0:OK, -1:error)
298
        """
299
        # Disconnect signals
300
        self._sd.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
301
        self._sd.accepted.disconnect()
302
        self._sd.rejected.disconnect()
303
        self._mw.action_Settings.triggered.disconnect()
304
        self._odmr_logic.sigParameterUpdated.disconnect()
305
        self._odmr_logic.sigOutputStateUpdated.disconnect()
306
        self._odmr_logic.sigOdmrPlotsUpdated.disconnect()
307
        self._odmr_logic.sigOdmrFitUpdated.disconnect()
308
        self._odmr_logic.sigOdmrElapsedTimeUpdated.disconnect()
309
        self.sigCwMwOn.disconnect()
310
        self.sigMwOff.disconnect()
311
        self.sigClearData.disconnect()
312
        self.sigStartOdmrScan.disconnect()
313
        self.sigStopOdmrScan.disconnect()
314
        self.sigContinueOdmrScan.disconnect()
315
        self.sigDoFit.disconnect()
316
        self.sigMwCwParamsChanged.disconnect()
317
        self.sigMwSweepParamsChanged.disconnect()
318
        self.sigRuntimeChanged.disconnect()
319
        self.sigNumberOfLinesChanged.disconnect()
320
        self.sigClockFreqChanged.disconnect()
321
        self.sigSaveMeasurement.disconnect()
322
        self._mw.odmr_cb_manual_RadioButton.clicked.disconnect()
323
        self._mw.odmr_cb_centiles_RadioButton.clicked.disconnect()
324
        self._mw.clear_odmr_PushButton.clicked.disconnect()
325
        self._mw.action_run_stop.triggered.disconnect()
326
        self._mw.action_resume_odmr.triggered.disconnect()
327
        self._mw.action_Save.triggered.disconnect()
328
        self._mw.action_toggle_cw.triggered.disconnect()
329
        self._mw.action_RestoreDefault.triggered.disconnect()
330
        self._mw.do_fit_PushButton.clicked.disconnect()
331
        self._mw.cw_frequency_DoubleSpinBox.editingFinished.disconnect()
332
        self._mw.start_freq_DoubleSpinBox.editingFinished.disconnect()
333
        self._mw.step_freq_DoubleSpinBox.editingFinished.disconnect()
334
        self._mw.stop_freq_DoubleSpinBox.editingFinished.disconnect()
335
        self._mw.cw_power_DoubleSpinBox.editingFinished.disconnect()
336
        self._mw.sweep_power_DoubleSpinBox.editingFinished.disconnect()
337
        self._mw.runtime_DoubleSpinBox.editingFinished.disconnect()
338
        self._mw.odmr_cb_max_DoubleSpinBox.valueChanged.disconnect()
339
        self._mw.odmr_cb_min_DoubleSpinBox.valueChanged.disconnect()
340
        self._mw.odmr_cb_high_percentile_DoubleSpinBox.valueChanged.disconnect()
341
        self._mw.odmr_cb_low_percentile_DoubleSpinBox.valueChanged.disconnect()
342
        self._fsd.sigFitsUpdated.disconnect()
343
        self._mw.action_FitSettings.triggered.disconnect()
344
        self._mw.close()
345
        return 0
346
347
    def show(self):
348
        """Make window visible and put it above all other windows. """
349
        self._mw.show()
350
        self._mw.activateWindow()
351
        self._mw.raise_()
352
353
    def _menu_settings(self):
354
        """ Open the settings menu """
355 View Code Duplication
        self._sd.exec_()
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
356
357
    def run_stop_odmr(self, is_checked):
358
        """ Manages what happens if odmr scan is started/stopped. """
359
        if is_checked:
360
            # change the axes appearance according to input values:
361
            self._mw.action_run_stop.setEnabled(False)
362
            self._mw.action_resume_odmr.setEnabled(False)
363
            self._mw.action_toggle_cw.setEnabled(False)
364
            self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)
365
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
366
            self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
367
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
368
            self._mw.start_freq_DoubleSpinBox.setEnabled(False)
369
            self._mw.step_freq_DoubleSpinBox.setEnabled(False)
370
            self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
371
            self._mw.runtime_DoubleSpinBox.setEnabled(False)
372
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
373
            self.sigStartOdmrScan.emit()
374
        else:
375
            self._mw.action_run_stop.setEnabled(False)
376
            self._mw.action_resume_odmr.setEnabled(False)
377
            self._mw.action_toggle_cw.setEnabled(False)
378 View Code Duplication
            self.sigStopOdmrScan.emit()
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
379
        return
380
381
    def resume_odmr(self, is_checked):
382
        if is_checked:
383
            self._mw.action_run_stop.setEnabled(False)
384
            self._mw.action_resume_odmr.setEnabled(False)
385
            self._mw.action_toggle_cw.setEnabled(False)
386
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
387
            self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
388
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
389
            self._mw.start_freq_DoubleSpinBox.setEnabled(False)
390
            self._mw.step_freq_DoubleSpinBox.setEnabled(False)
391
            self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
392
            self._mw.runtime_DoubleSpinBox.setEnabled(False)
393
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
394
            self.sigContinueOdmrScan.emit()
395
        else:
396
            self._mw.action_run_stop.setEnabled(False)
397
            self._mw.action_resume_odmr.setEnabled(False)
398
            self._mw.action_toggle_cw.setEnabled(False)
399
            self.sigStopOdmrScan.emit()
400
        return
401
402
    def toggle_cw_mode(self, is_checked):
403
        """ Starts or stops CW microwave output if no measurement is running. """
404
        if is_checked:
405
            self._mw.action_run_stop.setEnabled(False)
406
            self._mw.action_resume_odmr.setEnabled(False)
407
            self._mw.action_toggle_cw.setEnabled(False)
408
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
409
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
410
            self.sigCwMwOn.emit()
411
        else:
412
            self._mw.action_toggle_cw.setEnabled(False)
413
            self.sigMwOff.emit()
414
        return
415
416
    def update_status(self, mw_mode, is_running):
417
        """
418
        Update the display for a change in the microwave status (mode and output).
419
420
        @param str mw_mode: is the microwave output active?
421
        @param bool is_running: is the microwave output active?
422
        """
423
        # Block signals from firing
424
        self._mw.action_run_stop.blockSignals(True)
425
        self._mw.action_resume_odmr.blockSignals(True)
426
        self._mw.action_toggle_cw.blockSignals(True)
427
428
        # Update measurement status (activate/deactivate widgets/actions)
429
        if is_running:
430
            self._mw.action_resume_odmr.setEnabled(False)
431
            self._mw.cw_power_DoubleSpinBox.setEnabled(False)
432
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(False)
433
            if mw_mode != 'cw':
434
                self._mw.clear_odmr_PushButton.setEnabled(True)
435
                self._mw.action_run_stop.setEnabled(True)
436
                self._mw.action_toggle_cw.setEnabled(False)
437
                self._mw.start_freq_DoubleSpinBox.setEnabled(False)
438
                self._mw.step_freq_DoubleSpinBox.setEnabled(False)
439
                self._mw.stop_freq_DoubleSpinBox.setEnabled(False)
440
                self._mw.sweep_power_DoubleSpinBox.setEnabled(False)
441
                self._mw.runtime_DoubleSpinBox.setEnabled(False)
442
                self._sd.clock_frequency_DoubleSpinBox.setEnabled(False)
443
                self._mw.action_run_stop.setChecked(True)
444
                self._mw.action_resume_odmr.setChecked(True)
445
                self._mw.action_toggle_cw.setChecked(False)
446
            else:
447
                self._mw.clear_odmr_PushButton.setEnabled(False)
448
                self._mw.action_run_stop.setEnabled(False)
449
                self._mw.action_toggle_cw.setEnabled(True)
450
                self._mw.start_freq_DoubleSpinBox.setEnabled(True)
451
                self._mw.step_freq_DoubleSpinBox.setEnabled(True)
452
                self._mw.stop_freq_DoubleSpinBox.setEnabled(True)
453
                self._mw.sweep_power_DoubleSpinBox.setEnabled(True)
454
                self._mw.runtime_DoubleSpinBox.setEnabled(True)
455
                self._sd.clock_frequency_DoubleSpinBox.setEnabled(True)
456
                self._mw.action_run_stop.setChecked(False)
457
                self._mw.action_resume_odmr.setChecked(False)
458
                self._mw.action_toggle_cw.setChecked(True)
459
        else:
460
            self._mw.action_resume_odmr.setEnabled(True)
461
            self._mw.cw_power_DoubleSpinBox.setEnabled(True)
462
            self._mw.sweep_power_DoubleSpinBox.setEnabled(True)
463
            self._mw.cw_frequency_DoubleSpinBox.setEnabled(True)
464
            self._mw.clear_odmr_PushButton.setEnabled(False)
465
            self._mw.action_run_stop.setEnabled(True)
466
            self._mw.action_toggle_cw.setEnabled(True)
467
            self._mw.start_freq_DoubleSpinBox.setEnabled(True)
468
            self._mw.step_freq_DoubleSpinBox.setEnabled(True)
469
            self._mw.stop_freq_DoubleSpinBox.setEnabled(True)
470
            self._mw.runtime_DoubleSpinBox.setEnabled(True)
471
            self._sd.clock_frequency_DoubleSpinBox.setEnabled(True)
472
            self._mw.action_run_stop.setChecked(False)
473
            self._mw.action_resume_odmr.setChecked(False)
474
            self._mw.action_toggle_cw.setChecked(False)
475
476
        # Unblock signal firing
477
        self._mw.action_run_stop.blockSignals(False)
478
        self._mw.action_resume_odmr.blockSignals(False)
479
        self._mw.action_toggle_cw.blockSignals(False)
480
        return
481
482
    def clear_odmr_data(self):
483
        """ Clear the ODMR data. """
484
        self.sigClearData.emit()
485
        return
486
487
    def update_plots(self, odmr_data_x, odmr_data_y, odmr_matrix):
488
        """ Refresh the plot widgets with new data. """
489
        # Update mean signal plot
490
        self.odmr_image.setData(odmr_data_x, odmr_data_y[self.display_channel])
491
        # Update raw data matrix plot
492
        cb_range = self.get_matrix_cb_range()
493
        self.update_colorbar(cb_range)
494
        self.odmr_matrix_image.setRect(
495
            QtCore.QRectF(
496
                odmr_data_x[0],
497
                0,
498
                np.abs(odmr_data_x[-1] - odmr_data_x[0]),
499
                odmr_matrix.shape[0])
500
            )
501
        self.odmr_matrix_image.setImage(
502
            image=odmr_matrix[:, self.display_channel],
503
            axisOrder='row-major',
504
            levels=(cb_range[0], cb_range[1]))
505
506
    def update_channel(self, index):
507
        self.display_channel = int(
508
            self._mw.odmr_channel_ComboBox.itemData(index, QtCore.Qt.UserRole))
509
        self.update_plots(
510
            self._odmr_logic.odmr_plot_x,
511
            self._odmr_logic.odmr_plot_y,
512
            self._odmr_logic.odmr_plot_xy)
513
514
    def colorscale_changed(self):
515
        """
516
        Updates the range of the displayed colorscale in both the colorbar and the matrix plot.
517
        """
518
        cb_range = self.get_matrix_cb_range()
519
        self.update_colorbar(cb_range)
520
        matrix_image = self.odmr_matrix_image.image
521
        self.odmr_matrix_image.setImage(image=matrix_image, levels=(cb_range[0], cb_range[1]))
522
        return
523
524
    def update_colorbar(self, cb_range):
525
        """
526
        Update the colorbar to a new range.
527
528
        @param list cb_range: List or tuple containing the min and max values for the cb range
529
        """
530
        self.odmr_cb.refresh_colorbar(cb_range[0], cb_range[1])
531
        return
532
533
    def get_matrix_cb_range(self):
534
        """
535
        Determines the cb_min and cb_max values for the matrix plot
536
        """
537
        matrix_image = self.odmr_matrix_image.image
538
539
        # If "Manual" is checked or the image is empty (all zeros), then take manual cb range.
540
        # Otherwise, calculate cb range from percentiles.
541
        if self._mw.odmr_cb_manual_RadioButton.isChecked() or np.max(matrix_image) < 0.1:
542
            cb_min = self._mw.odmr_cb_min_DoubleSpinBox.value()
543
            cb_max = self._mw.odmr_cb_max_DoubleSpinBox.value()
544
        else:
545
            # Exclude any zeros (which are typically due to unfinished scan)
546
            matrix_image_nonzero = matrix_image[np.nonzero(matrix_image)]
547
548
            # Read centile range
549
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
550
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value()
551
552
            cb_min = np.percentile(matrix_image_nonzero, low_centile)
553
            cb_max = np.percentile(matrix_image_nonzero, high_centile)
554
555
        cb_range = [cb_min, cb_max]
556
        return cb_range
557
558
    def restore_defaultview(self):
559
        self._mw.restoreGeometry(self.mwsettings.value("geometry", ""))
560
        self._mw.restoreState(self.mwsettings.value("windowState", ""))
561
562
    def update_elapsedtime(self, elapsed_time, scanned_lines):
563
        """ Updates current elapsed measurement time and completed frequency sweeps """
564
        self._mw.elapsed_time_DisplayWidget.display(int(np.rint(elapsed_time)))
565
        self._mw.elapsed_sweeps_DisplayWidget.display(scanned_lines)
566
        return
567
568
    def update_settings(self):
569
        """ Write the new settings from the gui to the file. """
570
        number_of_lines = self._sd.matrix_lines_SpinBox.value()
571
        clock_frequency = self._sd.clock_frequency_DoubleSpinBox.value()
572
        self.sigClockFreqChanged.emit(clock_frequency)
573
        self.sigNumberOfLinesChanged.emit(number_of_lines)
574
        return
575
576
    def reject_settings(self):
577
        """ Keep the old settings and restores the old settings in the gui. """
578
        self._sd.matrix_lines_SpinBox.setValue(self._odmr_logic.number_of_lines)
579
        self._sd.clock_frequency_DoubleSpinBox.setValue(self._odmr_logic.clock_frequency)
580
        return
581
582
    def do_fit(self):
583
        fit_function = self._mw.fit_methods_ComboBox.getCurrentFit()[0]
584
        self.sigDoFit.emit(fit_function, None, None, self._mw.odmr_channel_ComboBox.currentIndex())
585
        return
586
587
    def update_fit(self, x_data, y_data, result_str_dict, current_fit):
588
        """ Update the shown fit. """
589
        if current_fit != 'No Fit':
590
            # display results as formatted text
591
            self._mw.odmr_fit_results_DisplayWidget.clear()
592
            try:
593
                formated_results = units.create_formatted_output(result_str_dict)
594
            except:
595
                formated_results = 'this fit does not return formatted results'
596
            self._mw.odmr_fit_results_DisplayWidget.setPlainText(formated_results)
597
598
        self._mw.fit_methods_ComboBox.blockSignals(True)
599
        self._mw.fit_methods_ComboBox.setCurrentFit(current_fit)
600
        self._mw.fit_methods_ComboBox.blockSignals(False)
601
602
        # check which Fit method is used and remove or add again the
603
        # odmr_fit_image, check also whether a odmr_fit_image already exists.
604
        if current_fit != 'No Fit':
605
            self.odmr_fit_image.setData(x=x_data, y=y_data)
606
            if self.odmr_fit_image not in self._mw.odmr_PlotWidget.listDataItems():
607
                self._mw.odmr_PlotWidget.addItem(self.odmr_fit_image)
608
        else:
609
            if self.odmr_fit_image in self._mw.odmr_PlotWidget.listDataItems():
610
                self._mw.odmr_PlotWidget.removeItem(self.odmr_fit_image)
611
612
        self._mw.odmr_PlotWidget.getViewBox().updateAutoRange()
613
        return
614
615
    def update_parameter(self, param_dict):
616
        """ Update the parameter display in the GUI.
617
618
        @param param_dict:
619
        @return:
620
621
        Any change event from the logic should call this update function.
622
        The update will block the GUI signals from emitting a change back to the
623
        logic.
624
        """
625
        param = param_dict.get('sweep_mw_power')
626
        if param is not None:
627
            self._mw.sweep_power_DoubleSpinBox.blockSignals(True)
628
            self._mw.sweep_power_DoubleSpinBox.setValue(param)
629
            self._mw.sweep_power_DoubleSpinBox.blockSignals(False)
630
631
        param = param_dict.get('mw_start')
632
        if param is not None:
633
            self._mw.start_freq_DoubleSpinBox.blockSignals(True)
634
            self._mw.start_freq_DoubleSpinBox.setValue(param)
635
            self._mw.start_freq_DoubleSpinBox.blockSignals(False)
636
637
        param = param_dict.get('mw_step')
638
        if param is not None:
639
            self._mw.step_freq_DoubleSpinBox.blockSignals(True)
640
            self._mw.step_freq_DoubleSpinBox.setValue(param)
641
            self._mw.step_freq_DoubleSpinBox.blockSignals(False)
642
643
        param = param_dict.get('mw_stop')
644
        if param is not None:
645
            self._mw.stop_freq_DoubleSpinBox.blockSignals(True)
646
            self._mw.stop_freq_DoubleSpinBox.setValue(param)
647
            self._mw.stop_freq_DoubleSpinBox.blockSignals(False)
648
649
        param = param_dict.get('run_time')
650
        if param is not None:
651
            self._mw.runtime_DoubleSpinBox.blockSignals(True)
652
            self._mw.runtime_DoubleSpinBox.setValue(param)
653
            self._mw.runtime_DoubleSpinBox.blockSignals(False)
654
655
        param = param_dict.get('number_of_lines')
656
        if param is not None:
657
            self._sd.matrix_lines_SpinBox.blockSignals(True)
658
            self._sd.matrix_lines_SpinBox.setValue(param)
659
            self._sd.matrix_lines_SpinBox.blockSignals(False)
660
661
        param = param_dict.get('clock_frequency')
662
        if param is not None:
663
            self._sd.clock_frequency_DoubleSpinBox.blockSignals(True)
664
            self._sd.clock_frequency_DoubleSpinBox.setValue(param)
665
            self._sd.clock_frequency_DoubleSpinBox.blockSignals(False)
666
667
        param = param_dict.get('cw_mw_frequency')
668
        if param is not None:
669
            self._mw.cw_frequency_DoubleSpinBox.blockSignals(True)
670
            self._mw.cw_frequency_DoubleSpinBox.setValue(param)
671
            self._mw.cw_frequency_DoubleSpinBox.blockSignals(False)
672
673
        param = param_dict.get('cw_mw_power')
674
        if param is not None:
675
            self._mw.cw_power_DoubleSpinBox.blockSignals(True)
676
            self._mw.cw_power_DoubleSpinBox.setValue(param)
677
            self._mw.cw_power_DoubleSpinBox.blockSignals(False)
678
        return
679
680
    ############################################################################
681
    #                           Change Methods                                 #
682
    ############################################################################
683
684
    def change_cw_params(self):
685
        """ Change CW frequency and power of microwave source """
686
        frequency = self._mw.cw_frequency_DoubleSpinBox.value()
687
        power = self._mw.cw_power_DoubleSpinBox.value()
688
        self.sigMwCwParamsChanged.emit(frequency, power)
689
        return
690
691
    def change_sweep_params(self):
692
        """ Change start, stop and step frequency of frequency sweep """
693
        start = self._mw.start_freq_DoubleSpinBox.value()
694
        stop = self._mw.stop_freq_DoubleSpinBox.value()
695
        step = self._mw.step_freq_DoubleSpinBox.value()
696
        power = self._mw.sweep_power_DoubleSpinBox.value()
697
        self.sigMwSweepParamsChanged.emit(start, stop, step, power)
698
        return
699
700
    def change_runtime(self):
701
        """ Change time after which microwave sweep is stopped """
702
        runtime = self._mw.runtime_DoubleSpinBox.value()
703
        self.sigRuntimeChanged.emit(runtime)
704
        return
705
706
    def save_data(self):
707
        """ Save the sum plot, the scan marix plot and the scan data """
708
        filetag = self._mw.save_tag_LineEdit.text()
709
        cb_range = self.get_matrix_cb_range()
710
711
        # Percentile range is None, unless the percentile scaling is selected in GUI.
712
        pcile_range = None
713
        if self._mw.odmr_cb_centiles_RadioButton.isChecked():
714
            low_centile = self._mw.odmr_cb_low_percentile_DoubleSpinBox.value()
715
            high_centile = self._mw.odmr_cb_high_percentile_DoubleSpinBox.value()
716
            pcile_range = [low_centile, high_centile]
717
718
        self.sigSaveMeasurement.emit(filetag, cb_range, pcile_range)
719
        return
720