Completed
Push — master ( d7e661...ed6eea )
by Jan
16s
created

PulsedMeasurementGui.repr_global_params()   B

Complexity

Conditions 5

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
dl 0
loc 17
rs 8.5454
1
# -*- coding: utf-8 -*-
2
3
"""
4
This file contains the QuDi main GUI for pulsed measurements.
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
import datetime
24
import inspect
25
import numpy as np
26
import os
27
import pyqtgraph as pg
28
import re
29
30
31
from collections import OrderedDict
32
from core.module import Connector, StatusVar
33
from core.util import units
34
from core.util.mutex import Mutex
35
from gui.colordefs import QudiPalettePale as palette
36
from gui.colordefs import QudiPalette as palettedark
37
from gui.fitsettings import FitSettingsDialog, FitSettingsComboBox
38
from gui.guibase import GUIBase
39
from gui.pulsed.pulse_editors import BlockEditor, BlockOrganizer, SequenceEditor
40
#from gui.pulsed.pulse_editor import PulseEditor
41
from logic.sampling_functions import SamplingFunctions
42
from qtpy import QtGui
43
from qtpy import QtCore
44
from qtpy import QtWidgets
45
from qtpy import uic
46
from qtwidgets.scientific_spinbox import ScienDSpinBox
47
48
49
#FIXME: Display the Pulse
50
#FIXME: save the length in sample points (bins)
51
#FIXME: adjust the length to the bins
52
53
predefined_global_parameter_list = [
54
    'mw_channel',
55
    'gate_count_channel',
56
    'sync_trig_channel',
57
    'mw_amp',
58
    'mw_freq',
59
    'channel_amp',
60
    'delay_length',
61
    'wait_time',
62
    'laser_length',
63
    'rabi_period',
64
    ]
65
66
class PulsedMeasurementMainWindow(QtWidgets.QMainWindow):
67
    def __init__(self):
68
        # Get the path to the *.ui file
69
        this_dir = os.path.dirname(__file__)
70
        ui_file = os.path.join(this_dir, 'ui_pulsed_maingui.ui')
71
72
        # Load it
73
        super(PulsedMeasurementMainWindow, self).__init__()
74
75
        uic.loadUi(ui_file, self)
76
        self.show()
77
78
79
class PulseAnalysisTab(QtWidgets.QWidget):
80
    def __init__(self):
81
        # Get the path to the *.ui file
82
        this_dir = os.path.dirname(__file__)
83
        ui_file = os.path.join(this_dir, 'ui_pulse_analysis.ui')
84
        # Load it
85
        super().__init__()
86
        uic.loadUi(ui_file, self)
87
88
89
class PulseGeneratorTab(QtWidgets.QWidget):
90
    def __init__(self):
91
        # Get the path to the *.ui file
92
        this_dir = os.path.dirname(__file__)
93
        ui_file = os.path.join(this_dir, 'ui_pulse_editor.ui')
94
        # Load it
95
        super().__init__()
96
        uic.loadUi(ui_file, self)
97
98
99
class SequenceGeneratorTab(QtWidgets.QWidget):
100
    def __init__(self):
101
        # Get the path to the *.ui file
102
        this_dir = os.path.dirname(__file__)
103
        ui_file = os.path.join(this_dir, 'ui_sequence_editor.ui')
104
        # Load it
105
        super().__init__()
106
        uic.loadUi(ui_file, self)
107
108
109
class PulseExtractionTab(QtWidgets.QWidget):
110
    def __init__(self):
111
        # Get the path to the *.ui file
112
        this_dir = os.path.dirname(__file__)
113
        ui_file = os.path.join(this_dir, 'ui_pulse_extraction.ui')
114
        # Load it
115
        super().__init__()
116
        uic.loadUi(ui_file, self)
117
118
119
class AnalysisSettingDialog(QtWidgets.QDialog):
120
    def __init__(self):
121
        # Get the path to the *.ui file
122
        this_dir = os.path.dirname(__file__)
123
        ui_file = os.path.join(this_dir, 'ui_pulsed_main_gui_settings_analysis.ui')
124
125
        # Load it
126
        super().__init__()
127
128
        uic.loadUi(ui_file, self)
129
130
131
class GeneratorSettingsDialog(QtWidgets.QDialog):
132
    def __init__(self):
133
        # Get the path to the *.ui file
134
        this_dir = os.path.dirname(__file__)
135
        ui_file = os.path.join(this_dir, 'ui_pulsed_main_gui_settings_block_gen.ui')
136
137
        # Load it
138
        super().__init__()
139
140
        uic.loadUi(ui_file, self)
141
142
143
class PredefinedMethodsTab(QtWidgets.QWidget):
144
    def __init__(self):
145
        # Get the path to the *.ui file
146
        this_dir = os.path.dirname(__file__)
147
        ui_file = os.path.join(this_dir, 'ui_predefined_methods.ui')
148
149
        # Load it
150
        super().__init__()
151
152
        uic.loadUi(ui_file, self)
153
154
class PredefinedMethodsConfigDialog(QtWidgets.QDialog):
155
    def __init__(self):
156
        # Get the path to the *.ui file
157
        this_dir = os.path.dirname(__file__)
158
        ui_file = os.path.join(this_dir, 'ui_predefined_methods_config.ui')
159
160
        # Load it
161
        super().__init__()
162
163
        uic.loadUi(ui_file, self)
164
165
class PulsedMeasurementGui(GUIBase):
166
    """ This is the main GUI Class for pulsed measurements. """
167
168
    _modclass = 'PulsedMeasurementGui'
169
    _modtype = 'gui'
170
171
    ## declare connectors
172
    pulsedmasterlogic = Connector(interface='PulsedMasterLogic')
173
    savelogic = Connector(interface='SaveLogic')
174
175
    # status var
176
    _ana_param_x_axis_name_text = StatusVar('ana_param_x_axis_name_LineEdit', 'Tau')
177
    _ana_param_x_axis_unit_text = StatusVar('ana_param_x_axis_unit_LineEdit', 's')
178
    _ana_param_y_axis_name_text = StatusVar('ana_param_y_axis_name_LineEdit', 'Normalized Signal')
179
    _ana_param_y_axis_unit_text = StatusVar('ana_param_y_axis_unit_LineEdit', '')
180
    _ana_param_second_plot_x_axis_name_text = StatusVar('ana_param_second_plot_x_axis_name_LineEdit', 'Frequency')
181
    _ana_param_second_plot_x_axis_unit_text = StatusVar('ana_param_second_plot_x_axis_unit_LineEdit', 'Hz')
182
    _ana_param_second_plot_y_axis_name_text = StatusVar('ana_param_second_plot_y_axis_name_LineEdit', 'Ft Signal')
183
    _ana_param_second_plot_y_axis_unit_text = StatusVar('ana_param_second_plot_y_axis_unit_LineEdit', '')
184
185
    _ana_param_errorbars = StatusVar('ana_param_errorbars_CheckBox', False)
186
    _second_plot_ComboBox_text = StatusVar('second_plot_ComboBox_text', 'None')
187
188
    _predefined_methods_to_show = StatusVar('predefined_methods_to_show', [])
189
    _functions_to_show = StatusVar('functions_to_show', [])
190
    _predefined_global_param_values = StatusVar('predefined_global_parameters', {})
191
192
    def __init__(self, config, **kwargs):
193
        super().__init__(config=config, **kwargs)
194
195
    def on_activate(self):
196
        """ Initialize, connect and configure the pulsed measurement GUI.
197
198
        Establish general connectivity and activate the different tabs of the
199
        GUI.
200
        """
201
        self._pulsed_master_logic = self.pulsedmasterlogic()
202
        self._save_logic = self.savelogic()
203
204
        self._mw = PulsedMeasurementMainWindow()
205
        self._pa = PulseAnalysisTab()
206
        self._pg = PulseGeneratorTab()
207
        self._pe = PulseExtractionTab()
208
        self._pm = PredefinedMethodsTab()
209
        self._sg = SequenceGeneratorTab()
210
211
        self._mw.tabWidget.addTab(self._pa, 'Analysis')
212
        self._mw.tabWidget.addTab(self._pe, 'Pulse Extraction')
213
        self._mw.tabWidget.addTab(self._pg, 'Pulse Generator')
214
        self._mw.tabWidget.addTab(self._sg, 'Sequence Generator')
215
        self._mw.tabWidget.addTab(self._pm, 'Predefined Methods')
216
217
        self._mw.actionSave.triggered.connect(self.save_clicked)
218
219
        self.setup_toolbar()
220
        self._activate_analysis_settings_ui()
221
        self._activate_analysis_ui()
222
        self.setup_extraction_ui()
223
224
        self._activate_generator_settings_ui()
225
        self._activate_pulse_generator_ui()
226
227
        self.show()
228
229
        self._pa.ext_control_mw_freq_DoubleSpinBox.setMaximum(999999999999)
230
231
    def on_deactivate(self):
232
        """ Undo the Definition, configuration and initialisation of the pulsed
233
            measurement GUI.
234
235
        This deactivation disconnects all the graphic modules, which were
236
        connected in the initUI method.
237
        """
238
239
        self._mw.actionSave.triggered.disconnect()
240
241
        self._deactivate_analysis_settings_ui()
242
        self._deactivate_analysis_ui()
243
244
        self._deactivate_generator_settings_ui()
245
        self._deactivate_pulse_generator_ui()
246
247
        self._mw.close()
248
249
    def show(self):
250
        """Make main window visible and put it above all other windows. """
251
        QtWidgets.QMainWindow.show(self._mw)
252
        self._mw.activateWindow()
253
        self._mw.raise_()
254
255
    ###########################################################################
256
    ###   Methods related to Settings for the 'Pulse Generator' tab:        ###
257
    ###########################################################################
258
    def _activate_generator_settings_ui(self):
259
        """ Initialize, connect and configure the pulse generator settings to be displayed in the
260
        editor.
261
        """
262
        self._gs = GeneratorSettingsDialog()
263
        self._gs.accepted.connect(self.apply_generator_settings)
264
        self._gs.rejected.connect(self.keep_former_generator_settings)
265
        self._gs.sampled_file_format_comboBox.currentIndexChanged.connect(
266
            self.generator_settings_changed, QtCore.Qt.QueuedConnection)
267
        self._gs.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
268
            self.apply_generator_settings)
269
270
        # here are all the names of the predefined methods are saved.
271
        self._predefined_methods_list = []
272
        # create a config for the predefined methods:
273
        self._pm_cfg = PredefinedMethodsConfigDialog()
274
        self._pm_cfg.accepted.connect(self.apply_predefined_methods_config)
275
        self._pm_cfg.rejected.connect(self.keep_former_predefined_methods_config)
276
        self._pm_cfg.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
277
            self.apply_predefined_methods_config)
278
        # Set ranges for the global parameters and default values
279
        self._pm.pm_mw_amp_Widget.setRange(0.0, np.inf)
280
        self._pm.pm_mw_freq_Widget.setRange(0.0, np.inf)
281
        self._pm.pm_channel_amp_Widget.setRange(0.0, np.inf)
282
        self._pm.pm_delay_length_Widget.setRange(0.0, np.inf)
283
        self._pm.pm_wait_time_Widget.setRange(0.0, np.inf)
284
        self._pm.pm_laser_length_Widget.setRange(0.0, np.inf)
285
        self._pm.pm_rabi_period_Widget.setRange(0.0, np.inf)
286
        self._pm.pm_mw_amp_Widget.setValue(0.125)
287
        self._pm.pm_mw_freq_Widget.setValue(2.87e9)
288
        self._pm.pm_channel_amp_Widget.setValue(0.0)
289
        self._pm.pm_delay_length_Widget.setValue(500.0e-9)
290
        self._pm.pm_wait_time_Widget.setValue(1.5e-6)
291
        self._pm.pm_laser_length_Widget.setValue(3.0e-6)
292
        self._pm.pm_rabi_period_Widget.setValue(200.0e-9)
293
294
        for param_name in predefined_global_parameter_list:
295
            if param_name in self._predefined_global_param_values:
296
                widget = getattr(self._pm, 'pm_' + param_name + '_Widget')
297
298
                if hasattr(widget, 'setChecked'):
299
                    widget.setChecked(self._predefined_global_param_values[param_name])
300
                elif hasattr(widget, 'setValue'):
301
                    widget.setValue(self._predefined_global_param_values[param_name])
302
                elif hasattr(widget, 'setText'):
303
                    widget.setText(self._predefined_global_param_values[param_name])
304
                else:
305
                    self.log.error('Not possible to get the value from the widget {0},'
306
                                   'since it does not have one of the possible access methods!'
307
                                   ''.format(param_name))
308
309
        # connect the menu to the actions:
310
        self._mw.action_Settings_Block_Generation.triggered.connect(self.show_generator_settings)
311
        self._mw.action_Predefined_Methods_Config.triggered.connect(self.show_predefined_methods_config)
312
313
        self._pulsed_master_logic.sigPredefinedSequencesUpdated.connect(self.predefined_methods_changed)
314
315
        # Create function config dialog
316
        self._create_function_config()
317
        return
318
319
    def _deactivate_generator_settings_ui(self):
320
        """ Disconnects the configuration of the Settings for the 'Pulse Generator' Tab.
321
        """
322
        self._gs.accepted.disconnect()
323
        self._gs.rejected.disconnect()
324
        self._gs.sampled_file_format_comboBox.currentIndexChanged.disconnect()
325
        self._gs.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
326
        self._gs.close()
327
328
        self._pm_cfg.accepted.disconnect()
329
        self._pm_cfg.rejected.disconnect()
330
        self._pm_cfg.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
331
        self._pm_cfg.close()
332
333
334
        self._pulsed_master_logic.sigPredefinedSequencesUpdated.disconnect()
335
        self._mw.action_Settings_Block_Generation.triggered.disconnect()
336
        self._mw.action_Predefined_Methods_Config.triggered.disconnect()
337
        return
338
339
    def show_generator_settings(self):
340
        """
341
        Opens the generator settings menu.
342
        """
343
        self._gs.exec_()
344
        return
345
346
    @_predefined_global_param_values.representer
347
    def repr_global_params(self, val):
348
        pdict = {}
349
        for param_name in predefined_global_parameter_list:
350
            widget = getattr(self._pm, 'pm_' + param_name + '_Widget')
351
352
            if hasattr(widget, 'isChecked'):
353
                pdict[param_name] = widget.isChecked()
354
            elif hasattr(widget, 'value'):
355
                pdict[param_name] = widget.value()
356
            elif hasattr(widget, 'text'):
357
                pdict[param_name] = widget.text()
358
            else:
359
                self.log.error('Not possible to get the value from the widget {0},'
360
                               'since it does not have one of the possible access methods!'
361
                               ''.format(param_name))
362
        return pdict
363
364
    def _create_function_config(self):
365
        # Add in the settings menu within the groupbox widget all the available math_functions,
366
        # based on the list from the Logic. Right now, the GUI objects are inserted the 'hard' way,
367
        # like it is done in the Qt-Designer.
368
        # FIXME: Make a nicer way of displaying the available functions, maybe with a Table!
369
        objectname = self._gs.objectName()
370
        for index, func_name in enumerate(list(SamplingFunctions().func_config)):
371
            name_label = 'func_' + str(index)
372
            setattr(self._gs, name_label, QtWidgets.QLabel(self._gs.groupBox))
373
            label = getattr(self._gs, name_label)
374
            label.setObjectName(name_label)
375
            self._gs.gridLayout_3.addWidget(label, index, 0, 1, 1)
376
            label.setText(QtWidgets.QApplication.translate(objectname, func_name, None))
377
378
            name_checkbox = 'checkbox_' + str(index)
379
            setattr(self._gs, name_checkbox, QtWidgets.QCheckBox(self._gs.groupBox))
380
            checkbox = getattr(self._gs, name_checkbox)
381
            checkbox.setObjectName(name_checkbox)
382
            self._gs.gridLayout_3.addWidget(checkbox, index, 1, 1, 1)
383
            checkbox.setText(QtWidgets.QApplication.translate(objectname, '', None))
384
        # Check all functions that are in the _functions_to_show list.
385
        # If no such list is present take the first 3 functions as default
386
        if len(self._functions_to_show) > 0:
387
            for func in self._functions_to_show:
388
                index = list(SamplingFunctions().func_config).index(func)
389
                name_checkbox = 'checkbox_' + str(index)
390
                checkbox = getattr(self._gs, name_checkbox)
391
                checkbox.setCheckState(QtCore.Qt.Checked)
392
        else:
393
            for index in range(3):
394
                name_checkbox = 'checkbox_' + str(index)
395
                checkbox = getattr(self._gs, name_checkbox)
396
                checkbox.setCheckState(QtCore.Qt.Checked)
397
        return
398
399
    def apply_generator_settings(self):
400
        """
401
        Write new generator settings from the gui to the file.
402
        """
403
        new_config = SamplingFunctions().func_config
404
        for index, func_name in enumerate(list(SamplingFunctions().func_config)):
405
            name_checkbox = 'checkbox_' + str(index)
406
            checkbox = getattr(self._gs, name_checkbox)
407
            if not checkbox.isChecked():
408
                name_label = 'func_' + str(index)
409
                func = getattr(self._gs, name_label)
410
                del new_config[func.text()]
411
        self._functions_to_show = list(new_config)
412
        if self.block_editor.function_config != new_config:
413
            self.block_editor.set_function_config(new_config)
414
        return
415
416
    def keep_former_generator_settings(self):
417
        """
418
        Keep the old generator settings and restores them in the gui.
419
        """
420
        old_config = self.block_editor.function_config
421
        for index, func_name in enumerate(list(SamplingFunctions().func_config)):
422
            name_checkbox = 'checkbox_' + str(index)
423
            checkbox = getattr(self._gs, name_checkbox)
424
            if func_name in old_config:
425
                checkbox.setChecked(True)
426
            else:
427
                checkbox.setChecked(False)
428
        return
429
430
    def show_predefined_methods_config(self):
431
        """ Opens the Window for the config of predefined methods."""
432
        self._pm_cfg.show()
433
        self._pm_cfg.raise_()
434
435
    def predefined_methods_changed(self, methods_dict):
436
        """
437
438
        @param methods_dict:
439
        @return:
440
        """
441
        self._predefined_methods_list = list(methods_dict)
442
        # create all GUI elements
443
        self._create_predefined_methods(methods_dict)
444
        # check all checkboxes that correspond to the methods to show in the config dialogue
445
        for method_name in self._predefined_methods_to_show:
446
            if method_name in self._predefined_methods_list:
447
                index = self._predefined_methods_list.index(method_name)
448
                checkbox = getattr(self._pm_cfg, 'checkbox_' + str(index))
449
                checkbox.setChecked(True)
450
            else:
451
                del_index = self._predefined_methods_to_show.index(method_name)
452
                del self._predefined_methods_to_show[del_index]
453
        # apply the chosen methods to the methods dialogue
454
        self.apply_predefined_methods_config()
455
        return
456
457
    def _create_predefined_methods(self, methods_dict):
458
        """
459
        Initializes the GUI elements for the predefined methods and the corresponding config
460
461
        @param methods_dict:
462
        @return:
463
        """
464
        for index, method_name in enumerate(list(methods_dict)):
465
            # create checkboxes for the config dialogue
466
            name_checkbox = 'checkbox_' + str(index)
467
            setattr(self._pm_cfg, name_checkbox, QtWidgets.QCheckBox(self._pm_cfg.scrollArea))
468
            checkbox = getattr(self._pm_cfg, name_checkbox)
469
            checkbox.setObjectName(name_checkbox)
470
            checkbox.setText(method_name)
471
            checkbox.setChecked(False)
472
            self._pm_cfg.verticalLayout.addWidget(checkbox)
473
474
            # Create the widgets for the predefined methods dialogue
475
            # Create GroupBox for the method to reside in
476
            groupBox = QtWidgets.QGroupBox(self._pm)
477
            groupBox.setAlignment(QtCore.Qt.AlignLeft)
478
            groupBox.setTitle(method_name)
479
            # Create layout within the GroupBox
480
            gridLayout = QtWidgets.QGridLayout(groupBox)
481
            # Create generate buttons
482
            gen_button = QtWidgets.QPushButton(groupBox)
483
            gen_button.setText('Generate')
484
            gen_button.setObjectName('gen_' + method_name)
485
            gen_button.clicked.connect(self.generate_predefined_clicked)
486
            sauplo_button = QtWidgets.QPushButton(groupBox)
487
            sauplo_button.setText('GenSaUpLo')
488
            sauplo_button.setObjectName('sauplo_' + method_name)
489
            sauplo_button.clicked.connect(self.generate_sauplo_predefined_clicked)
490
            gridLayout.addWidget(gen_button, 0, 0, 1, 1)
491
            gridLayout.addWidget(sauplo_button, 1, 0, 1, 1)
492
            # inspect current method to extract the parameters
493
            inspected = inspect.signature(methods_dict[method_name])
494
            # run through all parameters of the current method and create the widgets
495
            for param_index, param_name in enumerate(inspected.parameters):
496
                if param_name not in predefined_global_parameter_list:
497
                    # get default value of the parameter
498
                    default_val = inspected.parameters[param_name].default
499
                    if default_val is inspect._empty:
500
                        self.log.error('The method "{0}" in the logic has an argument "{1}" without'
501
                                       ' a default value!\nAssign a default value to that, '
502
                                       'otherwise a type estimation is not possible!\n'
503
                                       'Creation of the viewbox aborted.'
504
                                       ''.format('generate_' + method_name, param_name))
505
                        return
506
                    # create a label for the parameter
507
                    param_label = QtWidgets.QLabel(groupBox)
508
                    param_label.setText(param_name)
509
                    # create proper input widget for the parameter depending on the type of default_val
510
                    if type(default_val) is bool:
511
                        input_obj = QtWidgets.QCheckBox(groupBox)
512
                        input_obj.setChecked(default_val)
513
                    elif type(default_val) is float:
514
                        input_obj = ScienDSpinBox(groupBox)
515
                        input_obj.setMaximum(np.inf)
516
                        input_obj.setMinimum(-np.inf)
517
                        if 'amp' in param_name:
518
                            input_obj.setSuffix('V')
519
                        elif 'freq' in param_name:
520
                            input_obj.setSuffix('Hz')
521
                        elif 'length' in param_name or 'time' in param_name or 'period' in param_name or 'tau' in param_name:
522
                            input_obj.setSuffix('s')
523
                        input_obj.setMinimumSize(QtCore.QSize(80, 0))
524
                        input_obj.setValue(default_val)
525
                    elif type(default_val) is int:
526
                        input_obj = QtWidgets.QSpinBox(groupBox)
527
                        input_obj.setMaximum(2**31 - 1)
528
                        input_obj.setMinimum(-2**31 + 1)
529
                        input_obj.setValue(default_val)
530
                    elif type(default_val) is str:
531
                        input_obj = QtWidgets.QLineEdit(groupBox)
532
                        input_obj.setMinimumSize(QtCore.QSize(80, 0))
533
                        input_obj.setText(default_val)
534
                    else:
535
                        self.log.error('The method "{0}" in the logic has an argument "{1}" with is not'
536
                                       ' of the valid types str, float, int or bool!\nChoose one of '
537
                                       'those default values! Creation of the viewbox aborted.'
538
                                       ''.format('generate_' + method_name, param_name))
539
                    # Adjust size policy
540
                    input_obj.setMinimumWidth(75)
541
                    input_obj.setMaximumWidth(100)
542
                    gridLayout.addWidget(param_label, 0, param_index+1, 1, 1)
543
                    gridLayout.addWidget(input_obj, 1, param_index+1, 1, 1)
544
                    setattr(self._pm, method_name + '_param_' + param_name + '_Widget', input_obj)
545
            h_spacer = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Expanding,
546
                                             QtWidgets.QSizePolicy.Minimum)
547
            gridLayout.addItem(h_spacer, 1, param_index+2, 1, 1)
548
549
            # attach the GroupBox widget to the predefined methods widget.
550
            setattr(self._pm, method_name + '_GroupBox', groupBox)
551
            self._pm.verticalLayout.addWidget(groupBox)
552
        self._pm.verticalLayout.addStretch()
553
        return
554
555
    def keep_former_predefined_methods_config(self):
556
        for index, name in enumerate(self._predefined_methods_list):
557
            groupbox = getattr(self._pm, name + '_GroupBox')
558
            checkbox = getattr(self._pm_cfg, 'checkbox_' + str(index))
559
            checkbox.setChecked(groupbox.isVisible())
560
        return
561
562
    def apply_predefined_methods_config(self):
563
        self._predefined_methods_to_show = []
564
        for index, name in enumerate(self._predefined_methods_list):
565
            groupbox = getattr(self._pm, name + '_GroupBox')
566
            checkbox = getattr(self._pm_cfg, 'checkbox_' + str(index))
567
            is_checked = checkbox.isChecked()
568
            groupbox.setVisible(is_checked)
569
            if is_checked:
570
                self._predefined_methods_to_show.append(name)
571
572
        self._pm.hintLabel.setVisible(len(self._predefined_methods_to_show) == 0)
573
        return
574
575
576
    ###########################################################################
577
    ###   Methods related to Tab 'Pulse Generator' in the Pulsed Window:    ###
578
    ###########################################################################
579
    def _activate_pulse_generator_ui(self):
580
        """ Initialize, connect and configure the 'Pulse Generator' Tab.
581
        """
582
        # connect signals of input widgets
583
        self._pg.gen_sample_freq_DSpinBox.editingFinished.connect(self.generator_settings_changed, QtCore.Qt.QueuedConnection)
584
        self._pg.gen_laserchannel_ComboBox.currentIndexChanged.connect(self.generator_settings_changed, QtCore.Qt.QueuedConnection)
585
        self._pg.gen_activation_config_ComboBox.currentIndexChanged.connect(self.generator_settings_changed, QtCore.Qt.QueuedConnection)
586
        # connect signals of buttons
587
        self._pg.saup_ensemble_PushButton.clicked.connect(self.saup_ensemble_clicked)
588
        self._sg.saup_sequence_PushButton.clicked.connect(self.saup_sequence_clicked)
589
        self._pg.sauplo_ensemble_PushButton.clicked.connect(self.sauplo_ensemble_clicked)
590
        self._sg.sauplo_sequence_PushButton.clicked.connect(self.sauplo_sequence_clicked)
591
592
        self._pg.block_add_last_PushButton.clicked.connect(self.block_add_last_clicked)
593
        self._pg.block_del_last_PushButton.clicked.connect(self.block_del_last_clicked)
594
        self._pg.block_add_sel_PushButton.clicked.connect(self.block_add_sel_clicked)
595
        self._pg.block_del_sel_PushButton.clicked.connect(self.block_del_sel_clicked)
596
        self._pg.block_clear_PushButton.clicked.connect(self.block_clear_clicked)
597
        self._pg.organizer_add_last_PushButton.clicked.connect(self.organizer_add_last_clicked)
598
        self._pg.organizer_del_last_PushButton.clicked.connect(self.organizer_del_last_clicked)
599
        self._pg.organizer_add_sel_PushButton.clicked.connect(self.organizer_add_sel_clicked)
600
        self._pg.organizer_del_sel_PushButton.clicked.connect(self.organizer_del_sel_clicked)
601
        self._pg.organizer_clear_PushButton.clicked.connect(self.organizer_clear_clicked)
602
        self._sg.sequence_add_last_PushButton.clicked.connect(self.sequence_add_last_clicked)
603
        self._sg.sequence_del_last_PushButton.clicked.connect(self.sequence_del_last_clicked)
604
        self._sg.sequence_add_sel_PushButton.clicked.connect(self.sequence_add_sel_clicked)
605
        self._sg.sequence_del_sel_PushButton.clicked.connect(self.sequence_del_sel_clicked)
606
        self._sg.sequence_clear_PushButton.clicked.connect(self.sequence_clear_clicked)
607
608
        self._pg.curr_block_generate_PushButton.clicked.connect(self.editor_generate_block_clicked)
609
        self._pg.curr_block_del_PushButton.clicked.connect(self.editor_delete_block_clicked)
610
        self._pg.curr_block_load_PushButton.clicked.connect(self.editor_load_block_clicked)
611
        self._pg.curr_ensemble_generate_PushButton.clicked.connect(self.editor_generate_ensemble_clicked)
612
        self._pg.curr_ensemble_del_PushButton.clicked.connect(self.editor_delete_ensemble_clicked)
613
        self._pg.curr_ensemble_load_PushButton.clicked.connect(self.editor_load_ensemble_clicked)
614
        self._sg.curr_sequence_generate_PushButton.clicked.connect(self.editor_generate_sequence_clicked)
615
        self._sg.curr_sequence_del_PushButton.clicked.connect(self.editor_delete_sequence_clicked)
616
        self._sg.curr_sequence_load_PushButton.clicked.connect(self.editor_load_sequence_clicked)
617
618
        # connect update signals from pulsed_master_logic
619
        self._pulsed_master_logic.sigEnsembleSaUpComplete.connect(self.saup_ensemble_finished)
620
        self._pulsed_master_logic.sigSequenceSaUpComplete.connect(self.saup_sequence_finished)
621
        self._pulsed_master_logic.sigSavedPulseBlocksUpdated.connect(self.update_block_dict)
622
        self._pulsed_master_logic.sigSavedBlockEnsemblesUpdated.connect(self.update_ensemble_dict)
623
        self._pulsed_master_logic.sigSavedSequencesUpdated.connect(self.update_sequence_dict)
624
        self._pulsed_master_logic.sigGeneratorSettingsUpdated.connect(self.update_generator_settings)
625
626
        self._pulsed_master_logic.sigCurrentPulseBlockUpdated.connect(self.load_block_in_editor)
627
        self._pulsed_master_logic.sigCurrentBlockEnsembleUpdated.connect(self.load_ensemble_in_editor)
628
        self._pulsed_master_logic.sigCurrentSequenceUpdated.connect(self.load_sequence_in_editor)
629
630
        self.block_organizer = BlockOrganizer(self._pg.block_organizer_TableWidget)
631
        self.block_editor = BlockEditor(self._pg.block_editor_TableWidget)
632
        self.sequence_editor = SequenceEditor(self._sg.sequence_editor_TableWidget)
633
634
        # Apply hardware constraints to input widgets
635
        self._gen_apply_hardware_constraints()
636
637
        # Fill initial values from logic into input widgets
638
        self._pulsed_master_logic.request_generator_init_values()
639
        return
640
641
    def _deactivate_pulse_generator_ui(self):
642
        """ Disconnects the configuration for 'Pulse Generator Tab.
643
        """
644
        # disconnect signals of input widgets
645
        self._pg.gen_sample_freq_DSpinBox.editingFinished.disconnect()
646
        self._pg.gen_laserchannel_ComboBox.currentIndexChanged.disconnect()
647
        self._pg.gen_activation_config_ComboBox.currentIndexChanged.disconnect()
648
        # disconnect signals of buttons
649
        self._pg.saup_ensemble_PushButton.clicked.disconnect()
650
        self._sg.saup_sequence_PushButton.clicked.disconnect()
651
        self._pg.sauplo_ensemble_PushButton.clicked.disconnect()
652
        self._sg.sauplo_sequence_PushButton.clicked.disconnect()
653
        self._pg.block_add_last_PushButton.clicked.disconnect()
654
        self._pg.block_del_last_PushButton.clicked.disconnect()
655
        self._pg.block_add_sel_PushButton.clicked.disconnect()
656
        self._pg.block_del_sel_PushButton.clicked.disconnect()
657
        self._pg.block_clear_PushButton.clicked.disconnect()
658
        self._pg.organizer_add_last_PushButton.clicked.disconnect()
659
        self._pg.organizer_del_last_PushButton.clicked.disconnect()
660
        self._pg.organizer_add_sel_PushButton.clicked.disconnect()
661
        self._pg.organizer_del_sel_PushButton.clicked.disconnect()
662
        self._pg.organizer_clear_PushButton.clicked.disconnect()
663
        self._sg.sequence_add_last_PushButton.clicked.disconnect()
664
        self._sg.sequence_del_last_PushButton.clicked.disconnect()
665
        self._sg.sequence_add_sel_PushButton.clicked.disconnect()
666
        self._sg.sequence_del_sel_PushButton.clicked.disconnect()
667
        self._sg.sequence_clear_PushButton.clicked.disconnect()
668
        self._pg.curr_block_generate_PushButton.clicked.disconnect()
669
        self._pg.curr_block_del_PushButton.clicked.disconnect()
670
        self._pg.curr_block_load_PushButton.clicked.disconnect()
671
        self._pg.curr_ensemble_generate_PushButton.clicked.disconnect()
672
        self._pg.curr_ensemble_del_PushButton.clicked.disconnect()
673
        self._pg.curr_ensemble_load_PushButton.clicked.disconnect()
674
        self._sg.curr_sequence_generate_PushButton.clicked.disconnect()
675
        self._sg.curr_sequence_del_PushButton.clicked.disconnect()
676
        self._sg.curr_sequence_load_PushButton.clicked.disconnect()
677
        # disconnect update signals from pulsed_master_logic
678
        self._pulsed_master_logic.sigEnsembleSaUpComplete.disconnect()
679
        self._pulsed_master_logic.sigSequenceSaUpComplete.disconnect()
680
        self._pulsed_master_logic.sigSavedPulseBlocksUpdated.disconnect()
681
        self._pulsed_master_logic.sigSavedBlockEnsemblesUpdated.disconnect()
682
        self._pulsed_master_logic.sigSavedSequencesUpdated.disconnect()
683
        self._pulsed_master_logic.sigGeneratorSettingsUpdated.disconnect()
684
        self._pulsed_master_logic.sigCurrentPulseBlockUpdated.disconnect()
685
        self._pulsed_master_logic.sigCurrentBlockEnsembleUpdated.disconnect()
686
        self._pulsed_master_logic.sigCurrentSequenceUpdated.disconnect()
687
        return
688
689
    def _gen_apply_hardware_constraints(self):
690
        """
691
        Retrieve the constraints from pulser hardware and apply these constraints to the pulse
692
        generator GUI elements.
693
        """
694
        # block signals
695
        self._pg.gen_activation_config_ComboBox.blockSignals(True)
696
        self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
697
        # apply constraints
698
        pulser_constr, dummy = self._pulsed_master_logic.get_hardware_constraints()
699
        self._pg.gen_activation_config_ComboBox.addItems(list(pulser_constr.activation_config))
700
        self._pg.gen_sample_freq_DSpinBox.setMinimum(pulser_constr.sample_rate.min)
701
        self._pg.gen_sample_freq_DSpinBox.setMaximum(pulser_constr.sample_rate.max)
702
        # unblock signals
703
        self._pg.gen_activation_config_ComboBox.blockSignals(False)
704
        self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
705
        return
706
707
    def generator_settings_changed(self):
708
        """
709
710
        @return:
711
        """
712
        sample_rate = self._pg.gen_sample_freq_DSpinBox.value()
713
        laser_channel = self._pg.gen_laserchannel_ComboBox.currentText()
714
        activation_config_name = self._pg.gen_activation_config_ComboBox.currentText()
715
        amplitude_dict = self._pulsed_master_logic._generator_logic.amplitude_dict
716
        waveform_format = self._gs.sampled_file_format_comboBox.currentText()
717
718
        self._pulsed_master_logic.generator_settings_changed(activation_config_name, laser_channel,
719
                                                             sample_rate, amplitude_dict,
720
                                                             waveform_format)
721
        return
722
723
    def update_generator_settings(self, activation_config_name, activation_config, sample_rate,
724
                                   amplitude_dict, laser_channel, waveform_format):
725
        """
726
727
        @param activation_config_name:
728
        @param activation_config:
729
        @param sample_rate:
730
        @param amplitude_dict:
731
        @param laser_channel:
732
        @param waveform_format:
733
        @return:
734
        """
735
        # block signals
736
        self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
737
        self._pg.gen_laserchannel_ComboBox.blockSignals(True)
738
        self._pg.gen_activation_config_ComboBox.blockSignals(True)
739
        self._gs.sampled_file_format_comboBox.blockSignals(True)
740
        # sampling format
741
        index = self._gs.sampled_file_format_comboBox.findText(waveform_format)
742
        self._gs.sampled_file_format_comboBox.setCurrentIndex(index)
743
        # activation config
744
        index = self._pg.gen_activation_config_ComboBox.findText(activation_config_name)
745
        self._pg.gen_activation_config_ComboBox.setCurrentIndex(index)
746
        display_str = ''
747
        for chnl in activation_config:
748
            display_str += chnl + ' | '
749
        display_str = display_str[:-3]
750
        self._pg.gen_activation_config_LineEdit.setText(display_str)
751
        self._pg.gen_analog_channels_SpinBox.setValue(
752
            len([chnl for chnl in activation_config if 'a_ch' in chnl]))
753
        self._pg.gen_digital_channels_SpinBox.setValue(
754
            len([chnl for chnl in activation_config if 'd_ch' in chnl]))
755
        # laser channel
756
        self._pg.gen_laserchannel_ComboBox.clear()
757
        self._pg.gen_laserchannel_ComboBox.addItems(activation_config)
758
        index = self._pg.gen_laserchannel_ComboBox.findText(laser_channel)
759
        self._pg.gen_laserchannel_ComboBox.setCurrentIndex(index)
760
        # sample rate
761
        self._pg.gen_sample_freq_DSpinBox.setValue(sample_rate)
762
        # set activation config in block editor
763
        if self.block_editor.activation_config != activation_config:
764
            if self.block_editor.activation_config is None:
765
                self.block_editor.set_activation_config(activation_config)
766
                self.apply_generator_settings()
767
            else:
768
                self.block_editor.set_activation_config(activation_config)
769
        # unblock signals
770
        self._gs.sampled_file_format_comboBox.blockSignals(False)
771
        self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
772
        self._pg.gen_laserchannel_ComboBox.blockSignals(False)
773
        self._pg.gen_activation_config_ComboBox.blockSignals(False)
774
        return
775
776
    def block_add_last_clicked(self):
777
        """
778
779
        @return:
780
        """
781
        self.block_editor.insert_rows(self._pg.block_editor_TableWidget.rowCount(), 1)
782
        return
783
784
    def block_del_last_clicked(self):
785
        """
786
787
        @return:
788
        """
789
        self.block_editor.delete_row(self._pg.block_editor_TableWidget.rowCount() - 1)
790
        return
791
792
    def block_add_sel_clicked(self):
793
        """
794
795
        @return:
796
        """
797
        index = self._pg.block_editor_TableWidget.currentRow()
798
        self.block_editor.insert_rows(index + 1, 1)
799
        return
800
801
    def block_del_sel_clicked(self):
802
        """
803
804
        @return:
805
        """
806
        index = self._pg.block_editor_TableWidget.currentRow()
807
        self.block_editor.delete_row(index)
808
        return
809
810
    def block_clear_clicked(self):
811
        """
812
813
        @return:
814
        """
815
        self.block_editor.clear_table()
816
        return
817
818
    def organizer_add_last_clicked(self):
819
        """
820
821
        @return:
822
        """
823
        self.block_organizer.insert_rows(self._pg.block_organizer_TableWidget.rowCount(), 1)
824
        return
825
826
    def organizer_del_last_clicked(self):
827
        """
828
829
        @return:
830
        """
831
        self.block_organizer.delete_row(self._pg.block_organizer_TableWidget.rowCount() - 1)
832
        return
833
834
    def organizer_add_sel_clicked(self):
835
        """
836
837
        @return:
838
        """
839
        index = self._pg.block_organizer_TableWidget.currentRow()
840
        self.block_organizer.insert_rows(index + 1, 1)
841
        return
842
843
    def organizer_del_sel_clicked(self):
844
        """
845
846
        @return:
847
        """
848
        index = self._pg.block_organizer_TableWidget.currentRow()
849
        self.block_organizer.delete_row(index)
850
        return
851
852
    def organizer_clear_clicked(self):
853
        """
854
855
        @return:
856
        """
857
        self.block_organizer.clear_table()
858
        return
859
860
    def sequence_add_last_clicked(self):
861
        """
862
863
        @return:
864
        """
865
        self.sequence_editor.insert_rows(self._sg.sequence_editor_TableWidget.rowCount(), 1)
866
        return
867
868
    def sequence_del_last_clicked(self):
869
        """
870
871
        @return:
872
        """
873
        self.sequence_editor.delete_row(self._sg.sequence_editor_TableWidget.rowCount() - 1)
874
        return
875
876
    def sequence_add_sel_clicked(self):
877
        """
878
879
        @return:
880
        """
881
        index = self._sg.sequence_editor_TableWidget.currentRow()
882
        self.sequence_editor.insert_rows(index + 1, 1)
883
        return
884
885
    def sequence_del_sel_clicked(self):
886
        """
887
888
        @return:
889
        """
890
        index = self._sg.sequence_editor_TableWidget.currentRow()
891
        self.sequence_editor.delete_row(index)
892
        return
893
894
    def sequence_clear_clicked(self):
895
        """
896
897
        @return:
898
        """
899
        self.sequence_editor.clear_table()
900
        return
901
902
    def editor_generate_block_clicked(self):
903
        name = self._pg.curr_block_name_LineEdit.text()
904
        if name == '':
905
            self.log.error('No name has been entered for the PulseBlock to be generated.')
906
            return
907
        block_object = self.block_editor.generate_block_object(name)
908
        self._pulsed_master_logic.save_pulse_block(name, block_object)
909
        return
910
911
    def editor_delete_block_clicked(self):
912
        name = self._pg.saved_blocks_ComboBox.currentText()
913
        self._pulsed_master_logic.delete_pulse_block(name)
914
        return
915
916
    def editor_load_block_clicked(self):
917
        name = self._pg.saved_blocks_ComboBox.currentText()
918
        self._pulsed_master_logic.load_pulse_block(name)
919
        return
920
921
    def editor_generate_ensemble_clicked(self):
922
        name = self._pg.curr_ensemble_name_LineEdit.text()
923
        if name == '':
924
            self.log.error('No name has been entered for the PulseBlockEnsemble to be generated.')
925
            return
926
        rotating_frame = self._pg.curr_ensemble_rot_frame_CheckBox.isChecked()
927
        ensemble_object = self.block_organizer.generate_ensemble_object(name, rotating_frame)
928
        self._pulsed_master_logic.save_block_ensemble(name, ensemble_object)
929
        return
930
931
    def editor_delete_ensemble_clicked(self):
932
        name = self._pg.saved_ensembles_ComboBox.currentText()
933
        self._pulsed_master_logic.delete_block_ensemble(name)
934
        return
935
936
    def editor_load_ensemble_clicked(self):
937
        name = self._pg.saved_ensembles_ComboBox.currentText()
938
        self._pulsed_master_logic.load_block_ensemble(name)
939
        return
940 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
941
    def editor_generate_sequence_clicked(self):
942
        name = self._sg.curr_sequence_name_LineEdit.text()
943
        if name == '':
944
            self.log.error('No name has been entered for the PulseSequence to be generated.')
945
            return
946
        rotating_frame = self._sg.curr_sequence_rot_frame_CheckBox.isChecked()
947
        sequence_object = self.sequence_editor.generate_sequence_object(name, rotating_frame)
948
        self._pulsed_master_logic.save_sequence(name, sequence_object)
949
        return
950
951
    def editor_delete_sequence_clicked(self):
952
        name = self._sg.saved_sequences_ComboBox.currentText()
953
        self._pulsed_master_logic.delete_sequence(name)
954
        return
955
956
    def editor_load_sequence_clicked(self):
957
        name = self._sg.saved_sequences_ComboBox.currentText()
958
        self._pulsed_master_logic.load_sequence(name)
959
        return
960
961
    def load_block_in_editor(self, block_obj):
962
        self.block_editor.load_pulse_block(block_obj)
963
        if block_obj is not None:
964
            self._pg.curr_block_name_LineEdit.setText(block_obj.name)
965
        return
966
967
    def load_ensemble_in_editor(self, ensemble_obj, ensemble_params):
968
        self.block_organizer.load_pulse_block_ensemble(ensemble_obj)
969
        if ensemble_params != {}:
970
            self._pg.curr_ensemble_length_DSpinBox.setValue(ensemble_params['sequence_length'])
971
            self._pg.curr_ensemble_bins_SpinBox.setValue(ensemble_params['sequence_length_bins'])
972
            # FIXME: This is just a rough estimation of the waveform size in MB (only valid for AWG)
973
            size_mb = (ensemble_params['sequence_length_bins'] * 5) / 1024**2
974 View Code Duplication
            self._pg.curr_ensemble_size_DSpinBox.setValue(size_mb)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
975
            self._pg.curr_ensemble_laserpulses_SpinBox.setValue(ensemble_params['num_of_lasers'])
976
        else:
977
            self._pg.curr_ensemble_length_DSpinBox.setValue(0.0)
978
            self._pg.curr_ensemble_bins_SpinBox.setValue(0)
979
            self._pg.curr_ensemble_size_DSpinBox.setValue(0.0)
980
            self._pg.curr_ensemble_laserpulses_SpinBox.setValue(0)
981
        if ensemble_obj is not None:
982
            self._pg.curr_ensemble_name_LineEdit.setText(ensemble_obj.name)
983
        return
984
985
    def load_sequence_in_editor(self, sequence_obj, sequence_params):
986
        self.sequence_editor.load_pulse_sequence(sequence_obj)
987
        if sequence_params != {}:
988
            self._sg.curr_sequence_length_DSpinBox.setValue(sequence_params['sequence_length'])
989
            self._sg.curr_sequence_bins_SpinBox.setValue(sequence_params['sequence_length_bins'])
990
            # FIXME: This is just a rough estimation of the sequence size in MB
991
            size_mb = (sequence_params['sequence_length_bins'] * 5) / 1024**2
992
            self._sg.curr_sequence_size_DSpinBox.setValue(size_mb)
993
        else:
994
            self._sg.curr_sequence_length_DSpinBox.setValue(0.0)
995
            self._sg.curr_sequence_bins_SpinBox.setValue(0)
996
            self._sg.curr_sequence_size_DSpinBox.setValue(0.0)
997
        if sequence_obj is not None:
998
            self._sg.curr_sequence_name_LineEdit.setText(sequence_obj.name)
999
        return
1000
1001
    def update_block_dict(self, block_dict):
1002
        """
1003
1004
        @param block_dict:
1005
        @return:
1006
        """
1007
        self.block_organizer.set_block_dict(block_dict)
1008
        self._pg.saved_blocks_ComboBox.blockSignals(True)
1009
        self._pg.saved_blocks_ComboBox.clear()
1010
        self._pg.saved_blocks_ComboBox.addItems(list(block_dict))
1011
        self._pg.saved_blocks_ComboBox.blockSignals(False)
1012
        return
1013
1014
    def update_ensemble_dict(self, ensemble_dict):
1015
        """
1016
1017
        @param ensemble_dict:
1018
        @return:
1019
        """
1020
        # Check if an ensemble has been added. In that case set the current index to the new one.
1021
        # In all other cases try to maintain the current item and if it was removed, set the first.
1022
        text_to_set = None
1023
        if len(ensemble_dict) == self._pg.gen_ensemble_ComboBox.count() + 1:
1024
            for key in ensemble_dict:
1025
                if self._pg.gen_ensemble_ComboBox.findText(key) == -1:
1026
                    text_to_set = key
1027
        else:
1028
            text_to_set = self._pg.gen_ensemble_ComboBox.currentText()
1029
1030
        self.sequence_editor.set_ensemble_dict(ensemble_dict)
1031
        # block signals
1032
        self._pg.gen_ensemble_ComboBox.blockSignals(True)
1033
        self._pg.saved_ensembles_ComboBox.blockSignals(True)
1034
        # update gen_sequence_ComboBox items
1035
        self._pg.gen_ensemble_ComboBox.clear()
1036
        self._pg.gen_ensemble_ComboBox.addItems(list(ensemble_dict))
1037
        self._pg.saved_ensembles_ComboBox.clear()
1038
        self._pg.saved_ensembles_ComboBox.addItems(list(ensemble_dict))
1039
        if text_to_set is not None:
1040
            index = self._pg.gen_ensemble_ComboBox.findText(text_to_set)
1041
            if index != -1:
1042
                self._pg.gen_ensemble_ComboBox.setCurrentIndex(index)
1043
        # unblock signals
1044
        self._pg.gen_ensemble_ComboBox.blockSignals(False)
1045
        self._pg.saved_ensembles_ComboBox.blockSignals(False)
1046
        return
1047
1048
    def update_sequence_dict(self, sequence_dict):
1049
        """
1050
1051
        @param sequence_dict:
1052
        @return:
1053
        """
1054
        # Check if a sequence has been added. In that case set the current index to the new one.
1055
        # In all other cases try to maintain the current item and if it was removed, set the first.
1056
        text_to_set = None
1057
        if len(sequence_dict) == self._sg.gen_sequence_ComboBox.count() + 1:
1058
            for key in sequence_dict:
1059
                if self._sg.gen_sequence_ComboBox.findText(key) == -1:
1060
                    text_to_set = key
1061
        else:
1062
            text_to_set = self._sg.gen_sequence_ComboBox.currentText()
1063
1064
        # block signals
1065
        self._sg.gen_sequence_ComboBox.blockSignals(True)
1066
        self._sg.saved_sequences_ComboBox.blockSignals(True)
1067
        # update gen_sequence_ComboBox items
1068
        self._sg.gen_sequence_ComboBox.clear()
1069
        self._sg.gen_sequence_ComboBox.addItems(list(sequence_dict))
1070
        self._sg.saved_sequences_ComboBox.clear()
1071
        self._sg.saved_sequences_ComboBox.addItems(list(sequence_dict))
1072
        if text_to_set is not None:
1073
            index = self._sg.gen_sequence_ComboBox.findText(text_to_set)
1074
            if index != -1:
1075
                self._sg.gen_sequence_ComboBox.setCurrentIndex(index)
1076
        # unblock signals
1077
        self._sg.gen_sequence_ComboBox.blockSignals(False)
1078
        self._sg.saved_sequences_ComboBox.blockSignals(False)
1079
        return
1080
1081
    def saup_ensemble_clicked(self):
1082
        """
1083
        This method is called when the user clicks on "Sample + Upload Ensemble"
1084
        """
1085
        # Get the ensemble name from the ComboBox
1086
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
1087
        # disable buttons
1088
        self._pg.saup_ensemble_PushButton.setEnabled(False)
1089
        self._pg.sauplo_ensemble_PushButton.setEnabled(False)
1090
        # Sample and upload the ensemble via logic module
1091
        self._pulsed_master_logic.sample_block_ensemble(ensemble_name, False)
1092
        return
1093
1094
    def saup_ensemble_finished(self, ensemble_name):
1095
        """
1096
        This method
1097
        """
1098
        # enable buttons
1099
        self._pg.saup_ensemble_PushButton.setEnabled(True)
1100
        self._pg.sauplo_ensemble_PushButton.setEnabled(True)
1101
        return
1102
1103
    def sauplo_ensemble_clicked(self):
1104
        """
1105
        This method is called when the user clicks on "Sample + Upload + Load Ensemble"
1106
        """
1107
        # Get the ensemble name from the ComboBox
1108
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
1109
        # disable buttons
1110
        self._pg.saup_ensemble_PushButton.setEnabled(False)
1111
        self._pg.sauplo_ensemble_PushButton.setEnabled(False)
1112
        self._pg.load_ensemble_PushButton.setEnabled(False)
1113
        # Sample, upload and load the ensemble via logic module
1114
        self._pulsed_master_logic.sample_block_ensemble(ensemble_name, True)
1115
        return
1116
1117
    def saup_sequence_clicked(self):
1118
        """
1119
        This method is called when the user clicks on "Sample + Upload Sequence"
1120
        """
1121
        # Get the sequence name from the ComboBox
1122
        sequence_name = self._sg.gen_sequence_ComboBox.currentText()
1123
        # disable buttons
1124
        self._sg.saup_sequence_PushButton.setEnabled(False)
1125
        self._sg.sauplo_sequence_PushButton.setEnabled(False)
1126
        # Sample the sequence via logic module
1127
        self._pulsed_master_logic.sample_sequence(sequence_name, False)
1128
        return
1129
1130
    def saup_sequence_finished(self, sequence_name):
1131
        """
1132
        This method
1133
        """
1134
        # enable buttons
1135
        self._sg.saup_sequence_PushButton.setEnabled(True)
1136
        self._sg.sauplo_sequence_PushButton.setEnabled(True)
1137
        return
1138
1139
    def sauplo_sequence_clicked(self):
1140
        """
1141
        This method is called when the user clicks on "Sample + Upload + Load Sequence"
1142
        """
1143
        # Get the sequence name from the ComboBox
1144
        sequence_name = self._sg.gen_sequence_ComboBox.currentText()
1145
        # disable buttons
1146
        self._sg.saup_sequence_PushButton.setEnabled(False)
1147
        self._sg.sauplo_sequence_PushButton.setEnabled(False)
1148
        self._sg.load_sequence_PushButton.setEnabled(False)
1149
        # Sample the sequence via logic module
1150
        self._pulsed_master_logic.sample_sequence(sequence_name, True)
1151
        return
1152
1153
    def generate_predefined_clicked(self, button_obj=None):
1154
        """
1155
1156
        @param button_obj:
1157
        @return:
1158
        """
1159
        if type(button_obj) is bool:
1160
            button_obj = self.sender()
1161
        method_name = button_obj.objectName()
1162
        if method_name.startswith('gen_'):
1163
            method_name = method_name[4:]
1164
        elif method_name.startswith('sauplo_'):
1165
            method_name = method_name[7:]
1166
        else:
1167
            self.log.error('Strange naming of generate buttons in predefined methods occured.')
1168
            return
1169
1170
        # get parameters from input widgets
1171
        param_searchstr = method_name + '_param_'
1172
        param_widgets = [widget for widget in dir(self._pm) if widget.startswith(param_searchstr)]
1173
        # Store parameters together with the parameter names in a dictionary
1174
        param_dict = dict()
1175
        for widget_name in param_widgets:
1176
            input_obj = getattr(self._pm, widget_name)
1177
            param_name = widget_name.replace(param_searchstr, '').replace('_Widget', '')
1178
1179
            if hasattr(input_obj, 'isChecked'):
1180
                param_dict[param_name] = input_obj.isChecked()
1181
            elif hasattr(input_obj, 'value'):
1182
                param_dict[param_name] = input_obj.value()
1183
            elif hasattr(input_obj, 'text'):
1184
                param_dict[param_name] = input_obj.text()
1185
            else:
1186
                self.log.error('Not possible to get the value from the widgets, since it does not '
1187
                               'have one of the possible access methods!')
1188
                return
1189
1190
        # get global parameters and add them to the dictionary
1191
        for param_name in predefined_global_parameter_list:
1192
            input_obj = getattr(self._pm, 'pm_' + param_name + '_Widget')
1193
1194
            if hasattr(input_obj, 'isChecked'):
1195
                param_dict[param_name] = input_obj.isChecked()
1196
            elif hasattr(input_obj, 'value'):
1197
                param_dict[param_name] = input_obj.value()
1198
            elif hasattr(input_obj, 'text'):
1199
                param_dict[param_name] = input_obj.text()
1200
            else:
1201
                self.log.error('Not possible to get the value from the widgets, since it does not '
1202
                               'have one of the possible access methods!')
1203
                return
1204
1205
        self._pulsed_master_logic.generate_predefined_sequence(method_name, param_dict)
1206
        return
1207
1208
    def generate_sauplo_predefined_clicked(self):
1209
        button_obj = self.sender()
1210
        method_name = button_obj.objectName()[7:]
1211
        self.generate_predefined_clicked(button_obj)
1212
        # get name of the generated ensemble
1213
        if not hasattr(self._pm, method_name + '_param_name_Widget'):
1214
            self.log.error('Predefined sequence methods must have an argument called "name" in '
1215
                           'order to use the sample/upload/load functionality. It must be the '
1216
                           'naming of the generated asset.\n"{0}" has probably been generated '
1217
                           'but not sampled/uploaded/loaded'.format(method_name))
1218
            return
1219
        input_obj = getattr(self._pm, method_name + '_param_name_Widget')
1220
        if not hasattr(input_obj, 'text'):
1221
            self.log.error('Predefined sequence methods must have as first argument the name of '
1222
                           'the asset to be generated.')
1223
            return
1224
        asset_name = input_obj.text()
1225
1226
        # disable buttons
1227
        self._pg.saup_ensemble_PushButton.setEnabled(False)
1228
        self._pg.sauplo_ensemble_PushButton.setEnabled(False)
1229
        self._pg.load_ensemble_PushButton.setEnabled(False)
1230
1231
        self._pulsed_master_logic.sample_block_ensemble(asset_name, True)
1232
        return
1233
1234
    ###########################################################################
1235
    ###        Methods related to Settings for the 'Analysis' Tab:          ###
1236
    ###########################################################################
1237
    #FIXME: Implement the setting for 'Analysis' tab.
1238
    def _activate_analysis_settings_ui(self):
1239
        """ Initialize, connect and configure the Settings of 'Analysis' Tab.
1240
        """
1241
        self._as = AnalysisSettingDialog()
1242
        self._as.accepted.connect(self.update_analysis_settings)
1243
        self._as.rejected.connect(self.keep_former_analysis_settings)
1244
        self._as.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_analysis_settings)
1245
1246
        self._as.ana_param_x_axis_name_LineEdit.setText(self._ana_param_x_axis_name_text)
1247
        self._as.ana_param_x_axis_unit_LineEdit.setText(self._ana_param_x_axis_unit_text)
1248
        self._as.ana_param_y_axis_name_LineEdit.setText(self._ana_param_y_axis_name_text)
1249
        self._as.ana_param_y_axis_unit_LineEdit.setText(self._ana_param_y_axis_unit_text)
1250
        self._as.ana_param_second_plot_x_axis_name_LineEdit.setText(self._ana_param_second_plot_x_axis_name_text)
1251
        self._as.ana_param_second_plot_x_axis_unit_LineEdit.setText(self._ana_param_second_plot_x_axis_unit_text)
1252
        self._as.ana_param_second_plot_y_axis_name_LineEdit.setText(self._ana_param_second_plot_y_axis_name_text)
1253
        self._as.ana_param_second_plot_y_axis_unit_LineEdit.setText(self._ana_param_second_plot_y_axis_unit_text)
1254
        self._as.ana_param_couple_settings_checkBox.setChecked(self._pulsed_master_logic.couple_generator_hw)
1255
        self.update_analysis_settings()
1256
        return
1257
1258
    def _deactivate_analysis_settings_ui(self):
1259
        """ Disconnects the configuration of the Settings for 'Analysis' Tab.
1260
        """
1261
        # FIXME: disconnect something
1262
        return
1263
1264
    def update_analysis_settings(self):
1265
        """ Apply the new settings """
1266
        self._ana_param_x_axis_name_text = self._as.ana_param_x_axis_name_LineEdit.text()
1267
        self._ana_param_x_axis_unit_text = self._as.ana_param_x_axis_unit_LineEdit.text()
1268
        self._ana_param_y_axis_name_text = self._as.ana_param_y_axis_name_LineEdit.text()
1269
        self._ana_param_y_axis_unit_text = self._as.ana_param_y_axis_unit_LineEdit.text()
1270
1271 View Code Duplication
        if self._pa.second_plot_ComboBox.currentText() == 'FFT':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1272
            self._ana_param_second_plot_x_axis_name_text = self._as.ana_param_second_plot_x_axis_name_LineEdit.text()
1273
            self._ana_param_second_plot_x_axis_unit_text = self._as.ana_param_second_plot_x_axis_unit_LineEdit.text()
1274
            self._ana_param_second_plot_y_axis_name_text = self._as.ana_param_second_plot_y_axis_name_LineEdit.text()
1275
            self._ana_param_second_plot_y_axis_unit_text = self._as.ana_param_second_plot_y_axis_unit_LineEdit.text()
1276
        else:
1277
            self._ana_param_second_plot_x_axis_name_text = self._ana_param_x_axis_name_text
1278
            self._ana_param_second_plot_x_axis_unit_text = self._ana_param_x_axis_unit_text
1279
            self._ana_param_second_plot_y_axis_name_text = self._ana_param_y_axis_name_text
1280
            self._ana_param_second_plot_y_axis_unit_text = self._ana_param_y_axis_unit_text
1281
1282
        self._pa.pulse_analysis_PlotWidget.setLabel(
1283
            axis='bottom',
1284
            text=self._ana_param_x_axis_name_text,
1285
            units=self._ana_param_x_axis_unit_text)
1286
        self._pa.pulse_analysis_PlotWidget.setLabel(
1287
            axis='left',
1288
            text=self._ana_param_y_axis_name_text,
1289
            units=self._ana_param_y_axis_unit_text)
1290
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
1291
            axis='bottom',
1292
            text=self._ana_param_second_plot_x_axis_name_text,
1293
            units=self._ana_param_second_plot_x_axis_unit_text)
1294
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
1295
            axis='left',
1296
            text=self._ana_param_second_plot_y_axis_name_text,
1297
            units=self._ana_param_second_plot_y_axis_unit_text)
1298
        self._pe.measuring_error_PlotWidget.setLabel(
1299
            axis='bottom',
1300
            text=self._ana_param_x_axis_name_text,
1301
            units=self._ana_param_x_axis_unit_text)
1302
1303
        couple_settings = self._as.ana_param_couple_settings_checkBox.isChecked()
1304
        self._pulsed_master_logic.couple_generator_hw = couple_settings
1305
        if couple_settings:
1306
            self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
1307
            self._pg.gen_activation_config_ComboBox.blockSignals(True)
1308
            self._pg.gen_sample_freq_DSpinBox.setEnabled(False)
1309
            self._pg.gen_activation_config_ComboBox.setEnabled(False)
1310
        else:
1311
            self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
1312
            self._pg.gen_activation_config_ComboBox.blockSignals(False)
1313
            self._pg.gen_sample_freq_DSpinBox.setEnabled(True)
1314
            self._pg.gen_activation_config_ComboBox.setEnabled(True)
1315
        # FIXME: Not very elegant
1316
        self._pulsed_master_logic._measurement_logic.fc.set_units(
1317
            [self._ana_param_x_axis_unit_text, self._ana_param_y_axis_unit_text])
1318
        return
1319
1320
    def keep_former_analysis_settings(self):
1321
        """ Keep the old settings """
1322
        #FIXME: Implement the behaviour
1323
        pass
1324
1325
    def show_analysis_settings(self):
1326
        """ Open the Analysis Settings Window. """
1327
        self._as.exec_()
1328
        return
1329
1330
    ###########################################################################
1331
    ###     Methods related to the Tab 'Analysis' in the Pulsed Window:     ###
1332
    ###########################################################################
1333
    def setup_toolbar(self):
1334
        # create all the needed control widgets on the fly and connect their
1335
        # actions to each other:
1336
        self._mw.pulser_on_off_PushButton = QtWidgets.QPushButton()
1337
        self._mw.pulser_on_off_PushButton.setText('Pulser ON')
1338
        self._mw.pulser_on_off_PushButton.setToolTip('Switch the device on and off.')
1339
        self._mw.pulser_on_off_PushButton.setCheckable(True)
1340
        self._mw.control_ToolBar.addWidget(self._mw.pulser_on_off_PushButton)
1341
1342
        self._mw.clear_device_PushButton = QtWidgets.QPushButton(self._mw)
1343
        self._mw.clear_device_PushButton.setText('Clear Pulser')
1344
        self._mw.clear_device_PushButton.setToolTip(
1345
            'Clear the Pulser Device Memory\nfrom all loaded files.')
1346
        self._mw.control_ToolBar.addWidget(self._mw.clear_device_PushButton)
1347
1348
        self._mw.current_loaded_asset_Label = QtWidgets.QLabel(self._mw)
1349
        sizepolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
1350
                                           QtWidgets.QSizePolicy.Fixed)
1351
        sizepolicy.setHorizontalStretch(0)
1352
        sizepolicy.setVerticalStretch(0)
1353
        sizepolicy.setHeightForWidth(
1354
            self._mw.current_loaded_asset_Label.sizePolicy().hasHeightForWidth())
1355
        self._mw.current_loaded_asset_Label.setSizePolicy(sizepolicy)
1356
        self._mw.current_loaded_asset_Label.setText('  No Asset Loaded')
1357
        self._mw.current_loaded_asset_Label.setToolTip('Display the currently loaded asset.')
1358
        self._mw.control_ToolBar.addWidget(self._mw.current_loaded_asset_Label)
1359
1360
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit()
1361
        self._mw.save_tag_LineEdit.setMaximumWidth(200)
1362
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)
1363
1364
    def setup_extraction_ui(self):
1365
        self.lasertrace_image = pg.PlotDataItem(np.array(range(10)), np.zeros(10), pen=palette.c1)
1366
        self._pe.laserpulses_PlotWidget.addItem(self.lasertrace_image)
1367
        self._pe.laserpulses_PlotWidget.addItem(self.sig_start_line)
1368
        self._pe.laserpulses_PlotWidget.addItem(self.sig_end_line)
1369
        self._pe.laserpulses_PlotWidget.addItem(self.ref_start_line)
1370
        self._pe.laserpulses_PlotWidget.addItem(self.ref_end_line)
1371
        self._pe.laserpulses_PlotWidget.setLabel(axis='bottom', text='time', units='s')
1372
1373
    def _activate_analysis_ui(self):
1374
        """ Initialize, connect and configure the 'Analysis' Tab.
1375
        """
1376
        self._pa.ana_param_errorbars_CheckBox.setChecked(self._ana_param_errorbars)
1377
        index = self._pa.second_plot_ComboBox.findText(self._second_plot_ComboBox_text)
1378
        self._pa.second_plot_ComboBox.setCurrentIndex(index)
1379
        self._pulsed_master_logic._measurement_logic.second_plot_type = self._second_plot_ComboBox_text
1380
1381
        self._pa.ana_param_invoke_settings_CheckBox.setChecked(
1382
            self._pulsed_master_logic.invoke_settings)
1383
1384
        # Fit settings dialog
1385
        self._fsd = FitSettingsDialog(self._pulsed_master_logic._measurement_logic.fc)
1386
        self._fsd.sigFitsUpdated.connect(self._pa.fit_param_fit_func_ComboBox.setFitFunctions)
1387
        self._fsd.applySettings()
1388
1389
        # Configure the main pulse analysis display:
1390
        self.signal_image = pg.PlotDataItem(np.array(range(10)),
1391
                                            np.zeros(10),
1392
                                            pen=pg.mkPen(palette.c1,
1393
                                                         style=QtCore.Qt.DotLine),
1394
                                            style=QtCore.Qt.DotLine,
1395
                                            symbol='o',
1396
                                            symbolPen=palette.c1,
1397
                                            symbolBrush=palette.c1,
1398
                                            symbolSize=7)
1399
1400
        self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image)
1401
        self.signal_image2 = pg.PlotDataItem(pen=pg.mkPen(palette.c4,
1402
                                                          style=QtCore.Qt.DotLine),
1403
                                             style=QtCore.Qt.DotLine,
1404
                                             symbol='o',
1405
                                             symbolPen=palette.c4,
1406
                                             symbolBrush=palette.c4,
1407
                                             symbolSize=7)
1408
        self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image2)
1409
        self._pa.pulse_analysis_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
1410
1411
        # Configure the fit of the data in the main pulse analysis display:
1412
        self.fit_image = pg.PlotDataItem(pen=palette.c3)
1413
        self._pa.pulse_analysis_PlotWidget.addItem(self.fit_image)
1414
1415
        # Configure the errorbars of the data in the main pulse analysis display:
1416
        self.signal_image_error_bars = pg.ErrorBarItem(x=np.array(range(10)),
1417
                                                       y=np.zeros(10),
1418
                                                       top=0., bottom=0.,
1419
                                                       pen=palette.c2)
1420
        self.signal_image_error_bars2 = pg.ErrorBarItem(x=np.array(range(10)),
1421
                                                        y=np.zeros(10),
1422
                                                        top=0., bottom=0.,
1423
                                                        pen=palette.c5)
1424
        self.second_image_error_bars = pg.ErrorBarItem(x=np.array(range(10)),
1425
                                                        y=np.zeros(10),
1426
                                                        top=0., bottom=0.,
1427
                                                        pen=palette.c5)
1428
1429
        # Configure the second pulse analysis display:
1430
        self.second_plot_image = pg.PlotDataItem(np.array(range(10)),
1431
                                                 np.zeros(10), pen=palette.c1)
1432
        self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image)
1433
        self.second_plot_image2 = pg.PlotDataItem(pen=palette.c4)
1434
        self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image2)
1435
        self._pa.pulse_analysis_second_PlotWidget.showGrid(x=True, y=True,
1436
                                                           alpha=0.8)
1437
1438
        # Configure the lasertrace plot display:
1439
        self.sig_start_line = pg.InfiniteLine(pos=0,
1440
                                              pen={'color': palette.c3, 'width': 1},
1441
                                              movable=True)
1442
        #self.sig_start_line.setHoverPen(QtGui.QPen(palette.c3), width=10)
1443
        self.sig_end_line = pg.InfiniteLine(pos=0,
1444
                                            pen={'color': palette.c3, 'width': 1},
1445
                                            movable=True)
1446
        #self.sig_end_line.setHoverPen(QtGui.QPen(palette.c3), width=10)
1447
        self.ref_start_line = pg.InfiniteLine(pos=0,
1448
                                              pen={'color': palette.c4, 'width': 1},
1449
                                              movable=True)
1450
        #self.ref_start_line.setHoverPen(QtGui.QPen(palette.c4), width=10)
1451
        self.ref_end_line = pg.InfiniteLine(pos=0,
1452
                                            pen={'color': palette.c4, 'width': 1},
1453
                                            movable=True)
1454
        #self.ref_end_line.setHoverPen(QtGui.QPen(palette.c4), width=10)
1455
        # Configure the measuring error display:
1456
        self.measuring_error_image = pg.PlotDataItem(np.array(range(10)),
1457
                                                     np.zeros(10),
1458
                                                     pen=palette.c1)
1459
        self.measuring_error_image2 = pg.PlotDataItem(np.array(range(10)),
1460
                                                      np.zeros(10),
1461
                                                      pen=palette.c3)
1462
        self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image)
1463
        self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image2)
1464
        self._pe.measuring_error_PlotWidget.setLabel('left', 'measuring error',
1465
                                                     units='a.u.')
1466
        #self._pe.measuring_error_PlotWidget.setLabel('bottom', 'tau', units='s')
1467
1468
1469
        # set boundaries
1470
        self._pe.extract_param_conv_std_dev_slider.setRange(1, 200)
1471
        self._pe.extract_param_conv_std_dev_DSpinBox.setRange(1, 200)
1472
        self._pa.ana_param_x_axis_start_ScienDSpinBox.setRange(0, 1.0e99)
1473
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.setRange(0, 1.0e99)
1474
        self._pa.ana_param_num_laser_pulse_SpinBox.setRange(1, 1e6)
1475
        self._pa.ana_param_record_length_SpinBox.setRange(0, 1.0e99)
1476
        self._pa.time_param_ana_periode_DoubleSpinBox.setRange(0, 1.0e99)
1477
        self._pa.ext_control_mw_freq_DoubleSpinBox.setRange(0, 1.0e99)
1478
        self._pa.ext_control_mw_power_DoubleSpinBox.setRange(-200, 1.0e99)
1479
        self._pe.extract_param_threshold_SpinBox.setRange(1, 2**31-1)
1480
1481
        # ---------------------------------------------------------------------
1482
        #                         Connect signals
1483
        # ---------------------------------------------------------------------
1484
        # connect update signals from logic
1485
        self._pulsed_master_logic.sigSignalDataUpdated.connect(self.signal_data_updated)
1486
        self._pulsed_master_logic.sigLaserDataUpdated.connect(self.laser_data_updated)
1487
        self._pulsed_master_logic.sigLaserToShowUpdated.connect(self.laser_to_show_updated)
1488
        self._pulsed_master_logic.sigElapsedTimeUpdated.connect(self.elapsed_time_updated)
1489
        self._pulsed_master_logic.sigFitUpdated.connect(self.fit_data_updated)
1490
        self._pulsed_master_logic.sigMeasurementStatusUpdated.connect(self.measurement_status_updated)
1491
        self._pulsed_master_logic.sigPulserRunningUpdated.connect(self.pulser_running_updated)
1492
        self._pulsed_master_logic.sigFastCounterSettingsUpdated.connect(self.fast_counter_settings_updated)
1493
        self._pulsed_master_logic.sigMeasurementSequenceSettingsUpdated.connect(self.measurement_sequence_settings_updated)
1494
        self._pulsed_master_logic.sigPulserSettingsUpdated.connect(self.pulse_generator_settings_updated)
1495
        self._pulsed_master_logic.sigUploadedAssetsUpdated.connect(self.update_uploaded_assets)
1496
        self._pulsed_master_logic.sigLoadedAssetUpdated.connect(self.update_loaded_asset)
1497
        self._pulsed_master_logic.sigExtMicrowaveSettingsUpdated.connect(self.microwave_settings_updated)
1498
        self._pulsed_master_logic.sigExtMicrowaveRunningUpdated.connect(self.microwave_running_updated)
1499
        self._pulsed_master_logic.sigTimerIntervalUpdated.connect(self.measurement_timer_updated)
1500
        self._pulsed_master_logic.sigAnalysisSettingsUpdated.connect(self.analysis_settings_updated)
1501
        self._pulsed_master_logic.sigAnalysisMethodsUpdated.connect(self.analysis_methods_updated)
1502
        self._pulsed_master_logic.sigExtractionSettingsUpdated.connect(self.extraction_settings_updated)
1503
        self._pulsed_master_logic.sigExtractionMethodsUpdated.connect(self.extraction_methods_updated)
1504
1505
        # connect button click signals
1506
        self._pg.load_ensemble_PushButton.clicked.connect(self.load_ensemble_clicked)
1507
        self._sg.load_sequence_PushButton.clicked.connect(self.load_sequence_clicked)
1508
        self._mw.pulser_on_off_PushButton.clicked.connect(self.pulser_on_off_clicked)
1509
        self._mw.clear_device_PushButton.clicked.connect(self.clear_pulser_clicked)
1510
        self._pa.fit_param_PushButton.clicked.connect(self.fit_clicked)
1511
1512
        # connect action trigger signals
1513
        self._mw.action_run_stop.triggered.connect(self.measurement_run_stop_clicked)
1514
        self._mw.action_continue_pause.triggered.connect(self.measurement_continue_pause_clicked)
1515
        self._mw.action_pull_data.triggered.connect(self.pull_data_clicked)
1516
        self._mw.action_save.triggered.connect(self.save_clicked)
1517
        self._mw.action_Settings_Analysis.triggered.connect(self.show_analysis_settings)
1518
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)
1519
1520
        # connect checkbox click signals
1521
        self._pa.ext_control_use_mw_CheckBox.stateChanged.connect(self.ext_mw_params_changed)
1522
        self._pa.ana_param_invoke_settings_CheckBox.stateChanged.connect(self.toggle_settings_editor)
1523
        self._pa.ana_param_alternating_CheckBox.stateChanged.connect(self.measurement_sequence_settings_changed)
1524
        self._pa.ana_param_ignore_first_CheckBox.stateChanged.connect(self.measurement_sequence_settings_changed)
1525
        self._pa.ana_param_ignore_last_CheckBox.stateChanged.connect(self.measurement_sequence_settings_changed)
1526
        self._pe.laserpulses_display_raw_CheckBox.stateChanged.connect(self.laser_to_show_changed)
1527
        self._pa.ana_param_errorbars_CheckBox.stateChanged.connect(self.toggle_error_bars)
1528
        self._pa.pulser_use_interleave_CheckBox.stateChanged.connect(self.pulse_generator_settings_changed)
1529
1530
        # connect spinbox changed signals
1531
        self._pa.ana_param_num_laser_pulse_SpinBox.editingFinished.connect(self.measurement_sequence_settings_changed)
1532
        self._pa.ana_param_record_length_SpinBox.editingFinished.connect(self.fast_counter_settings_changed)
1533
        self._pa.time_param_ana_periode_DoubleSpinBox.editingFinished.connect(self.measurement_timer_changed)
1534
        self._pa.ext_control_mw_freq_DoubleSpinBox.editingFinished.connect(self.ext_mw_params_changed)
1535
        self._pa.ext_control_mw_power_DoubleSpinBox.editingFinished.connect(self.ext_mw_params_changed)
1536
        self._pa.pulser_sample_freq_DSpinBox.editingFinished.connect(self.pulse_generator_settings_changed)
1537
        self._pa.ana_param_x_axis_start_ScienDSpinBox.editingFinished.connect(self.measurement_sequence_settings_changed)
1538
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.editingFinished.connect(self.measurement_sequence_settings_changed)
1539
        self._pe.extract_param_ana_window_start_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
1540
        self._pe.extract_param_ana_window_width_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
1541
        self._pe.extract_param_ref_window_start_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
1542
        self._pe.extract_param_ref_window_width_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
1543
        self._pe.extract_param_conv_std_dev_DSpinBox.editingFinished.connect(self.extraction_settings_changed)
1544
        self._pe.extract_param_threshold_SpinBox.editingFinished.connect(self.extraction_settings_changed)
1545
        self._pe.extract_param_min_laser_length_SpinBox.editingFinished.connect(self.extraction_settings_changed)
1546
        self._pe.extract_param_tolerance_SpinBox.editingFinished.connect(self.extraction_settings_changed)
1547
1548
        # connect combobox changed signals
1549
        self._pa.ana_param_fc_bins_ComboBox.currentIndexChanged.connect(self.fast_counter_settings_changed)
1550
        self._pa.second_plot_ComboBox.currentIndexChanged.connect(self.change_second_plot)
1551
        self._pa.pulser_activation_config_ComboBox.currentIndexChanged.connect(self.pulse_generator_settings_changed)
1552
        self._pe.laserpulses_ComboBox.currentIndexChanged.connect(self.laser_to_show_changed)
1553
        self._pe.extract_param_analysis_method_comboBox.currentIndexChanged.connect(self.analysis_settings_changed)
1554
        self._pe.extract_param_extraction_method_comboBox.currentIndexChanged.connect(self.extraction_settings_changed)
1555
1556
        # connect other widgets changed signals
1557
        self.sig_start_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
1558
        self.sig_end_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
1559
        self.ref_start_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
1560
        self.ref_end_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
1561
        self._pe.extract_param_conv_std_dev_slider.valueChanged.connect(self.extraction_settings_changed)
1562
1563
1564
        # apply hardware constraints
1565
        self._analysis_apply_hardware_constraints()
1566
1567
        # initialize values
1568
        self._pulsed_master_logic.request_measurement_init_values()
1569
        return
1570
1571
    def _deactivate_analysis_ui(self):
1572
        """ Disconnects the configuration for 'Analysis' Tab.
1573
        """
1574
        self.measurement_run_stop_clicked(False)
1575
1576
        self._ana_param_errorbars = self._pa.ana_param_errorbars_CheckBox.isChecked()
1577
        self._second_plot_ComboBox_text = self._pa.second_plot_ComboBox.currentText()
1578
1579
        # disconnect signals
1580
        self._pulsed_master_logic.sigSignalDataUpdated.disconnect()
1581
        self._pulsed_master_logic.sigLaserDataUpdated.disconnect()
1582
        self._pulsed_master_logic.sigLaserToShowUpdated.disconnect()
1583
        self._pulsed_master_logic.sigElapsedTimeUpdated.disconnect()
1584
        self._pulsed_master_logic.sigFitUpdated.disconnect()
1585
        self._pulsed_master_logic.sigMeasurementStatusUpdated.disconnect()
1586
        self._pulsed_master_logic.sigPulserRunningUpdated.disconnect()
1587
        self._pulsed_master_logic.sigFastCounterSettingsUpdated.disconnect()
1588
        self._pulsed_master_logic.sigMeasurementSequenceSettingsUpdated.disconnect()
1589
        self._pulsed_master_logic.sigPulserSettingsUpdated.disconnect()
1590
        self._pulsed_master_logic.sigUploadedAssetsUpdated.disconnect()
1591
        self._pulsed_master_logic.sigLoadedAssetUpdated.disconnect()
1592
        self._pulsed_master_logic.sigExtMicrowaveSettingsUpdated.disconnect()
1593
        self._pulsed_master_logic.sigExtMicrowaveRunningUpdated.disconnect()
1594
        self._pulsed_master_logic.sigTimerIntervalUpdated.disconnect()
1595
        self._pulsed_master_logic.sigAnalysisSettingsUpdated.disconnect()
1596
        self._pulsed_master_logic.sigAnalysisMethodsUpdated.disconnect()
1597
        self._pulsed_master_logic.sigExtractionSettingsUpdated.disconnect()
1598
        self._pulsed_master_logic.sigExtractionMethodsUpdated.disconnect()
1599
        self._pg.load_ensemble_PushButton.clicked.disconnect()
1600
        self._sg.load_sequence_PushButton.clicked.disconnect()
1601
        self._mw.pulser_on_off_PushButton.clicked.disconnect()
1602
        self._mw.clear_device_PushButton.clicked.disconnect()
1603
        self._pa.fit_param_PushButton.clicked.disconnect()
1604
        self._mw.action_run_stop.triggered.disconnect()
1605
        self._mw.action_continue_pause.triggered.disconnect()
1606
        self._mw.action_pull_data.triggered.disconnect()
1607
        self._mw.action_save.triggered.disconnect()
1608
        self._mw.action_Settings_Analysis.triggered.disconnect()
1609
        self._pa.ext_control_use_mw_CheckBox.stateChanged.disconnect()
1610
        self._pa.ana_param_invoke_settings_CheckBox.stateChanged.disconnect()
1611
        self._pa.ana_param_alternating_CheckBox.stateChanged.disconnect()
1612
        self._pa.ana_param_ignore_first_CheckBox.stateChanged.disconnect()
1613
        self._pa.ana_param_ignore_last_CheckBox.stateChanged.disconnect()
1614
        self._pe.laserpulses_display_raw_CheckBox.stateChanged.disconnect()
1615
        self._pa.ana_param_errorbars_CheckBox.stateChanged.disconnect()
1616
        self._pa.pulser_use_interleave_CheckBox.stateChanged.disconnect()
1617
        self._pa.ana_param_num_laser_pulse_SpinBox.editingFinished.disconnect()
1618
        self._pa.ana_param_record_length_SpinBox.editingFinished.disconnect()
1619
        self._pa.time_param_ana_periode_DoubleSpinBox.editingFinished.disconnect()
1620
        self._pa.ext_control_mw_freq_DoubleSpinBox.editingFinished.disconnect()
1621
        self._pa.ext_control_mw_power_DoubleSpinBox.editingFinished.disconnect()
1622
        self._pa.pulser_sample_freq_DSpinBox.editingFinished.disconnect()
1623
        self._pa.ana_param_x_axis_start_ScienDSpinBox.editingFinished.disconnect()
1624
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.editingFinished.disconnect()
1625
        self._pe.extract_param_ana_window_start_DSpinBox.editingFinished.disconnect()
1626
        self._pe.extract_param_ana_window_width_DSpinBox.editingFinished.disconnect()
1627
        self._pe.extract_param_ref_window_start_DSpinBox.editingFinished.disconnect()
1628
        self._pe.extract_param_ref_window_width_DSpinBox.editingFinished.disconnect()
1629
        self._pe.extract_param_conv_std_dev_DSpinBox.editingFinished.disconnect()
1630
        self._pe.extract_param_threshold_SpinBox.editingFinished.disconnect()
1631
        self._pe.extract_param_min_laser_length_SpinBox.editingFinished.disconnect()
1632
        self._pe.extract_param_tolerance_SpinBox.editingFinished.disconnect()
1633
        self._pa.ana_param_fc_bins_ComboBox.currentIndexChanged.disconnect()
1634
        self._pa.second_plot_ComboBox.currentIndexChanged.disconnect()
1635
        self._pa.pulser_activation_config_ComboBox.currentIndexChanged.disconnect()
1636
        self._pe.laserpulses_ComboBox.currentIndexChanged.disconnect()
1637
        self._pe.extract_param_analysis_method_comboBox.currentIndexChanged.disconnect()
1638
        self._pe.extract_param_extraction_method_comboBox.currentIndexChanged.disconnect()
1639
        self.sig_start_line.sigPositionChangeFinished.disconnect()
1640
        self.sig_end_line.sigPositionChangeFinished.disconnect()
1641
        self.ref_start_line.sigPositionChangeFinished.disconnect()
1642
        self.ref_end_line.sigPositionChangeFinished.disconnect()
1643
        self._pe.extract_param_conv_std_dev_slider.valueChanged.disconnect()
1644
        self._fsd.sigFitsUpdated.disconnect()
1645
        return
1646
1647
    def _analysis_apply_hardware_constraints(self):
1648
        """
1649
        Retrieve the constraints from pulser and fast counter hardware and apply these constraints
1650
        to the analysis tab GUI elements.
1651
        """
1652
        # block signals
1653
        self._pa.pulser_activation_config_ComboBox.blockSignals(True)
1654
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(True)
1655
        # apply constraints
1656
        pulser_constr, fastcounter_constr = self._pulsed_master_logic.get_hardware_constraints()
1657 View Code Duplication
        self._pa.pulser_sample_freq_DSpinBox.setMinimum(pulser_constr.sample_rate.min)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1658
        self._pa.pulser_sample_freq_DSpinBox.setMaximum(pulser_constr.sample_rate.max)
1659
        self._pa.pulser_activation_config_ComboBox.clear()
1660
        self._pa.pulser_activation_config_ComboBox.addItems(list(pulser_constr.activation_config))
1661
        self._pa.ana_param_fc_bins_ComboBox.clear()
1662
        for binwidth in fastcounter_constr['hardware_binwidth_list']:
1663
            self._pa.ana_param_fc_bins_ComboBox.addItem(str(binwidth))
1664
        # unblock signals
1665
        self._pa.pulser_activation_config_ComboBox.blockSignals(False)
1666
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(False)
1667
        return
1668
1669
    def measurement_run_stop_clicked(self, isChecked):
1670
        """ Manages what happens if pulsed measurement is started or stopped.
1671
1672
        @param bool isChecked: start scan if that is possible
1673
        """
1674
        if isChecked:
1675
            self._pulsed_master_logic.start_measurement()
1676
        else:
1677
            self._pulsed_master_logic.stop_measurement()
1678
        return
1679
1680
    def measurement_continue_pause_clicked(self, isChecked):
1681
        """ Continues and pauses the measurement. """
1682
        if isChecked:
1683
            self._pulsed_master_logic.pause_measurement()
1684
        else:
1685
            self._pulsed_master_logic.continue_measurement()
1686
        return
1687
1688
    def measurement_status_updated(self, is_running, is_paused):
1689
        """
1690
1691
        @param is_running:
1692
        @param is_paused:
1693
        @return:
1694
        """
1695
        # block signals
1696
        self._mw.action_run_stop.blockSignals(True)
1697
        self._mw.action_continue_pause.blockSignals(True)
1698
1699
        # Enable/Disable widgets
1700
        if is_running:
1701
            if self._pa.ext_control_use_mw_CheckBox.isChecked():
1702
                self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
1703
                self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
1704
            if not self._pa.ana_param_invoke_settings_CheckBox.isChecked():
1705
                self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(False)
1706
                self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(False)
1707
                self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(False)
1708
                self._pa.ana_param_record_length_SpinBox.setEnabled(False)
1709
            self._pa.ext_control_use_mw_CheckBox.setEnabled(False)
1710
            self._pa.pulser_sample_freq_DSpinBox.setEnabled(False)
1711
            self._pa.pulser_activation_config_ComboBox.setEnabled(False)
1712
            self._pa.ana_param_fc_bins_ComboBox.setEnabled(False)
1713
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(False)
1714
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(False)
1715
            self._pa.ana_param_alternating_CheckBox.setEnabled(False)
1716
            self._pa.ana_param_invoke_settings_CheckBox.setEnabled(False)
1717
            self._pa.pulser_use_interleave_CheckBox.setEnabled(False)
1718
            self._pg.load_ensemble_PushButton.setEnabled(False)
1719
            self._sg.load_sequence_PushButton.setEnabled(False)
1720
            self._mw.pulser_on_off_PushButton.setEnabled(False)
1721
            self._mw.action_continue_pause.setEnabled(True)
1722
            self._mw.action_pull_data.setEnabled(True)
1723
            if not self._mw.action_run_stop.isChecked():
1724
                self._mw.action_run_stop.toggle()
1725
        else:
1726
            self._pa.ext_control_use_mw_CheckBox.setEnabled(True)
1727
            if self._pa.ext_control_use_mw_CheckBox.isChecked():
1728
                self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
1729
                self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
1730
            self._pa.pulser_sample_freq_DSpinBox.setEnabled(True)
1731
            self._pa.pulser_activation_config_ComboBox.setEnabled(True)
1732
            self._pa.ana_param_fc_bins_ComboBox.setEnabled(True)
1733
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(True)
1734
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(True)
1735
            self._pa.ana_param_alternating_CheckBox.setEnabled(True)
1736
            self._pa.ana_param_invoke_settings_CheckBox.setEnabled(True)
1737
            self._pa.pulser_use_interleave_CheckBox.setEnabled(True)
1738
            if not self._pa.ana_param_invoke_settings_CheckBox.isChecked():
1739
                self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(True)
1740
                self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(True)
1741
                self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(True)
1742
                self._pa.ana_param_record_length_SpinBox.setEnabled(True)
1743
            self._pg.load_ensemble_PushButton.setEnabled(True)
1744
            self._sg.load_sequence_PushButton.setEnabled(True)
1745
            self._mw.pulser_on_off_PushButton.setEnabled(True)
1746
            self._mw.action_continue_pause.setEnabled(False)
1747
            self._mw.action_pull_data.setEnabled(False)
1748
            if self._mw.action_run_stop.isChecked():
1749
                self._mw.action_run_stop.toggle()
1750
        if is_paused:
1751
            if not self._mw.action_continue_pause.isChecked():
1752
                self._mw.action_continue_pause.toggle()
1753
        else:
1754
            if self._mw.action_continue_pause.isChecked():
1755
                self._mw.action_continue_pause.toggle()
1756
        # unblock signals
1757
        self._mw.action_run_stop.blockSignals(False)
1758
        self._mw.action_continue_pause.blockSignals(False)
1759
        return
1760
1761
    def pull_data_clicked(self):
1762
        """ Pulls and analysis the data when the 'action_pull_data'-button is clicked. """
1763
        self._pulsed_master_logic.manually_pull_data()
1764
        return
1765
1766
    def signal_data_updated(self, x_data, y_signal_data, y2_signal_data, y_error_data,
1767
                            y2_error_data, second_x_data, second_y_data, second_y2_data):
1768
        """
1769
1770
        @param x_data:
1771
        @param y_signal_data:
1772
        @param y2_signal_data:
1773
        @param y_error_data:
1774
        @param y2_error_data:
1775
        @param second_x_data:
1776
        @param second_y_data:
1777
        @param second_y2_data:
1778
        @return:
1779
        """
1780
        is_alternating = self._pa.ana_param_alternating_CheckBox.isChecked()
1781
        second_plot = self._pa.second_plot_ComboBox.currentText()
1782
1783
        # create ErrorBarItems
1784
        beamwidth = np.inf
1785
        for i in range(len(x_data) - 1):
1786
            width = x_data[i + 1] - x_data[i]
1787
            width = width / 3
1788
            if width <= beamwidth:
1789
                beamwidth = width
1790
        self.signal_image_error_bars.setData(x=x_data, y=y_signal_data, top=y_error_data,
1791
                                             bottom=y_error_data, beam=beamwidth)
1792
        if is_alternating:
1793
            self.signal_image_error_bars2.setData(x=x_data, y=y2_signal_data, top=y2_error_data,
1794
                                                  bottom=y2_error_data, beam=beamwidth)
1795
        # dealing with the actual signal plot
1796
        self.signal_image.setData(x=x_data, y=y_signal_data)
1797
        if is_alternating:
1798
            self.signal_image2.setData(x=x_data, y=y2_signal_data)
1799
1800
        # dealing with the secondary plot
1801
        if second_plot == 'Delta':
1802
            if is_alternating:
1803
                self.second_plot_image.setData(x=second_x_data, y=second_y_data)
1804
                delta_y_error_data = np.sqrt(y_error_data**2 + y2_error_data**2)
1805
                self.second_image_error_bars.setData(x=second_x_data, y=second_y_data, top=delta_y_error_data,
1806
                                                     bottom=delta_y_error_data, beam=beamwidth)
1807
            else:
1808
                self.log.error('Delta can only be selected for the second plot if the sequence is '
1809
                               'alternating.')
1810
        elif second_plot == 'FFT':
1811
            self.second_plot_image.setData(x=second_x_data, y=second_y_data)
1812
            if is_alternating:
1813
                self.second_plot_image2.setData(x=second_x_data, y=second_y2_data)
1814
        else:
1815
            self.second_plot_image.setData(x=x_data, y=y_signal_data)
1816
            if is_alternating:
1817
                self.second_plot_image2.setData(x=x_data, y=y2_signal_data)
1818
1819
        # dealing with the error plot
1820
        self.measuring_error_image.setData(x=x_data, y=y_error_data)
1821
        if is_alternating:
1822
            self.measuring_error_image2.setData(x=x_data, y=y2_error_data)
1823
        return
1824
1825
    def save_clicked(self):
1826
        """Saves the current data"""
1827
        self._mw.action_save.setEnabled(False)
1828
        save_tag = self._mw.save_tag_LineEdit.text()
1829
        with_error = self._pa.ana_param_errorbars_CheckBox.isChecked()
1830
        controlled_val_unit = self._as.ana_param_x_axis_unit_LineEdit.text()
1831
        save_second_plot = self._pa.second_plot_ComboBox.currentText() != 'None'
1832
1833
        self._pulsed_master_logic.save_measurement_data(controlled_val_unit=controlled_val_unit,
1834
                                                        tag=save_tag,
1835
                                                        with_error=with_error,
1836
                                                        save_second_plot=save_second_plot)
1837
        self._mw.action_save.setEnabled(True)
1838
        return
1839
1840
    def fit_clicked(self):
1841
        """Fits the current data"""
1842
        current_fit_method = self._pa.fit_param_fit_func_ComboBox.getCurrentFit()[0]
1843
        self._pulsed_master_logic.do_fit(current_fit_method)
1844
        return
1845
1846
    def fit_data_updated(self, fit_method, fit_data_x, fit_data_y, result_dict):
1847
        """
1848
1849
        @param fit_method:
1850
        @param fit_data_x:
1851
        @param fit_data_y:
1852
        @param result_dict:
1853
        @return:
1854
        """
1855
        # block signals
1856
        self._pa.fit_param_fit_func_ComboBox.blockSignals(True)
1857
        # set widgets
1858
        self._pa.fit_param_results_TextBrowser.clear()
1859
        if fit_method == 'No Fit':
1860
            formatted_fitresult = 'No Fit'
1861
        else:
1862
            try:
1863
                formatted_fitresult = units.create_formatted_output(result_dict.result_str_dict)
1864
            except:
1865
                formatted_fitresult = 'This fit does not return formatted results'
1866
        self._pa.fit_param_results_TextBrowser.setPlainText(formatted_fitresult)
1867
1868
        self.fit_image.setData(x=fit_data_x, y=fit_data_y)
1869
        if fit_method == 'No Fit' and self.fit_image in self._pa.pulse_analysis_PlotWidget.items():
1870
            self._pa.pulse_analysis_PlotWidget.removeItem(self.fit_image)
1871
        elif fit_method != 'No Fit' and self.fit_image not in self._pa.pulse_analysis_PlotWidget.items():
1872
            self._pa.pulse_analysis_PlotWidget.addItem(self.fit_image)
1873
        if fit_method is not None:
1874
            self._pa.fit_param_fit_func_ComboBox.setCurrentFit(fit_method)
1875
        # unblock signals
1876
        self._pa.fit_param_fit_func_ComboBox.blockSignals(False)
1877
        return
1878
1879
    def elapsed_time_updated(self, elapsed_time, elapsed_time_str):
1880
        """
1881
        Refreshes the elapsed time and sweeps of the measurement.
1882
1883
        @param elapsed_time:
1884
        @param elapsed_time_str:
1885
        @return:
1886
        """
1887
        # block signals
1888
        self._pa.time_param_elapsed_time_LineEdit.blockSignals(True)
1889
        # Set widgets
1890
        self._pa.time_param_elapsed_time_LineEdit.setText(elapsed_time_str)
1891
        # unblock signals
1892
        self._pa.time_param_elapsed_time_LineEdit.blockSignals(True)
1893
        return
1894
1895
    def ext_mw_params_changed(self):
1896
        """ Shows or hides input widgets which are necessary if an external mw is turned on"""
1897
        if self._mw.action_run_stop.isChecked():
1898
            return
1899
        use_ext_microwave = self._pa.ext_control_use_mw_CheckBox.isChecked()
1900
        microwave_freq = self._pa.ext_control_mw_freq_DoubleSpinBox.value()
1901
        microwave_power = self._pa.ext_control_mw_power_DoubleSpinBox.value()
1902 View Code Duplication
        if use_ext_microwave and not self._pa.ext_control_mw_freq_DoubleSpinBox.isVisible():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1903
            self._pa.ext_control_mw_freq_Label.setVisible(True)
1904
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(True)
1905
            self._pa.ext_control_mw_power_Label.setVisible(True)
1906
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(True)
1907
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
1908
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
1909
        elif not use_ext_microwave and self._pa.ext_control_mw_freq_DoubleSpinBox.isVisible():
1910
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
1911
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
1912
            self._pa.ext_control_mw_freq_Label.setVisible(False)
1913
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(False)
1914
            self._pa.ext_control_mw_power_Label.setVisible(False)
1915
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(False)
1916
1917
        self._pulsed_master_logic.ext_microwave_settings_changed(microwave_freq, microwave_power,
1918
                                                                 use_ext_microwave)
1919
        return
1920
1921
    def microwave_settings_updated(self, frequency, power, use_ext_microwave):
1922
        """
1923
1924
        @param frequency:
1925
        @param power:
1926
        @param use_ext_microwave:
1927
        @return:
1928
        """
1929
        # set visibility
1930 View Code Duplication
        if use_ext_microwave and not self._pa.ext_control_mw_freq_DoubleSpinBox.isVisible():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1931
            self._pa.ext_control_mw_freq_Label.setVisible(True)
1932
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(True)
1933
            self._pa.ext_control_mw_power_Label.setVisible(True)
1934
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(True)
1935
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
1936
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
1937
        elif not use_ext_microwave and self._pa.ext_control_mw_freq_DoubleSpinBox.isVisible():
1938
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
1939
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
1940
            self._pa.ext_control_mw_freq_Label.setVisible(False)
1941
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(False)
1942
            self._pa.ext_control_mw_power_Label.setVisible(False)
1943
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(False)
1944
        # block signals
1945
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(True)
1946
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(True)
1947
        self._pa.ext_control_use_mw_CheckBox.blockSignals(True)
1948
        # set widgets
1949
        self._pa.ext_control_mw_freq_DoubleSpinBox.setValue(frequency)
1950
        self._pa.ext_control_mw_power_DoubleSpinBox.setValue(power)
1951
        self._pa.ext_control_use_mw_CheckBox.setChecked(use_ext_microwave)
1952
        # unblock signals
1953
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(False)
1954
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(False)
1955
        self._pa.ext_control_use_mw_CheckBox.blockSignals(False)
1956
        return
1957
1958
    def microwave_running_updated(self, is_running):
1959
        """
1960
1961
        @return:
1962
        """
1963
        pass
1964
1965
    def pulse_generator_settings_changed(self):
1966
        """
1967
1968
        @return:
1969
        """
1970
        if self._mw.action_run_stop.isChecked():
1971
            return
1972
        # FIXME: Properly implement amplitude and interleave
1973
        sample_rate_hz = self._pa.pulser_sample_freq_DSpinBox.value()
1974
        activation_config_name = self._pa.pulser_activation_config_ComboBox.currentText()
1975
        analogue_amplitude, dummy = self._pulsed_master_logic._measurement_logic._pulse_generator_device.get_analog_level()
1976
        interleave_on = self._pa.pulser_use_interleave_CheckBox.isChecked()
1977
        self._pulsed_master_logic.pulse_generator_settings_changed(sample_rate_hz,
1978
                                                                   activation_config_name,
1979
                                                                   analogue_amplitude,
1980
                                                                   interleave_on)
1981
        return
1982
1983
    def pulse_generator_settings_updated(self, sample_rate_hz, activation_config_name,
1984
                                         activation_config, analogue_amplitude, interleave_on):
1985
        """
1986
1987
        @param sample_rate_hz:
1988
        @param activation_config_name:
1989
        @param analogue_amplitude:
1990
        @param interleave_on:
1991
        @return:
1992
        """
1993
        # block signals
1994
        self._pa.pulser_sample_freq_DSpinBox.blockSignals(True)
1995
        self._pa.pulser_activation_config_ComboBox.blockSignals(True)
1996
        self._pa.pulser_activation_config_LineEdit.blockSignals(True)
1997
        self._pa.pulser_use_interleave_CheckBox.blockSignals(True)
1998
        # Set widgets
1999
        # FIXME: Properly implement amplitude and interleave
2000
        self._pa.pulser_sample_freq_DSpinBox.setValue(sample_rate_hz)
2001
        index = self._pa.pulser_activation_config_ComboBox.findText(activation_config_name)
2002
        self._pa.pulser_activation_config_ComboBox.setCurrentIndex(index)
2003
        config_display_str = ''
2004
        for channel in activation_config:
2005
            config_display_str += channel + ' | '
2006
        config_display_str = config_display_str[:-3]
2007
        self._pa.pulser_activation_config_LineEdit.setText(config_display_str)
2008
        self._pa.pulser_use_interleave_CheckBox.setChecked(interleave_on)
2009
        # unblock signals
2010
        self._pa.pulser_sample_freq_DSpinBox.blockSignals(False)
2011
        self._pa.pulser_activation_config_ComboBox.blockSignals(False)
2012
        self._pa.pulser_activation_config_LineEdit.blockSignals(False)
2013
        self._pa.pulser_use_interleave_CheckBox.blockSignals(False)
2014
        return
2015
2016
    def fast_counter_settings_changed(self):
2017
        """
2018
2019
        @return:
2020
        """
2021
        if self._mw.action_run_stop.isChecked():
2022
            return
2023
        record_length_s = self._pa.ana_param_record_length_SpinBox.value()
2024
        bin_width_s = float(self._pa.ana_param_fc_bins_ComboBox.currentText())
2025
        self._pulsed_master_logic.fast_counter_settings_changed(bin_width_s, record_length_s)
2026
        return
2027
2028
    def fast_counter_settings_updated(self, bin_width_s, record_length_s):
2029
        """
2030
2031
        @param bin_width_s:
2032
        @param record_length_s:
2033
        @return:
2034
        """
2035
        # block signals
2036
        self._pa.ana_param_record_length_SpinBox.blockSignals(True)
2037
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(True)
2038
        # set widgets
2039
        self._pa.ana_param_record_length_SpinBox.setValue(record_length_s)
2040
        index = self._pa.ana_param_fc_bins_ComboBox.findText(str(bin_width_s))
2041
        self._pa.ana_param_fc_bins_ComboBox.setCurrentIndex(index)
2042
        # unblock signals
2043
        self._pa.ana_param_record_length_SpinBox.blockSignals(False)
2044
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(False)
2045
        return
2046
2047
    def measurement_sequence_settings_changed(self):
2048
        """
2049
2050
        @return:
2051
        """
2052
        # Do nothing if measurement is already running
2053
        if self._mw.action_run_stop.isChecked():
2054
            return
2055
        laser_ignore_list = []
2056
        if self._pa.ana_param_ignore_first_CheckBox.isChecked():
2057
            laser_ignore_list.append(0)
2058
        if self._pa.ana_param_ignore_last_CheckBox.isChecked():
2059
            laser_ignore_list.append(-1)
2060
        alternating = self._pa.ana_param_alternating_CheckBox.isChecked()
2061
        num_of_lasers = self._pa.ana_param_num_laser_pulse_SpinBox.value()
2062
        controlled_vals_start = self._pa.ana_param_x_axis_start_ScienDSpinBox.value()
2063
        controlled_vals_incr = self._pa.ana_param_x_axis_inc_ScienDSpinBox.value()
2064
        # FIXME: properly implement sequence_length_s
2065
        sequence_length_s = self._pulsed_master_logic._measurement_logic.sequence_length_s
2066
        num_of_ticks = num_of_lasers - len(laser_ignore_list)
2067
        if alternating:
2068
            num_of_ticks //= 2
2069
        controlled_vals = np.arange(controlled_vals_start,
2070
                                    controlled_vals_start + (controlled_vals_incr * num_of_ticks) - (controlled_vals_incr / 2),
2071
                                    controlled_vals_incr)
2072
2073
        self._pulsed_master_logic.measurement_sequence_settings_changed(controlled_vals,
2074
                                                                        num_of_lasers,
2075
                                                                        sequence_length_s,
2076
                                                                        laser_ignore_list,
2077
                                                                        alternating)
2078
        return
2079
2080
    def measurement_sequence_settings_updated(self, controlled_vals, number_of_lasers,
2081
                                              sequence_length_s, laser_ignore_list, alternating):
2082
        """
2083
2084
        @param controlled_vals:
2085
        @param number_of_lasers:
2086
        @param sequence_length_s:
2087
        @param laser_ignore_list:
2088
        @param alternating:
2089
        @return:
2090
        """
2091
        # block signals
2092
        self._pa.ana_param_ignore_first_CheckBox.blockSignals(True)
2093
        self._pa.ana_param_ignore_last_CheckBox.blockSignals(True)
2094
        self._pa.ana_param_alternating_CheckBox.blockSignals(True)
2095
        self._pa.ana_param_num_laser_pulse_SpinBox.blockSignals(True)
2096
        self._pa.ana_param_x_axis_start_ScienDSpinBox.blockSignals(True)
2097
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.blockSignals(True)
2098
        self._pe.laserpulses_ComboBox.blockSignals(True)
2099
        # set widgets
2100
        self._pa.ana_param_ignore_first_CheckBox.setChecked(0 in laser_ignore_list)
2101
        self._pa.ana_param_ignore_last_CheckBox.setChecked(-1 in laser_ignore_list)
2102
        self._pa.ana_param_alternating_CheckBox.setChecked(alternating)
2103
        self._pa.ana_param_num_laser_pulse_SpinBox.setValue(number_of_lasers)
2104
        self._pa.ana_param_x_axis_start_ScienDSpinBox.setValue(controlled_vals[0])
2105
        if len(controlled_vals) > 1:
2106
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setValue(
2107
                (controlled_vals[-1] - controlled_vals[0]) / (len(controlled_vals)-1))
2108
        elif controlled_vals[0] > 0.0:
2109
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setValue(controlled_vals[0])
2110
        else:
2111
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setValue(1.0)
2112
        self._pe.laserpulses_ComboBox.clear()
2113
        self._pe.laserpulses_ComboBox.addItem('sum')
2114
        self._pe.laserpulses_ComboBox.addItems([str(i) for i in range(1, number_of_lasers+1)])
2115
        # change plots accordingly
2116
        if alternating:
2117
            if self.signal_image2 not in self._pa.pulse_analysis_PlotWidget.items():
2118
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image2)
2119
            if self.signal_image_error_bars in self._pa.pulse_analysis_PlotWidget.items() and self.signal_image_error_bars2 not in self._pa.pulse_analysis_PlotWidget.items():
2120
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
2121
            if self.second_image_error_bars not in self._pa.pulse_analysis_second_PlotWidget.items() and self._pa.second_plot_ComboBox.currentText() == 'Delta':
2122
                self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_image_error_bars)
2123
            if self.measuring_error_image2 not in self._pe.measuring_error_PlotWidget.items():
2124
                self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image2)
2125
            if self.second_plot_image2 not in self._pa.pulse_analysis_second_PlotWidget.items() and self._pa.second_plot_ComboBox.currentText() != 'Delta':
2126
                self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image2)
2127
        else:
2128
            if self.signal_image2 in self._pa.pulse_analysis_PlotWidget.items():
2129
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image2)
2130
            if self.signal_image_error_bars2 in self._pa.pulse_analysis_PlotWidget.items():
2131
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars2)
2132
            if self.second_image_error_bars in self._pa.pulse_analysis_second_PlotWidget.items():
2133
                self._pa.pulse_analysis_second_PlotWidget.removeItem(self.second_image_error_bars)
2134
            if self.measuring_error_image2 in self._pe.measuring_error_PlotWidget.items():
2135
                self._pe.measuring_error_PlotWidget.removeItem(self.measuring_error_image2)
2136
            if self.second_plot_image2 in self._pa.pulse_analysis_second_PlotWidget.items():
2137
                self._pa.pulse_analysis_second_PlotWidget.removeItem(self.second_plot_image2)
2138
        # unblock signals
2139
        self._pa.ana_param_ignore_first_CheckBox.blockSignals(False)
2140
        self._pa.ana_param_ignore_last_CheckBox.blockSignals(False)
2141
        self._pa.ana_param_alternating_CheckBox.blockSignals(False)
2142
        self._pa.ana_param_num_laser_pulse_SpinBox.blockSignals(False)
2143
        self._pa.ana_param_x_axis_start_ScienDSpinBox.blockSignals(False)
2144
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.blockSignals(False)
2145
        self._pe.laserpulses_ComboBox.blockSignals(False)
2146
2147
        # update dependent GUI elements
2148
        self.toggle_settings_editor()
2149
        self.toggle_error_bars()
2150
        self.change_second_plot()
2151
        return
2152
2153
    def toggle_settings_editor(self):
2154
        """
2155
        Shows or hides input widgets which are necessary if the x axis id defined or not.
2156
        """
2157
        invoke_checked = self._pa.ana_param_invoke_settings_CheckBox.isChecked()
2158
        if not invoke_checked:
2159
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(True)
2160
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(True)
2161
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(True)
2162
            self._pa.ana_param_record_length_SpinBox.setEnabled(True)
2163
        else:
2164
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(False)
2165
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(False)
2166
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(False)
2167
            self._pa.ana_param_record_length_SpinBox.setEnabled(False)
2168
        self._pulsed_master_logic.invoke_settings = invoke_checked
2169
        return
2170
2171
    def toggle_error_bars(self):
2172
        """
2173
2174
        @return:
2175
        """
2176
        show_bars = self._pa.ana_param_errorbars_CheckBox.isChecked()
2177
        is_alternating = self._pa.ana_param_alternating_CheckBox.isChecked()
2178
        if show_bars:
2179
            if self.signal_image_error_bars not in self._pa.pulse_analysis_PlotWidget.items():
2180
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars)
2181
            if self.second_image_error_bars not in self._pa.pulse_analysis_second_PlotWidget.items() and self._pa.second_plot_ComboBox.currentText() == 'Delta':
2182
                self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_image_error_bars)
2183
            if is_alternating and self.signal_image_error_bars2 not in self._pa.pulse_analysis_PlotWidget.items():
2184
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
2185
        else:
2186
            if self.signal_image_error_bars in self._pa.pulse_analysis_PlotWidget.items():
2187
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars)
2188
            if self.second_image_error_bars in self._pa.pulse_analysis_second_PlotWidget.items():
2189
                self._pa.pulse_analysis_second_PlotWidget.removeItem(self.second_image_error_bars)
2190
            if is_alternating and self.signal_image_error_bars2 in self._pa.pulse_analysis_PlotWidget.items():
2191
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars2)
2192
        return
2193
2194
    def change_second_plot(self):
2195
        """ This method handles the second plot"""
2196
        second_plot = self._pa.second_plot_ComboBox.currentText()
2197
        is_alternating = self._pa.ana_param_alternating_CheckBox.isChecked()
2198
2199
        # for second plot None deactivate the widget, otherwise display it
2200
        if second_plot == 'None':
2201
            self._pa.second_plot_GroupBox.setVisible(False)
2202
        else:
2203
            self._pa.second_plot_GroupBox.setVisible(True)
2204
2205
            # Delta is special, because it is only one plot with error bars
2206
            if second_plot == 'Delta':
2207
                if self.second_plot_image2 in self._pa.pulse_analysis_second_PlotWidget.items():
2208
                    self._pa.pulse_analysis_second_PlotWidget.removeItem(self.second_plot_image2)
2209
                if self.second_image_error_bars not in self._pa.pulse_analysis_second_PlotWidget.items() and self._pa.ana_param_errorbars_CheckBox.isChecked():
2210
                    self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_image_error_bars)
2211
            else:
2212
                # everything but Delta has two plots but no errorbars
2213
                if self.second_plot_image2 not in self._pa.pulse_analysis_second_PlotWidget.items():
2214
                    self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image2)
2215
                if self.second_image_error_bars in self._pa.pulse_analysis_second_PlotWidget.items():
2216
                    self._pa.pulse_analysis_second_PlotWidget.removeItem(self.second_image_error_bars)
2217
2218
            # change the axes scaling from/to logarithmic
2219
            if second_plot in ('FFT', 'Delta'):
2220
                self._pa.pulse_analysis_second_PlotWidget.setLogMode(x=False, y=False)
2221
            elif second_plot == 'Log(x)':
2222
                self._pa.pulse_analysis_second_PlotWidget.setLogMode(x=True, y=False)
2223
            elif second_plot == 'Log(y)':
2224
                self._pa.pulse_analysis_second_PlotWidget.setLogMode(x=False, y=True)
2225
            elif second_plot == 'Log(x)Log(y)':
2226
                self._pa.pulse_analysis_second_PlotWidget.setLogMode(x=True, y=True)
2227
2228
        # hand the second plot type to the logic for it to calculate the correct second plot data
2229
        self._pulsed_master_logic._measurement_logic.second_plot_type = second_plot
2230
2231
        # update the title and the labels of the plot
2232
        self._pa.second_plot_GroupBox.setTitle(second_plot)
2233 View Code Duplication
        if self._pa.second_plot_ComboBox.currentText() == 'FFT':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2234
            self._ana_param_second_plot_x_axis_name_text = self._as.ana_param_second_plot_x_axis_name_LineEdit.text()
2235
            self._ana_param_second_plot_x_axis_unit_text = self._as.ana_param_second_plot_x_axis_unit_LineEdit.text()
2236
            self._ana_param_second_plot_y_axis_name_text = self._as.ana_param_second_plot_y_axis_name_LineEdit.text()
2237
            self._ana_param_second_plot_y_axis_unit_text = self._as.ana_param_second_plot_y_axis_unit_LineEdit.text()
2238
        else:
2239
            self._ana_param_second_plot_x_axis_name_text = self._ana_param_x_axis_name_text
2240
            self._ana_param_second_plot_x_axis_unit_text = self._ana_param_x_axis_unit_text
2241
            self._ana_param_second_plot_y_axis_name_text = self._ana_param_y_axis_name_text
2242
            self._ana_param_second_plot_y_axis_unit_text = self._ana_param_y_axis_unit_text
2243
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
2244
            axis='bottom',
2245
            text=self._ana_param_second_plot_x_axis_name_text,
2246
            units=self._ana_param_second_plot_x_axis_unit_text)
2247
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
2248
            axis='left',
2249
            text=self._ana_param_second_plot_y_axis_name_text,
2250
            units=self._ana_param_second_plot_y_axis_unit_text)
2251
2252
        # handle errors: Delta can only be selected, if the sequence is alternating
2253
        if second_plot == 'Delta' and not is_alternating:
2254
            self.log.error('Delta can only be selected for the second plot if the sequence is '
2255
                           'alternating. Setting it to None instead.')
2256
            index = self._pa.second_plot_ComboBox.findText('None')
2257
            self._pa.second_plot_ComboBox.setCurrentIndex(index)
2258
2259
        return
2260
2261
    def measurement_timer_changed(self):
2262
        """ This method handles the analysis timing"""
2263
        timer_interval = self._pa.time_param_ana_periode_DoubleSpinBox.value()
2264
        self._pulsed_master_logic.analysis_interval_changed(timer_interval)
2265
        return
2266
2267
    def measurement_timer_updated(self, timer_interval_s):
2268
        """
2269
2270
        @param timer_interval_s:
2271
        @return:
2272
        """
2273
        # block signals
2274
        self._pa.time_param_ana_periode_DoubleSpinBox.blockSignals(True)
2275
        # set widget
2276
        self._pa.time_param_ana_periode_DoubleSpinBox.setValue(timer_interval_s)
2277
        # unblock signals
2278
        self._pa.time_param_ana_periode_DoubleSpinBox.blockSignals(False)
2279
        return
2280
2281
    def extraction_settings_changed(self):
2282
        """
2283
        Uodate new value of standard deviation of gaussian filter
2284
        """
2285
        extraction_settings = dict()
2286
        # determine if one of the conv_std_dev widgets (SpinBox or slider) has emitted the signal
2287
        if self.sender().objectName() == 'extract_param_conv_std_dev_slider':
2288
            extraction_settings['conv_std_dev'] = self._pe.extract_param_conv_std_dev_slider.value()
2289
        else:
2290
            extraction_settings['conv_std_dev'] = self._pe.extract_param_conv_std_dev_DSpinBox.value()
2291
2292
        extraction_settings['current_method'] = self._pe.extract_param_extraction_method_comboBox.currentText()
2293
        extraction_settings['count_threshold'] = self._pe.extract_param_threshold_SpinBox.value()
2294
        extraction_settings['threshold_tolerance'] = self._pe.extract_param_tolerance_SpinBox.value()
2295
        extraction_settings['min_laser_length'] = self._pe.extract_param_min_laser_length_SpinBox.value()
2296
2297
        self._pulsed_master_logic.extraction_settings_changed(extraction_settings)
2298
        return
2299
2300
    def extraction_settings_updated(self, extraction_settings):
2301
        """
2302
2303
        @param dict extraction_settings: dictionary with parameters to update
2304
        @return:
2305
        """
2306
2307
        if 'current_method' in extraction_settings:
2308
            self._pe.extract_param_extraction_method_comboBox.blockSignals(True)
2309
            index = self._pe.extract_param_extraction_method_comboBox.findText(extraction_settings['current_method'])
2310
            self._pe.extract_param_extraction_method_comboBox.setCurrentIndex(index)
2311
            self._pe.extract_param_extraction_method_comboBox.blockSignals(False)
2312
2313
        if 'conv_std_dev' in extraction_settings:
2314
            self._pe.extract_param_conv_std_dev_slider.blockSignals(True)
2315
            self._pe.extract_param_conv_std_dev_DSpinBox.blockSignals(True)
2316
            self._pe.extract_param_conv_std_dev_DSpinBox.setValue(extraction_settings['conv_std_dev'])
2317
            self._pe.extract_param_conv_std_dev_slider.setValue(extraction_settings['conv_std_dev'])
2318
            self._pe.extract_param_conv_std_dev_slider.blockSignals(False)
2319
            self._pe.extract_param_conv_std_dev_DSpinBox.blockSignals(False)
2320
2321
        if 'count_threshold' in extraction_settings:
2322
            self._pe.extract_param_threshold_SpinBox.blockSignals(True)
2323
            self._pe.extract_param_threshold_SpinBox.setValue(extraction_settings['count_threshold'])
2324
            self._pe.extract_param_threshold_SpinBox.blockSignals(False)
2325
2326
        if 'threshold_tolerance' in extraction_settings:
2327
            self._pe.extract_param_tolerance_SpinBox.blockSignals(True)
2328
            self._pe.extract_param_tolerance_SpinBox.setValue(extraction_settings['threshold_tolerance'])
2329
            self._pe.extract_param_tolerance_SpinBox.blockSignals(False)
2330
2331
        if 'min_laser_length' in extraction_settings:
2332
            self._pe.extract_param_min_laser_length_SpinBox.blockSignals(True)
2333
            self._pe.extract_param_min_laser_length_SpinBox.setValue(extraction_settings['min_laser_length'])
2334
            self._pe.extract_param_min_laser_length_SpinBox.blockSignals(False)
2335
2336
        return
2337
2338
2339
    def extraction_methods_updated(self, methods_dict):
2340
        """
2341
2342
        @param methods_dict:
2343
        @return:
2344
        """
2345
        method_names = list(methods_dict)
2346
        # block signals
2347
        self._pe.extract_param_extraction_method_comboBox.blockSignals(True)
2348
        # set items
2349
        self._pe.extract_param_extraction_method_comboBox.clear()
2350
        self._pe.extract_param_extraction_method_comboBox.addItems(method_names)
2351
        # unblock signals
2352
        self._pe.extract_param_extraction_method_comboBox.blockSignals(False)
2353
        return
2354
2355
    def analysis_settings_changed(self):
2356
        """
2357
2358
        @return:
2359
        """
2360
        analysis_settings = dict()
2361
        # Check if the signal has been emitted by a dragged line in the laser plot
2362
        if self.sender().__class__.__name__ == 'InfiniteLine':
2363
            if self.sig_start_line.value() <= self.sig_end_line.value():
2364
                analysis_settings['signal_start_s'] = self.sig_start_line.value()
2365
                analysis_settings['signal_end_s'] = self.sig_end_line.value()
2366
            else:
2367
                analysis_settings['signal_start_s'] = self.sig_end_line.value()
2368
                analysis_settings['signal_end_s'] = self.sig_start_line.value()
2369
            if self.ref_start_line.value() <= self.ref_end_line.value():
2370
                analysis_settings['norm_start_s'] = self.ref_start_line.value()
2371
                analysis_settings['norm_end_s'] = self.ref_end_line.value()
2372
            else:
2373
                analysis_settings['norm_start_s'] = self.ref_end_line.value()
2374
                analysis_settings['norm_end_s'] = self.ref_start_line.value()
2375
        else:
2376
            signal_width = self._pe.extract_param_ana_window_width_DSpinBox.value()
2377
            analysis_settings['signal_start_s'] = self._pe.extract_param_ana_window_start_DSpinBox.value()
2378
            analysis_settings['signal_end_s'] = analysis_settings['signal_start_s'] + signal_width
2379
            norm_width = self._pe.extract_param_ref_window_width_DSpinBox.value()
2380
            analysis_settings['norm_start_s'] = self._pe.extract_param_ref_window_start_DSpinBox.value()
2381
            analysis_settings['norm_end_s'] = analysis_settings['norm_start_s'] + norm_width
2382
2383
        analysis_settings['current_method'] = self._pe.extract_param_analysis_method_comboBox.currentText()
2384
2385
        self._pulsed_master_logic.analysis_settings_changed(analysis_settings)
2386
        return
2387
2388
    def analysis_settings_updated(self, analysis_settings):
2389
        """
2390
2391
        @param dict analysis_settings: dictionary with parameters to update
2392
        @return:
2393
        """
2394
2395
        # block signals
2396
        self._pe.extract_param_analysis_method_comboBox.blockSignals(True)
2397
        self._pe.extract_param_ana_window_start_DSpinBox.blockSignals(True)
2398
        self._pe.extract_param_ana_window_width_DSpinBox.blockSignals(True)
2399
        self._pe.extract_param_ref_window_start_DSpinBox.blockSignals(True)
2400
        self._pe.extract_param_ref_window_width_DSpinBox.blockSignals(True)
2401
        self.sig_start_line.blockSignals(True)
2402
        self.sig_end_line.blockSignals(True)
2403
        self.ref_start_line.blockSignals(True)
2404
        self.ref_end_line.blockSignals(True)
2405
2406
        if 'signal_start_s' in analysis_settings:
2407
            signal_start_s = analysis_settings['signal_start_s']
2408
        else:
2409
            signal_start_s = self._pe.extract_param_ana_window_start_DSpinBox.value()
2410
2411
        if 'signal_end_s' in analysis_settings:
2412
            signal_end_s = analysis_settings['signal_end_s']
2413
        else:
2414
            signal_end_s = signal_start_s + self._pe.extract_param_ana_window_width_DSpinBox.value()
2415
2416
        if 'norm_start_s' in analysis_settings:
2417
            norm_start_s = analysis_settings['norm_start_s']
2418
        else:
2419
            norm_start_s =  self._pe.extract_param_ref_window_start_DSpinBox.value()
2420
2421
        if 'norm_end_s' in analysis_settings:
2422
            norm_end_s = analysis_settings['norm_end_s']
2423
        else:
2424
            norm_end_s = norm_start_s + self._pe.extract_param_ref_window_width_DSpinBox.value()
2425
2426
        if 'current_method' in analysis_settings:
2427
            index = self._pe.extract_param_analysis_method_comboBox.findText(analysis_settings['current_method'])
2428
            self._pe.extract_param_analysis_method_comboBox.setCurrentIndex(index)
2429
        self._pe.extract_param_ana_window_start_DSpinBox.setValue(signal_start_s)
2430
        self._pe.extract_param_ana_window_width_DSpinBox.setValue(signal_end_s - signal_start_s)
2431
        self._pe.extract_param_ref_window_start_DSpinBox.setValue(norm_start_s)
2432
        self._pe.extract_param_ref_window_width_DSpinBox.setValue(norm_end_s - norm_start_s)
2433
        # update plots
2434
        self.sig_start_line.setValue(signal_start_s)
2435
        self.sig_end_line.setValue(signal_end_s)
2436
        self.ref_start_line.setValue(norm_start_s)
2437
        self.ref_end_line.setValue(norm_end_s)
2438
        # unblock signals
2439
        self._pe.extract_param_analysis_method_comboBox.blockSignals(False)
2440
        self._pe.extract_param_ana_window_start_DSpinBox.blockSignals(False)
2441
        self._pe.extract_param_ana_window_width_DSpinBox.blockSignals(False)
2442
        self._pe.extract_param_ref_window_start_DSpinBox.blockSignals(False)
2443
        self._pe.extract_param_ref_window_width_DSpinBox.blockSignals(False)
2444
        self.sig_start_line.blockSignals(False)
2445
        self.sig_end_line.blockSignals(False)
2446
        self.ref_start_line.blockSignals(False)
2447
        self.ref_end_line.blockSignals(False)
2448
        return
2449
2450
    def analysis_methods_updated(self, methods_dict):
2451
        """
2452
2453
        @param methods_dict:
2454
        @return:
2455
        """
2456
        method_names = list(methods_dict)
2457
        # block signals
2458
        self._pe.extract_param_analysis_method_comboBox.blockSignals(True)
2459
        # set items
2460
        self._pe.extract_param_analysis_method_comboBox.clear()
2461
        self._pe.extract_param_analysis_method_comboBox.addItems(method_names)
2462
        # unblock signals
2463
        self._pe.extract_param_analysis_method_comboBox.blockSignals(False)
2464
        return
2465
2466
    def laser_to_show_changed(self):
2467
        """
2468
2469
        @return:
2470
        """
2471
        current_laser = self._pe.laserpulses_ComboBox.currentText()
2472
        show_raw_data = self._pe.laserpulses_display_raw_CheckBox.isChecked()
2473
        if current_laser == 'sum':
2474
            show_laser_index = 0
2475
        else:
2476
            show_laser_index = int(current_laser)
2477
2478
        self._pulsed_master_logic.laser_to_show_changed(show_laser_index, show_raw_data)
2479
        return
2480
2481
    def laser_to_show_updated(self, laser_index, show_raw_data):
2482
        """
2483
2484
        @param laser_index:
2485
        @param show_raw_data:
2486
        @return:
2487
        """
2488
        # block signals
2489
        self._pe.laserpulses_ComboBox.blockSignals(True)
2490
        self._pe.laserpulses_display_raw_CheckBox.blockSignals(True)
2491
        # set widgets
2492
        self._pe.laserpulses_ComboBox.setCurrentIndex(laser_index)
2493
        self._pe.laserpulses_display_raw_CheckBox.setChecked(show_raw_data)
2494
        # unblock signals
2495
        self._pe.laserpulses_ComboBox.blockSignals(False)
2496
        self._pe.laserpulses_display_raw_CheckBox.blockSignals(False)
2497
        return
2498
2499
    def laser_data_updated(self, x_data, y_data):
2500
        """
2501
2502
        @param x_data:
2503
        @param y_data:
2504
        @return:
2505
        """
2506
        self.lasertrace_image.setData(x=x_data, y=y_data)
2507
        return
2508
2509
2510
2511
    ###########################################################################
2512
    ###         Methods related to the Tab 'Sequence Generator':            ###
2513
    ###########################################################################
2514
    def pulser_on_off_clicked(self, checked):
2515
        """ Manually switch the pulser output on/off. """
2516
        checked = self._mw.pulser_on_off_PushButton.isChecked()
2517
        if checked:
2518
            self._mw.pulser_on_off_PushButton.setText('Pulser OFF')
2519
            self._pulsed_master_logic.toggle_pulse_generator(True)
2520
        else:
2521
            self._mw.pulser_on_off_PushButton.setText('Pulser ON')
2522
            self._pulsed_master_logic.toggle_pulse_generator(False)
2523
        return
2524
2525
    def pulser_running_updated(self, is_running):
2526
        """
2527
2528
        @param is_running:
2529
        @return:
2530
        """
2531
        # block signals
2532
        self._mw.pulser_on_off_PushButton.blockSignals(True)
2533
        # set widgets
2534
        if is_running:
2535
            self._mw.pulser_on_off_PushButton.setText('Pulser OFF')
2536
            if not self._mw.pulser_on_off_PushButton.isChecked():
2537
                self._mw.pulser_on_off_PushButton.toggle()
2538
        else:
2539
            self._mw.pulser_on_off_PushButton.setText('Pulser ON')
2540
            if self._mw.pulser_on_off_PushButton.isChecked():
2541
                self._mw.pulser_on_off_PushButton.toggle()
2542
        # unblock signals
2543
        self._mw.pulser_on_off_PushButton.blockSignals(False)
2544
        return
2545
2546
    def clear_pulser_clicked(self):
2547
        """ Delete all loaded files in the device's current memory. """
2548
        self._pulsed_master_logic.clear_pulse_generator()
2549
        return
2550
2551
    def update_uploaded_assets(self, asset_names_list):
2552
        """
2553
2554
        @param asset_names_list:
2555
        @return:
2556
        """
2557
        pass
2558
2559
    def load_ensemble_clicked(self):
2560
        """
2561
        This method
2562
        """
2563
        # disable button
2564
        self._pg.load_ensemble_PushButton.setEnabled(False)
2565
        # Get the asset name to be uploaded from the ComboBox
2566
        asset_name = self._pg.gen_ensemble_ComboBox.currentText()
2567
        # Load asset into channles via logic module
2568
        self._pulsed_master_logic.load_asset_into_channels(asset_name, {})
2569
        return
2570
2571
    def load_sequence_clicked(self):
2572
        """
2573
        This method
2574
        """
2575
        # disable button
2576
        self._sg.load_sequence_PushButton.setEnabled(False)
2577
        # Get the asset name to be uploaded from the ComboBox
2578
        asset_name = self._sg.gen_sequence_ComboBox.currentText()
2579
        # Load asset into channles via logic module
2580
        self._pulsed_master_logic.load_asset_into_channels(asset_name, {})
2581
        return
2582
2583
    def update_loaded_asset(self, asset_name, asset_type):
2584
        """ Check the current loaded asset from the logic and update the display. """
2585
        label = self._mw.current_loaded_asset_Label
2586
        if asset_name is None or asset_name == '':
2587
            label.setText('  No asset loaded')
2588
        elif asset_type == 'PulseBlockEnsemble' or asset_type == 'PulseSequence':
2589
            label.setText('  {0} ({1})'.format(asset_name, asset_type))
2590
        else:
2591
            label.setText('  Unknown asset type')
2592
        # enable buttons
2593
        if asset_type == 'PulseBlockEnsemble':
2594
            self._pg.load_ensemble_PushButton.setEnabled(True)
2595
            self._pg.sauplo_ensemble_PushButton.setEnabled(True)
2596
            self._pg.saup_ensemble_PushButton.setEnabled(True)
2597
        elif asset_type == 'PulseSequence':
2598
            self._sg.load_sequence_PushButton.setEnabled(True)
2599
            self._sg.sauplo_sequence_PushButton.setEnabled(True)
2600
            self._sg.saup_sequence_PushButton.setEnabled(True)
2601
        return
2602