Completed
Push — pulsed_with_queued_connections ( 5a6169...ecd505 )
by
unknown
03:04
created

PulsedMeasurementGui.update_generator_settings()   D

Complexity

Conditions 8

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 8
c 3
b 0
f 0
dl 0
loc 46
rs 4.1666
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
from qtpy import QtGui
24
from qtpy import QtCore
25
from qtpy import QtWidgets
26
from qtpy import uic
27
import numpy as np
28
import os
29
from collections import OrderedDict
30
import pyqtgraph as pg
31
import re
32
import inspect
33
import datetime
34
35
36
from gui.guibase import GUIBase
37
from gui.colordefs import QudiPalettePale as palette
38
from gui.colordefs import QudiPalette as palettedark
39
from qtwidgets.scientific_spinbox import ScienDSpinBox, ScienSpinBox
40
#from gui.pulsed.pulse_editor import PulseEditor
41
from core.util.mutex import Mutex
42
from core.util import units
43
from gui.pulsed.pulse_editors import BlockEditor, BlockOrganizer
44
from logic.sampling_functions import SamplingFunctions
45
46
47
#FIXME: Display the Pulse
48
#FIXME: save the length in sample points (bins)
49
#FIXME: adjust the length to the bins
50
#FIXME: Later that should be able to round up the values directly within
51
52
53
class PulsedMeasurementMainWindow(QtWidgets.QMainWindow):
54
    def __init__(self):
55
        # Get the path to the *.ui file
56
        this_dir = os.path.dirname(__file__)
57
        ui_file = os.path.join(this_dir, 'ui_pulsed_noeditor.ui')
58
59
        # Load it
60
        super(PulsedMeasurementMainWindow, self).__init__()
61
62
        uic.loadUi(ui_file, self)
63
        self.show()
64
65
66
class PulseAnalysisTab(QtWidgets.QWidget):
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_pulse_analysis.ui')
71
        # Load it
72
        super().__init__()
73
        uic.loadUi(ui_file, self)
74
75
76
class PulseGeneratorTab(QtWidgets.QWidget):
77
    def __init__(self):
78
        # Get the path to the *.ui file
79
        this_dir = os.path.dirname(__file__)
80
        ui_file = os.path.join(this_dir, 'ui_pulse_editor.ui')
81
        # Load it
82
        super().__init__()
83
        uic.loadUi(ui_file, self)
84
85
86
class PulseExtractionTab(QtWidgets.QWidget):
87
    def __init__(self):
88
        # Get the path to the *.ui file
89
        this_dir = os.path.dirname(__file__)
90
        ui_file = os.path.join(this_dir, 'ui_pulse_extraction.ui')
91
        # Load it
92
        super().__init__()
93
        uic.loadUi(ui_file, self)
94
95
96
class AnalysisSettingDialog(QtWidgets.QDialog):
97
    def __init__(self):
98
        # Get the path to the *.ui file
99
        this_dir = os.path.dirname(__file__)
100
        ui_file = os.path.join(this_dir, 'ui_pulsed_main_gui_settings_analysis.ui')
101
102
        # Load it
103
        super(AnalysisSettingDialog, self).__init__()
104
105
        uic.loadUi(ui_file, self)
106
107
108
class GeneratorSettingsDialog(QtWidgets.QDialog):
109
    def __init__(self):
110
        # Get the path to the *.ui file
111
        this_dir = os.path.dirname(__file__)
112
        ui_file = os.path.join(this_dir, 'ui_pulsed_main_gui_settings_block_gen.ui')
113
114
        # Load it
115
        super(GeneratorSettingsDialog, self).__init__()
116
117
        uic.loadUi(ui_file, self)
118
119
120
class PredefinedMethodsDialog(QtWidgets.QDialog):
121
    def __init__(self):
122
        # Get the path to the *.ui file
123
        this_dir = os.path.dirname(__file__)
124
        ui_file = os.path.join(this_dir, 'ui_predefined_methods.ui')
125
126
        # Load it
127
        super(PredefinedMethodsDialog, self).__init__()
128
129
        uic.loadUi(ui_file, self)
130
131
class PredefinedMethodsConfigDialog(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_predefined_methods_config.ui')
136
137
        # Load it
138
        super(PredefinedMethodsConfigDialog, self).__init__()
139
140
        uic.loadUi(ui_file, self)
141
142
143
class PulsedMeasurementGui(GUIBase):
144
    """ This is the main GUI Class for pulsed measurements. """
145
146
    _modclass = 'PulsedMeasurementGui'
147
    _modtype = 'gui'
148
149
    ## declare connectors
150
    _in = {'pulsedmasterlogic': 'PulsedMasterLogic',
151
           'savelogic': 'SaveLogic'}
152
153
    def __init__(self, config, **kwargs):
154
        super().__init__(config=config, **kwargs)
155
156
        self.log.info('The following configuration was found.')
157
158
        # checking for the right configuration
159
        for key in config.keys():
160
            self.log.info('{}: {}'.format(key,config[key]))
161
162
        # that variable is for testing issues and can be deleted if not needed:
163
        self._write_chunkwise = False
164
165
    def on_activate(self, e=None):
166
        """ Initialize, connect and configure the pulsed measurement GUI.
167
168
        @param object e: Fysom.event object from Fysom class.
169
                         An object created by the state machine module Fysom,
170
                         which is connected to a specific event (have a look in
171
                         the Base Class). This object contains the passed event,
172
                         the state before the event happened and the destination
173
                         of the state which should be reached after the event
174
                         had happened.
175
176
        Establish general connectivity and activate the different tabs of the
177
        GUI.
178
        """
179
        self._pulsed_master_logic = self.get_in_connector('pulsedmasterlogic')
180
        self._save_logic = self.get_in_connector('savelogic')
181
182
        self._mw = PulsedMeasurementMainWindow()
183
        self._pa = PulseAnalysisTab()
184
        self._pg = PulseGeneratorTab()
185
        self._pe = PulseExtractionTab()
186
187
        self._mw.tabWidget.addTab(self._pa, 'Analysis')
188
        self._mw.tabWidget.addTab(self._pe, 'Pulse Extraction')
189
        self._mw.tabWidget.addTab(self._pg, 'Pulse Generator')
190
191
        self.setup_toolbar()
192
        self._activate_analysis_settings_ui(e)
193
        self._activate_analysis_ui(e)
194
        self.setup_extraction_ui()
195
196
        self._activate_generator_settings_ui(e)
197
        self._activate_pulse_generator_ui(e)
198
199
        self.show()
200
201
    def on_deactivate(self, e):
202
        """ Undo the Definition, configuration and initialisation of the pulsed
203
            measurement GUI.
204
205
        @param object e: Fysom.event object from Fysom class. A more detailed
206
                         explanation can be found in the method initUI.
207
208
        This deactivation disconnects all the graphic modules, which were
209
        connected in the initUI method.
210
        """
211
        self._deactivate_analysis_settings_ui(e)
212
        self._deactivate_analysis_ui(e)
213
214
        self._deactivate_generator_settings_ui(e)
215
        self._deactivate_pulse_generator_ui(e)
216
217
        self._mw.close()
218
219
    def show(self):
220
        """Make main window visible and put it above all other windows. """
221
        QtWidgets.QMainWindow.show(self._mw)
222
        self._mw.activateWindow()
223
        self._mw.raise_()
224
225
    ###########################################################################
226
    ###   Methods related to Settings for the 'Pulse Generator' tab:        ###
227
    ###########################################################################
228
    def _activate_generator_settings_ui(self, e):
229
        """ Initialize, connect and configure the pulse generator settings to be displayed in the
230
        editor.
231
232
        @param object e: Fysom.event object from Fysom class. A more detailed
233
                         explanation can be found in the method initUI.
234
        """
235
        self._gs = GeneratorSettingsDialog()
236
        self._gs.accepted.connect(self.apply_generator_settings)
237
        self._gs.rejected.connect(self.keep_former_generator_settings)
238
        self._gs.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
239
            self.apply_generator_settings)
240
        # Here the names of all function to show are stored
241
        self._functions_to_show = []
242
243
        # create the Predefined methods Dialog
244
        self._pm = PredefinedMethodsDialog()
245
        # here are all the names of the predefined methods are saved.
246
        self._predefined_methods_list = []
247
        # here all names of the chosen predefined methods are saved
248
        self._predefined_methods_to_show = []
249
        # create a config for the predefined methods:
250
        self._pm_cfg = PredefinedMethodsConfigDialog()
251
        self._pm_cfg.accepted.connect(self.apply_predefined_methods_config)
252
        self._pm_cfg.rejected.connect(self.keep_former_predefined_methods_config)
253
        self._pm_cfg.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(
254
            self.apply_predefined_methods_config)
255
256
        if 'predefined_methods_to_show' in self._statusVariables:
257
            self._predefined_methods_to_show = self._statusVariables['predefined_methods_to_show']
258
        if 'functions_to_show' in self._statusVariables:
259
            self._functions_to_show = self._statusVariables['functions_to_show']
260
261
        # connect the menu to the actions:
262
        self._mw.action_Settings_Block_Generation.triggered.connect(self.show_generator_settings)
263
        self._mw.action_Predefined_Methods_Config.triggered.connect(self.show_predefined_methods_config)
264
        self._mw.action_Show_Predefined_Methods.triggered.connect(self.show_predefined_methods)
265
266
        self._pulsed_master_logic.sigPredefinedSequencesUpdated.connect(self.predefined_methods_changed)
267
268
        # Create function config dialog
269
        self._create_function_config()
270
        return
271
272
    def _deactivate_generator_settings_ui(self, e):
273
        """ Disconnects the configuration of the Settings for the 'Pulse Generator' Tab.
274
275
        @param object e: Fysom.event object from Fysom class. A more detailed
276
                         explanation can be found in the method initUI.
277
        """
278
        self._statusVariables['predefined_methods_to_show'] = self._predefined_methods_to_show
279
        self._statusVariables['functions_to_show'] = self._functions_to_show
280
281
        self._gs.accepted.disconnect()
282
        self._gs.rejected.disconnect()
283
        self._gs.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
284
        self._gs.close()
285
286
        self._pm_cfg.accepted.disconnect()
287
        self._pm_cfg.rejected.disconnect()
288
        self._pm_cfg.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
289
        self._pm_cfg.close()
290
291
        self._pm.close()
292
293
        self._pulsed_master_logic.sigPredefinedSequencesUpdated.disconnect()
294
        self._mw.action_Settings_Block_Generation.triggered.disconnect()
295
        self._mw.action_Predefined_Methods_Config.triggered.disconnect()
296
        self._mw.action_Show_Predefined_Methods.triggered.disconnect()
297
        return
298
299
    def show_generator_settings(self):
300
        """
301
        Opens the generator settings menu.
302
        """
303
        self._gs.exec_()
304
        return
305
306
    def _create_function_config(self):
307
        # Add in the settings menu within the groupbox widget all the available math_functions,
308
        # based on the list from the Logic. Right now, the GUI objects are inserted the 'hard' way,
309
        # like it is done in the Qt-Designer.
310
        # FIXME: Make a nicer way of displaying the available functions, maybe with a Table!
311
        _encoding = QtWidgets.QApplication.UnicodeUTF8
312
        objectname = self._gs.objectName()
313
        for index, func_name in enumerate(list(SamplingFunctions().func_config)):
314
            name_label = 'func_' + str(index)
315
            setattr(self._gs, name_label, QtWidgets.QLabel(self._gs.groupBox))
316
            label = getattr(self._gs, name_label)
317
            label.setObjectName(name_label)
318
            self._gs.gridLayout_3.addWidget(label, index, 0, 1, 1)
319
            label.setText(QtWidgets.QApplication.translate(objectname, func_name, None, _encoding))
320
321
            name_checkbox = 'checkbox_' + str(index)
322
            setattr(self._gs, name_checkbox, QtWidgets.QCheckBox(self._gs.groupBox))
323
            checkbox = getattr(self._gs, name_checkbox)
324
            checkbox.setObjectName(name_checkbox)
325
            self._gs.gridLayout_3.addWidget(checkbox, index, 1, 1, 1)
326
            checkbox.setText(QtWidgets.QApplication.translate(objectname, '', None, _encoding))
327
        # Check all functions that are in the _functions_to_show list.
328
        # If no such list is present take the first 3 functions as default
329
        if len(self._functions_to_show) > 0:
330
            for func in self._functions_to_show:
331
                index = list(SamplingFunctions().func_config).index(func)
332
                name_checkbox = 'checkbox_' + str(index)
333
                checkbox = getattr(self._gs, name_checkbox)
334
                checkbox.setCheckState(QtCore.Qt.Checked)
335
        else:
336
            for index in range(3):
337
                name_checkbox = 'checkbox_' + str(index)
338
                checkbox = getattr(self._gs, name_checkbox)
339
                checkbox.setCheckState(QtCore.Qt.Checked)
340
        return
341
342
    def apply_generator_settings(self):
343
        """
344
        Write new generator settings from the gui to the file.
345
        """
346
        new_config = SamplingFunctions().func_config
347
        for index, func_name in enumerate(list(SamplingFunctions().func_config)):
348
            name_checkbox = 'checkbox_' + str(index)
349
            checkbox = getattr(self._gs, name_checkbox)
350
            if not checkbox.isChecked():
351
                name_label = 'func_' + str(index)
352
                func = getattr(self._gs, name_label)
353
                del new_config[func.text()]
354
        self._functions_to_show = list(new_config)
355
        if self.block_editor.function_config != new_config:
356
            self.block_editor.set_function_config(new_config)
357
        return
358
359
    def keep_former_generator_settings(self):
360
        """
361
        Keep the old generator settings and restores them in the gui.
362
        """
363
        old_config = self.block_editor.function_config
364
        for index, func_name in enumerate(list(SamplingFunctions().func_config)):
365
            name_checkbox = 'checkbox_' + str(index)
366
            checkbox = getattr(self._gs, name_checkbox)
367
            if func_name in old_config:
368
                checkbox.setChecked(True)
369
            else:
370
                checkbox.setChecked(False)
371
        return
372
373
    def show_predefined_methods(self):
374
        """ Opens the predefined methods Window."""
375
        self._pm.show()
376
        self._pm.raise_()
377
378
    def show_predefined_methods_config(self):
379
        """ Opens the Window for the config of predefined methods."""
380
        self._pm_cfg.show()
381
        self._pm_cfg.raise_()
382
383
    def predefined_methods_changed(self, methods_dict):
384
        """
385
386
        @param methods_dict:
387
        @return:
388
        """
389
        self._predefined_methods_list = list(methods_dict)
390
        # create all GUI elements
391
        self._create_predefined_methods(methods_dict)
392
        # check all checkboxes that correspond to the methods to show in the config dialogue
393
        for method_name in self._predefined_methods_to_show:
394
            if method_name in self._predefined_methods_list:
395
                index = self._predefined_methods_list.index(method_name)
396
                checkbox = getattr(self._pm_cfg, 'checkbox_' + str(index))
397
                checkbox.setChecked(True)
398
            else:
399
                del_index = self._predefined_methods_to_show.index(method_name)
400
                del self._predefined_methods_to_show[del_index]
401
        # apply the chosen methods to the methods dialogue
402
        self.apply_predefined_methods_config()
403
        return
404
405
    def _create_predefined_methods(self, methods_dict):
406
        """
407
        Initializes the GUI elements for the predefined methods and the corresponding config
408
409
        @param methods_dict:
410
        @return:
411
        """
412
        for index, method_name in enumerate(list(methods_dict)):
413
            # create checkboxes for the config dialogue
414
            name_checkbox = 'checkbox_' + str(index)
415
            setattr(self._pm_cfg, name_checkbox, QtWidgets.QCheckBox(self._pm_cfg.scrollArea))
416
            checkbox = getattr(self._pm_cfg, name_checkbox)
417
            checkbox.setObjectName(name_checkbox)
418
            checkbox.setText(method_name)
419
            checkbox.setChecked(False)
420
            self._pm_cfg.verticalLayout.addWidget(checkbox)
421
422
            # Create the widgets for the predefined methods dialogue
423
            # Create GroupBox for the method to reside in
424
            groupBox = QtWidgets.QGroupBox(self._pm)
425
            groupBox.setTitle(method_name)
426
            # Create layout within the GroupBox
427
            gridLayout = QtWidgets.QGridLayout(groupBox)
428
            # Create generate buttons
429
            gen_button = QtWidgets.QPushButton(groupBox)
430
            gen_button.setText('Generate')
431
            gen_button.setObjectName('gen_' + method_name)
432
            gen_button.clicked.connect(self.generate_predefined_clicked)
433
            sauplo_button = QtWidgets.QPushButton(groupBox)
434
            sauplo_button.setText('GenSaUpLo')
435
            sauplo_button.setObjectName('sauplo_' + method_name)
436
            sauplo_button.clicked.connect(self.generate_sauplo_predefined_clicked)
437
            # inspect current method to extract the parameters
438
            inspected = inspect.signature(methods_dict[method_name])
439
            # run through all parameters of the current method and create the widgets
440
            for param_index, param_name in enumerate(inspected.parameters):
441
                # get default value of the parameter
442
                default_val = inspected.parameters[param_name].default
443
                if default_val is inspect._empty:
444
                    self.log.error('The method "{0}" in the logic has an argument "{1}" without a '
445
                                   'default value!\nAssign a default value to that, otherwise a '
446
                                   'type estimation is not possible!\nCreation of the viewbox '
447
                                   'aborted.'.format('generate_' + method_name, param_name))
448
                    return
449
                # create a label for the parameter
450
                param_label = QtWidgets.QLabel(groupBox)
451
                param_label.setText(param_name)
452
                # create proper input widget for the parameter depending on the type of default_val
453
                if type(default_val) is bool:
454
                    input_obj = QtWidgets.QCheckBox(groupBox)
455
                    input_obj.setChecked(default_val)
456
                elif type(default_val) is float:
457
                    input_obj = ScienDSpinBox(groupBox)
458
                    input_obj.setMaximum(np.inf)
459
                    input_obj.setMinimum(-np.inf)
460
                    if 'amp' in param_name:
461
                        input_obj.setSuffix('V')
462
                    elif 'freq' in param_name:
463
                        input_obj.setSuffix('Hz')
464
                    elif 'length' in param_name or 'time' in param_name or 'period' in param_name or 'tau' in param_name:
465
                        input_obj.setSuffix('s')
466
                    input_obj.setMinimumSize(QtCore.QSize(80, 0))
467
                    input_obj.setValue(default_val)
468
                elif type(default_val) is int:
469
                    input_obj = ScienSpinBox(groupBox)
470
                    input_obj.setMaximum(2**31 - 1)
471
                    input_obj.setMinimum(-2**31 + 1)
472
                    input_obj.setValue(default_val)
473
                elif type(default_val) is str:
474
                    input_obj = QtWidgets.QLineEdit(groupBox)
475
                    input_obj.setMinimumSize(QtCore.QSize(80, 0))
476
                    input_obj.setText(default_val)
477
                else:
478
                    self.log.error('The method "{0}" in the logic has an argument "{1}" with is not'
479
                                   ' of the valid types str, float, int or bool!\nChoose one of '
480
                                   'those default values! Creation of the viewbox aborted.'
481
                                   ''.format('generate_' + method_name, param_name))
482
                gridLayout.addWidget(param_label, 0, param_index, 1, 1)
483
                gridLayout.addWidget(input_obj, 1, param_index, 1, 1)
484
                setattr(self._pm, method_name + '_param_' + str(param_index) + '_Widget', input_obj)
485
486
            gridLayout.addWidget(gen_button, 0, len(inspected.parameters), 1, 1)
487
            gridLayout.addWidget(sauplo_button, 1, len(inspected.parameters), 1, 1)
488
            # attach the GroupBox widget to the predefined methods widget.
489
            setattr(self._pm, method_name + '_GroupBox', groupBox)
490
            self._pm.verticalLayout.addWidget(groupBox)
491
        return
492
493
    def keep_former_predefined_methods_config(self):
494
        for index, name in enumerate(self._predefined_methods_list):
495
            groupbox = getattr(self._pm, name + '_GroupBox')
496
            checkbox = getattr(self._pm_cfg, 'checkbox_' + str(index))
497
            checkbox.setChecked(groupbox.isVisible())
498
        return
499
500
    def apply_predefined_methods_config(self):
501
        self._predefined_methods_to_show = []
502
        for index, name in enumerate(self._predefined_methods_list):
503
            groupbox = getattr(self._pm, name + '_GroupBox')
504
            checkbox = getattr(self._pm_cfg, 'checkbox_' + str(index))
505
            is_checked = checkbox.isChecked()
506
            groupbox.setVisible(is_checked)
507
            if is_checked:
508
                self._predefined_methods_to_show.append(name)
509
        return
510
511
    ###########################################################################
512
    ###   Methods related to Tab 'Pulse Generator' in the Pulsed Window:    ###
513
    ###########################################################################
514
    def _activate_pulse_generator_ui(self, e):
515
        """ Initialize, connect and configure the 'Pulse Generator' Tab.
516
517
        @param object e: Fysom.event object from Fysom class. A more detailed
518
                         explanation can be found in the method initUI.
519
        """
520
        # connect signals of input widgets
521
        self._pg.gen_sample_freq_DSpinBox.editingFinished.connect(self.generator_settings_changed, QtCore.Qt.QueuedConnection)
522
        self._pg.gen_laserchannel_ComboBox.currentIndexChanged.connect(self.generator_settings_changed, QtCore.Qt.QueuedConnection)
523
        self._pg.gen_activation_config_ComboBox.currentIndexChanged.connect(self.generator_settings_changed, QtCore.Qt.QueuedConnection)
524
        # connect signals of buttons
525
        self._pg.sample_ensemble_PushButton.clicked.connect(self.sample_ensemble_clicked)
526
        # self._pg.sample_sequence_PushButton.clicked.connect(self.sample_sequence_clicked)
527
        self._pg.sauplo_ensemble_PushButton.clicked.connect(self.sauplo_ensemble_clicked)
528
529
        self._pg.block_add_last_PushButton.clicked.connect(self.block_add_last_clicked)
530
        self._pg.block_del_last_PushButton.clicked.connect(self.block_del_last_clicked)
531
        self._pg.block_add_sel_PushButton.clicked.connect(self.block_add_sel_clicked)
532
        self._pg.block_del_sel_PushButton.clicked.connect(self.block_del_sel_clicked)
533
        self._pg.block_clear_PushButton.clicked.connect(self.block_clear_clicked)
534
        self._pg.organizer_add_last_PushButton.clicked.connect(self.organizer_add_last_clicked)
535
        self._pg.organizer_del_last_PushButton.clicked.connect(self.organizer_del_last_clicked)
536
        self._pg.organizer_add_sel_PushButton.clicked.connect(self.organizer_add_sel_clicked)
537
        self._pg.organizer_del_sel_PushButton.clicked.connect(self.organizer_del_sel_clicked)
538
        self._pg.organizer_clear_PushButton.clicked.connect(self.organizer_clear_clicked)
539
540
        self._pg.curr_block_generate_PushButton.clicked.connect(self.editor_generate_block_clicked)
541
        self._pg.curr_block_del_PushButton.clicked.connect(self.editor_delete_block_clicked)
542
        self._pg.curr_block_load_PushButton.clicked.connect(self.editor_load_block_clicked)
543
        self._pg.curr_ensemble_generate_PushButton.clicked.connect(self.editor_generate_ensemble_clicked)
544
        self._pg.curr_ensemble_del_PushButton.clicked.connect(self.editor_delete_ensemble_clicked)
545
        self._pg.curr_ensemble_load_PushButton.clicked.connect(self.editor_load_ensemble_clicked)
546
547
        # connect update signals from pulsed_master_logic
548
        self._pulsed_master_logic.sigBlockEnsembleSampled.connect(self.sample_ensemble_finished)
549
        # self._pulsed_master_logic.sigSequenceSampled.connect(self.sample_sequence_finished)
550
        self._pulsed_master_logic.sigSavedPulseBlocksUpdated.connect(self.update_block_dict)
551
        self._pulsed_master_logic.sigSavedBlockEnsemblesUpdated.connect(self.update_ensemble_dict)
552
        # self._pulsed_master_logic.sigSavedSequencesUpdated.connect(self.update_sequence_list)
553
        self._pulsed_master_logic.sigGeneratorSettingsUpdated.connect(self.update_generator_settings)
554
555
        self._pulsed_master_logic.sigCurrentPulseBlockUpdated.connect(self.load_block_in_editor)
556
        self._pulsed_master_logic.sigCurrentBlockEnsembleUpdated.connect(self.load_ensemble_in_editor)
557
        # self._pulsed_master_logic.sigCurrentSequenceUpdated.connect(self.)
558
559
        self.block_organizer = BlockOrganizer(self._pg.block_organizer_TableWidget)
560
        self.block_editor = BlockEditor(self._pg.block_editor_TableWidget)
561
562
        # Apply hardware constraints to input widgets
563
        self._gen_apply_hardware_constraints()
564
565
        # Fill initial values from logic into input widgets
566
        self._pulsed_master_logic.request_generator_init_values()
567
        return
568
569
    def _deactivate_pulse_generator_ui(self, e):
570
        """ Disconnects the configuration for 'Pulse Generator Tab.
571
572
        @param object e: Fysom.event object from Fysom class. A more detailed
573
                         explanation can be found in the method initUI.
574
        """
575
        # disconnect signals of input widgets
576
        self._pg.gen_sample_freq_DSpinBox.editingFinished.disconnect()
577
        self._pg.gen_laserchannel_ComboBox.currentIndexChanged.disconnect()
578
        self._pg.gen_activation_config_ComboBox.currentIndexChanged.disconnect()
579
        # disconnect signals of buttons
580
        self._pg.sample_ensemble_PushButton.clicked.disconnect()
581
        # self._pg.sample_sequence_PushButton.clicked.disconnect()
582
        self._pg.sauplo_ensemble_PushButton.clicked.disconnect()
583
        self._pg.block_add_last_PushButton.clicked.disconnect()
584
        self._pg.block_del_last_PushButton.clicked.disconnect()
585
        self._pg.block_add_sel_PushButton.clicked.disconnect()
586
        self._pg.block_del_sel_PushButton.clicked.disconnect()
587
        self._pg.block_clear_PushButton.clicked.disconnect()
588
        self._pg.organizer_add_last_PushButton.clicked.disconnect()
589
        self._pg.organizer_del_last_PushButton.clicked.disconnect()
590
        self._pg.organizer_add_sel_PushButton.clicked.disconnect()
591
        self._pg.organizer_del_sel_PushButton.clicked.disconnect()
592
        self._pg.organizer_clear_PushButton.clicked.disconnect()
593
        self._pg.curr_block_generate_PushButton.clicked.disconnect()
594
        self._pg.curr_block_del_PushButton.clicked.disconnect()
595
        self._pg.curr_block_load_PushButton.clicked.disconnect()
596
        self._pg.curr_ensemble_generate_PushButton.clicked.disconnect()
597
        self._pg.curr_ensemble_del_PushButton.clicked.disconnect()
598
        self._pg.curr_ensemble_load_PushButton.clicked.disconnect()
599
        # disconnect update signals from pulsed_master_logic
600
        self._pulsed_master_logic.sigBlockEnsembleSampled.disconnect()
601
        # self._pulsed_master_logic.sigSequenceSampled.disconnect()
602
        self._pulsed_master_logic.sigSavedPulseBlocksUpdated.disconnect()
603
        self._pulsed_master_logic.sigSavedBlockEnsemblesUpdated.disconnect()
604
        # self._pulsed_master_logic.sigSavedSequencesUpdated.disconnect()
605
        self._pulsed_master_logic.sigGeneratorSettingsUpdated.disconnect()
606
        self._pulsed_master_logic.sigCurrentPulseBlockUpdated.disconnect()
607
        self._pulsed_master_logic.sigCurrentBlockEnsembleUpdated.disconnect()
608
        # self._pulsed_master_logic.sigCurrentSequenceUpdated.disconnect()
609
        return
610
611
    def _gen_apply_hardware_constraints(self):
612
        """
613
        Retrieve the constraints from pulser hardware and apply these constraints to the pulse
614
        generator GUI elements.
615
        """
616
        # block signals
617
        self._pg.gen_activation_config_ComboBox.blockSignals(True)
618
        self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
619
        # apply constraints
620
        pulser_constr, dummy = self._pulsed_master_logic.get_hardware_constraints()
621
        self._pg.gen_activation_config_ComboBox.addItems(list(pulser_constr['activation_config']))
622
        self._pg.gen_sample_freq_DSpinBox.setMinimum(pulser_constr['sample_rate']['min'])
623
        self._pg.gen_sample_freq_DSpinBox.setMaximum(pulser_constr['sample_rate']['max'])
624
        # unblock signals
625
        self._pg.gen_activation_config_ComboBox.blockSignals(False)
626
        self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
627
        return
628
629
    def generator_settings_changed(self):
630
        """
631
632
        @return:
633
        """
634
        sample_rate = self._pg.gen_sample_freq_DSpinBox.value()
635
        laser_channel = self._pg.gen_laserchannel_ComboBox.currentText()
636
        activation_config_name = self._pg.gen_activation_config_ComboBox.currentText()
637
        amplitude_dict = self._pulsed_master_logic._generator_logic.amplitude_dict
638
639
        self._pulsed_master_logic.generator_settings_changed(activation_config_name, laser_channel,
640
                                                             sample_rate, amplitude_dict)
641
        return
642
643
    def update_generator_settings(self, activation_config_name, activation_config, sample_rate,
644
                                   amplitude_dict, laser_channel):
645
        """
646
647
        @param activation_config_name:
648
        @param activation_config:
649
        @param sample_rate:
650
        @param amplitude_dict:
651
        @param laser_channel:
652
        @return:
653
        """
654
        # block signals
655
        self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
656
        self._pg.gen_laserchannel_ComboBox.blockSignals(True)
657
        self._pg.gen_activation_config_ComboBox.blockSignals(True)
658
        # activation config
659
        index = self._pg.gen_activation_config_ComboBox.findText(activation_config_name)
660
        self._pg.gen_activation_config_ComboBox.setCurrentIndex(index)
661
        display_str = ''
662
        for chnl in activation_config:
663
            display_str += chnl + ' | '
664
        display_str = display_str[:-3]
665
        self._pg.gen_activation_config_LineEdit.setText(display_str)
666
        self._pg.gen_analog_channels_SpinBox.setValue(
667
            len([chnl for chnl in activation_config if 'a_ch' in chnl]))
668
        self._pg.gen_digital_channels_SpinBox.setValue(
669
            len([chnl for chnl in activation_config if 'd_ch' in chnl]))
670
        # laser channel
671
        self._pg.gen_laserchannel_ComboBox.clear()
672
        self._pg.gen_laserchannel_ComboBox.addItems(activation_config)
673
        index = self._pg.gen_laserchannel_ComboBox.findText(laser_channel)
674
        self._pg.gen_laserchannel_ComboBox.setCurrentIndex(index)
675
        # sample rate
676
        self._pg.gen_sample_freq_DSpinBox.setValue(sample_rate)
677
        # set activation config in block editor
678
        if self.block_editor.activation_config != activation_config:
679
            if self.block_editor.activation_config is None:
680
                self.block_editor.set_activation_config(activation_config)
681
                self.apply_generator_settings()
682
            else:
683
                self.block_editor.set_activation_config(activation_config)
684
        # unblock signals
685
        self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
686
        self._pg.gen_laserchannel_ComboBox.blockSignals(False)
687
        self._pg.gen_activation_config_ComboBox.blockSignals(False)
688
        return
689
690
    def block_add_last_clicked(self):
691
        """
692
693
        @return:
694
        """
695
        self.block_editor.insert_rows(self._pg.block_editor_TableWidget.rowCount(), 1)
696
        return
697
698
    def block_del_last_clicked(self):
699
        """
700
701
        @return:
702
        """
703
        self.block_editor.delete_row(self._pg.block_editor_TableWidget.rowCount())
704
        return
705
706
    def block_add_sel_clicked(self):
707
        """
708
709
        @return:
710
        """
711
        index = self._pg.block_editor_TableWidget.currentRow()
712
        self.block_editor.insert_rows(index + 1, 1)
713
        return
714
715
    def block_del_sel_clicked(self):
716
        """
717
718
        @return:
719
        """
720
        index = self._pg.block_editor_TableWidget.currentRow()
721
        self.block_editor.delete_row(index)
722
        return
723
724
    def block_clear_clicked(self):
725
        """
726
727
        @return:
728
        """
729
        self.block_editor.clear_table()
730
        return
731
732
    def organizer_add_last_clicked(self):
733
        """
734
735
        @return:
736
        """
737
        self.block_organizer.insert_rows(self._pg.block_organizer_TableWidget.rowCount(), 1)
738
        return
739
740
    def organizer_del_last_clicked(self):
741
        """
742
743
        @return:
744
        """
745
        self.block_organizer.delete_row(self._pg.block_organizer_TableWidget.rowCount() - 1)
746
        return
747
748
    def organizer_add_sel_clicked(self):
749
        """
750
751
        @return:
752
        """
753
        index = self._pg.block_organizer_TableWidget.currentRow()
754
        self.block_organizer.insert_rows(index + 1, 1)
755
        return
756
757
    def organizer_del_sel_clicked(self):
758
        """
759
760
        @return:
761
        """
762
        index = self._pg.block_organizer_TableWidget.currentRow()
763
        self.block_organizer.delete_row(index)
764
        return
765
766
    def organizer_clear_clicked(self):
767
        """
768
769
        @return:
770
        """
771
        self.block_organizer.clear_table()
772
        return
773
774
    def editor_generate_block_clicked(self):
775
        name = self._pg.curr_block_name_LineEdit.text()
776
        if name == '':
777
            self.log.error('No name has been entered for the PulseBlock to be generated.')
778
            return
779
        block_object = self.block_editor.generate_block_object(name)
780
        self._pulsed_master_logic.save_pulse_block(name, block_object)
781
        return
782
783
    def editor_delete_block_clicked(self):
784
        name = self._pg.saved_blocks_ComboBox.currentText()
785
        self._pulsed_master_logic.delete_pulse_block(name)
786
        return
787
788
    def editor_load_block_clicked(self):
789
        name = self._pg.saved_blocks_ComboBox.currentText()
790
        self._pulsed_master_logic.load_pulse_block(name)
791
        return
792
793
    def editor_generate_ensemble_clicked(self):
794
        name = self._pg.curr_ensemble_name_LineEdit.text()
795
        if name == '':
796
            self.log.error('No name has been entered for the PulseBlockEnsemble to be generated.')
797
            return
798
        rotating_frame = self._pg.curr_ensemble_rot_frame_CheckBox.isChecked()
799
        ensemble_object = self.block_organizer.generate_ensemble_object(name, rotating_frame)
800
        self._pulsed_master_logic.save_block_ensemble(name, ensemble_object)
801
        return
802
803
    def editor_delete_ensemble_clicked(self):
804
        name = self._pg.saved_ensembles_ComboBox.currentText()
805
        self._pulsed_master_logic.delete_block_ensemble(name)
806
        return
807
808
    def editor_load_ensemble_clicked(self):
809
        name = self._pg.saved_ensembles_ComboBox.currentText()
810
        self._pulsed_master_logic.load_block_ensemble(name)
811
        return
812
813
    def load_block_in_editor(self, block_obj):
814
        self.block_editor.load_pulse_block(block_obj)
815
        return
816
817
    def load_ensemble_in_editor(self, ensemble_obj):
818
        self.block_organizer.load_pulse_block_ensemble(ensemble_obj)
819
        return
820
821
    def update_block_dict(self, block_dict):
822
        """
823
824
        @param block_dict:
825
        @return:
826
        """
827
        self.block_organizer.set_block_dict(block_dict)
828
        self._pg.saved_blocks_ComboBox.blockSignals(True)
829
        self._pg.saved_blocks_ComboBox.clear()
830
        self._pg.saved_blocks_ComboBox.addItems(list(block_dict))
831
        self._pg.saved_blocks_ComboBox.blockSignals(False)
832
        return
833
834
    def update_ensemble_dict(self, ensemble_dict):
835
        """
836
837
        @param ensemble_dict:
838
        @return:
839
        """
840
        # block signals
841
        self._pg.gen_ensemble_ComboBox.blockSignals(True)
842
        self._pg.saved_ensembles_ComboBox.blockSignals(True)
843
        # update gen_sequence_ComboBox items
844
        self._pg.gen_ensemble_ComboBox.clear()
845
        self._pg.gen_ensemble_ComboBox.addItems(list(ensemble_dict))
846
        self._pg.saved_ensembles_ComboBox.clear()
847
        self._pg.saved_ensembles_ComboBox.addItems(list(ensemble_dict))
848
        # unblock signals
849
        self._pg.gen_ensemble_ComboBox.blockSignals(False)
850
        self._pg.saved_ensembles_ComboBox.blockSignals(False)
851
        return
852
853
    # def update_sequence_list(self, sequence_list):
854
    #     """
855
    #
856
    #     @param sequence_list:
857
    #     @return:
858
    #     """
859
    #     # block signals
860
    #     self._pg.gen_sequence_ComboBox.blockSignals(True)
861
    #     # update gen_sequence_ComboBox items
862
    #     self._pg.gen_sequence_ComboBox.clear()
863
    #     self._pg.gen_sequence_ComboBox.addItems(sequence_list)
864
    #     # unblock signals
865
    #     self._pg.gen_sequence_ComboBox.blockSignals(False)
866
    #     return
867
868
    def sample_ensemble_clicked(self):
869
        """
870
        This method is called when the user clicks on "sample"
871
        """
872
        # Get the ensemble name from the ComboBox
873
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
874
        # disable button
875
        self._pg.sample_ensemble_PushButton.setEnabled(False)
876
        # Sample the ensemble via logic module
877
        self._pulsed_master_logic.sample_block_ensemble(ensemble_name, True, self._write_chunkwise)
878
        return
879
880
    def sample_ensemble_finished(self, ensemble_name):
881
        """
882
883
        @return:
884
        """
885
        # enable button
886
        self._pg.sample_ensemble_PushButton.setEnabled(True)
887
        return
888
889
    def sauplo_ensemble_clicked(self):
890
        """
891
892
        @return:
893
        """
894
        # Get the ensemble name from the ComboBox
895
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
896
        # disable button
897
        self._pg.sample_ensemble_PushButton.setEnabled(False)
898
        self._pg.upload_ensemble_PushButton.setEnabled(False)
899
        self._pg.load_ensemble_PushButton.setEnabled(False)
900
        # Sample the ensemble via logic module
901
        self._pulsed_master_logic.sample_block_ensemble(ensemble_name, True, self._write_chunkwise, True)
902
        return
903
904
    # def sample_sequence_clicked(self):
905
    #     """
906
    #     This method is called when the user clicks on "sample"
907
    #     """
908
    #     # Get the sequence name from the ComboBox
909
    #     sequence_name = self._pg.gen_sequence_ComboBox.currentText()
910
    #     # Sample the sequence via logic module
911
    #     self._pulsed_master_logic.sample_sequence(sequence_name, True, self._write_chunkwise)
912
    #     # disable button
913
    #     self._pg.sample_sequence_PushButton.setEnabled(False)
914
    #     return
915
916
    # def sample_sequence_finished(self, sequence_name):
917
    #     """
918
    #
919
    #     @return:
920
    #     """
921
    #     # enable button
922
    #     self._pg.sample_sequence_PushButton.setEnabled(True)
923
    #     return
924
925
    def generate_predefined_clicked(self, button_obj=None):
926
        """
927
928
        @param button_obj:
929
        @return:
930
        """
931
        if type(button_obj) is bool:
932
            button_obj = self.sender()
933
        method_name = button_obj.objectName()
934
        if method_name.startswith('gen_'):
935
            method_name = method_name[4:]
936
        elif method_name.startswith('sauplo_'):
937
            method_name = method_name[7:]
938
        else:
939
            self.log.error('Strange naming of generate buttons in predefined methods occured.')
940
            return
941
942
        # get parameters from input widgets
943
        param_index = 0
944
        param_list = []
945
        while True:
946
            if not hasattr(self._pm, method_name + '_param_' + str(param_index) + '_Widget'):
947
                break
948
949
            input_obj = getattr(self._pm, method_name + '_param_' + str(param_index) + '_Widget')
950
            if hasattr(input_obj, 'isChecked'):
951
                param_list.append(input_obj.isChecked())
952
            elif hasattr(input_obj, 'value'):
953
                param_list.append(input_obj.value())
954
            elif hasattr(input_obj, 'text'):
955
                param_list.append(input_obj.text())
956
            else:
957
                self.log.error('Not possible to get the value from the widgets, since it does not '
958
                               'have one of the possible access methods!')
959
                return
960
961
            param_index += 1
962
963
        self._pulsed_master_logic.generate_predefined_sequence(method_name, param_list)
964
        return
965
966
    def generate_sauplo_predefined_clicked(self):
967
        button_obj = self.sender()
968
        method_name = button_obj.objectName()[7:]
969
        self.generate_predefined_clicked(button_obj)
970
        # get name of the generated ensemble
971
        input_obj = getattr(self._pm, method_name + '_param_0_Widget')
972
        if not hasattr(input_obj, 'text'):
973
            self.log.error('Predefined sequence methods must have as first argument the name of '
974
                           'the asset to be generated.')
975
            return
976
        name = input_obj.text()
977
        self._pulsed_master_logic.sample_block_ensemble(name, True, False, True)
978
        return
979
980
    ###########################################################################
981
    ###        Methods related to Settings for the 'Analysis' Tab:          ###
982
    ###########################################################################
983
    #FIXME: Implement the setting for 'Analysis' tab.
984
    def _activate_analysis_settings_ui(self, e):
985
        """ Initialize, connect and configure the Settings of 'Analysis' Tab.
986
987
        @param object e: Fysom.event object from Fysom class. A more detailed
988
                         explanation can be found in the method initUI.
989
        """
990
        self._as = AnalysisSettingDialog()
991
        self._as.accepted.connect(self.update_analysis_settings)
992
        self._as.rejected.connect(self.keep_former_analysis_settings)
993
        self._as.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_analysis_settings)
994
995
        if 'ana_param_x_axis_name_LineEdit' in self._statusVariables:
996
            self._as.ana_param_x_axis_name_LineEdit.setText(self._statusVariables['ana_param_x_axis_name_LineEdit'])
997
        if 'ana_param_x_axis_unit_LineEdit' in self._statusVariables:
998
            self._as.ana_param_x_axis_unit_LineEdit.setText(self._statusVariables['ana_param_x_axis_unit_LineEdit'])
999
        if 'ana_param_y_axis_name_LineEdit' in self._statusVariables:
1000
            self._as.ana_param_y_axis_name_LineEdit.setText(self._statusVariables['ana_param_y_axis_name_LineEdit'])
1001
        if 'ana_param_y_axis_unit_LineEdit' in self._statusVariables:
1002
            self._as.ana_param_y_axis_unit_LineEdit.setText(self._statusVariables['ana_param_y_axis_unit_LineEdit'])
1003
        if 'ana_param_second_plot_x_axis_name_LineEdit' in self._statusVariables:
1004
            self._as.ana_param_second_plot_x_axis_name_LineEdit.setText(self._statusVariables['ana_param_second_plot_x_axis_name_LineEdit'])
1005
        if 'ana_param_second_plot_x_axis_unit_LineEdit' in self._statusVariables:
1006
            self._as.ana_param_second_plot_x_axis_unit_LineEdit.setText(self._statusVariables['ana_param_second_plot_x_axis_unit_LineEdit'])
1007
        if 'ana_param_second_plot_y_axis_name_LineEdit' in self._statusVariables:
1008
            self._as.ana_param_second_plot_y_axis_name_LineEdit.setText(self._statusVariables['ana_param_second_plot_y_axis_name_LineEdit'])
1009
        if 'ana_param_second_plot_y_axis_unit_LineEdit' in self._statusVariables:
1010
            self._as.ana_param_second_plot_y_axis_unit_LineEdit.setText(self._statusVariables['ana_param_second_plot_y_axis_unit_LineEdit'])
1011
        self.update_analysis_settings()
1012
        return
1013
1014
1015
    def _deactivate_analysis_settings_ui(self, e):
1016
        """ Disconnects the configuration of the Settings for 'Analysis' Tab.
1017
1018
        @param object e: Fysom.event object from Fysom class. A more detailed
1019
                         explanation can be found in the method initUI.
1020
        """
1021
        self._statusVariables['ana_param_x_axis_name_LineEdit'] = self._as.ana_param_x_axis_name_LineEdit.text()
1022
        self._statusVariables['ana_param_x_axis_unit_LineEdit'] = self._as.ana_param_x_axis_unit_LineEdit.text()
1023
        self._statusVariables['ana_param_y_axis_name_LineEdit'] = self._as.ana_param_y_axis_name_LineEdit.text()
1024
        self._statusVariables['ana_param_y_axis_unit_LineEdit'] = self._as.ana_param_y_axis_unit_LineEdit.text()
1025
        self._statusVariables['ana_param_second_plot_x_axis_name_LineEdit'] = self._as.ana_param_second_plot_x_axis_name_LineEdit.text()
1026
        self._statusVariables['ana_param_second_plot_x_axis_unit_LineEdit'] = self._as.ana_param_second_plot_x_axis_unit_LineEdit.text()
1027
        self._statusVariables['ana_param_second_plot_y_axis_name_LineEdit'] = self._as.ana_param_second_plot_y_axis_name_LineEdit.text()
1028
        self._statusVariables['ana_param_second_plot_y_axis_unit_LineEdit'] = self._as.ana_param_second_plot_y_axis_unit_LineEdit.text()
1029
        return
1030
1031
1032
    def update_analysis_settings(self):
1033
        """ Apply the new settings """
1034
        self._pa.pulse_analysis_PlotWidget.setLabel(
1035
            axis='bottom',
1036
            text=self._as.ana_param_x_axis_name_LineEdit.text(),
1037
            units=self._as.ana_param_x_axis_unit_LineEdit.text())
1038
        self._pa.pulse_analysis_PlotWidget.setLabel(
1039
            axis='left',
1040
            text=self._as.ana_param_y_axis_name_LineEdit.text(),
1041
            units=self._as.ana_param_y_axis_unit_LineEdit.text())
1042
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
1043
            axis='bottom',
1044
            text=self._as.ana_param_second_plot_x_axis_name_LineEdit.text(),
1045
            units=self._as.ana_param_second_plot_x_axis_unit_LineEdit.text())
1046
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
1047
            axis='left',
1048
            text=self._as.ana_param_second_plot_y_axis_name_LineEdit.text(),
1049
            units=self._as.ana_param_second_plot_y_axis_unit_LineEdit.text())
1050
        return
1051
1052
    def keep_former_analysis_settings(self):
1053
        """ Keep the old settings """
1054
        #FIXME: Implement the behaviour
1055
        pass
1056
1057
    def show_analysis_settings(self):
1058
        """ Open the Analysis Settings Window. """
1059
        self._as.exec_()
1060
        return
1061
1062
    ###########################################################################
1063
    ###     Methods related to the Tab 'Analysis' in the Pulsed Window:     ###
1064
    ###########################################################################
1065
    def setup_toolbar(self):
1066
        # create all the needed control widgets on the fly and connect their
1067
        # actions to each other:
1068
        self._mw.pulser_on_off_PushButton = QtWidgets.QPushButton()
1069
        self._mw.pulser_on_off_PushButton.setText('Pulser ON')
1070
        self._mw.pulser_on_off_PushButton.setToolTip('Switch the device on and off.')
1071
        self._mw.pulser_on_off_PushButton.setCheckable(True)
1072
        self._mw.control_ToolBar.addWidget(self._mw.pulser_on_off_PushButton)
1073
1074
        self._mw.clear_device_PushButton = QtWidgets.QPushButton(self._mw)
1075
        self._mw.clear_device_PushButton.setText('Clear Pulser')
1076
        self._mw.clear_device_PushButton.setToolTip(
1077
            'Clear the Pulser Device Memory\nfrom all loaded files.')
1078
        self._mw.control_ToolBar.addWidget(self._mw.clear_device_PushButton)
1079
1080
        self._mw.current_loaded_asset_Label = QtWidgets.QLabel(self._mw)
1081
        sizepolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
1082
                                           QtWidgets.QSizePolicy.Fixed)
1083
        sizepolicy.setHorizontalStretch(0)
1084
        sizepolicy.setVerticalStretch(0)
1085
        sizepolicy.setHeightForWidth(
1086
            self._mw.current_loaded_asset_Label.sizePolicy().hasHeightForWidth())
1087
        self._mw.current_loaded_asset_Label.setSizePolicy(sizepolicy)
1088
        self._mw.current_loaded_asset_Label.setText('  No Asset Loaded')
1089
        self._mw.current_loaded_asset_Label.setToolTip('Display the currently loaded asset.')
1090
        self._mw.control_ToolBar.addWidget(self._mw.current_loaded_asset_Label)
1091
1092
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit()
1093
        self._mw.save_tag_LineEdit.setMaximumWidth(200)
1094
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)
1095
1096
    def setup_extraction_ui(self):
1097
        self.lasertrace_image = pg.PlotDataItem(np.array(range(10)), np.zeros(10), pen=palette.c1)
1098
        self._pe.laserpulses_PlotWidget.addItem(self.lasertrace_image)
1099
        self._pe.laserpulses_PlotWidget.addItem(self.sig_start_line)
1100
        self._pe.laserpulses_PlotWidget.addItem(self.sig_end_line)
1101
        self._pe.laserpulses_PlotWidget.addItem(self.ref_start_line)
1102
        self._pe.laserpulses_PlotWidget.addItem(self.ref_end_line)
1103
        self._pe.laserpulses_PlotWidget.setLabel('bottom', 'bins')
1104
1105
    def _activate_analysis_ui(self, e):
1106
        """ Initialize, connect and configure the 'Analysis' Tab.
1107
1108
        @param object e: Fysom.event object from Fysom class. A more detailed
1109
                         explanation can be found in the method initUI.
1110
        """
1111
        # FIXME: Implement second plot
1112
        self._pa.second_plot_GroupBox.setVisible(False)
1113
        # Configure the main pulse analysis display:
1114
        self.signal_image = pg.PlotDataItem(np.array(range(10)), np.zeros(10), pen=palette.c1)
1115
        self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image)
1116
        self.signal_image2 = pg.PlotDataItem(pen=palette.c3)
1117
        self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image2)
1118
        self._pa.pulse_analysis_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
1119
1120
        # Configure the fit of the data in the main pulse analysis display:
1121
        self.fit_image = pg.PlotDataItem(pen=palette.c2)
1122
        self._pa.pulse_analysis_PlotWidget.addItem(self.fit_image)
1123
        self._pa.fit_param_fit_func_ComboBox.clear()
1124
        self._pa.fit_param_fit_func_ComboBox.addItems(self._pulsed_master_logic.get_fit_functions())
1125
1126
        # Configure the errorbars of the data in the main pulse analysis display:
1127
        self.signal_image_error_bars = pg.ErrorBarItem(
1128
            x=np.array(range(10)),
1129
            y=np.zeros(10),
1130
            top=0.,
1131
            bottom=0.,
1132
            pen=palette.c1)
1133
        self.signal_image_error_bars2 = pg.ErrorBarItem(
1134
            x=np.array(range(10)),
1135
            y=np.zeros(10),
1136
            top=0.,
1137
            bottom=0.,
1138
            pen=palette.c3)
1139
1140
        # Configure the second pulse analysis display:
1141
        self.second_plot_image = pg.PlotDataItem(np.array(range(10)), np.zeros(10), pen=palette.c1)
1142
        self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image)
1143
        self._pa.pulse_analysis_second_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
1144
1145
        # Configure the lasertrace plot display:
1146
        self.sig_start_line = pg.InfiniteLine(pos=0, pen=QtGui.QPen(palette.c3), movable=True)
1147
        self.sig_start_line.setHoverPen(QtGui.QPen(palette.c2))
1148
        self.sig_end_line = pg.InfiniteLine(pos=0, pen=QtGui.QPen(palette.c3), movable=True)
1149
        self.sig_end_line.setHoverPen(QtGui.QPen(palette.c2))
1150
        self.ref_start_line = pg.InfiniteLine(pos=0, pen=QtGui.QPen(palettedark.c4), movable=True)
1151
        self.ref_start_line.setHoverPen(QtGui.QPen(palette.c4))
1152
        self.ref_end_line = pg.InfiniteLine(pos=0, pen=QtGui.QPen(palettedark.c4), movable=True)
1153
        self.ref_end_line.setHoverPen(QtGui.QPen(palette.c4))
1154
        # Configure the measuring error display:
1155
        self.measuring_error_image = pg.PlotDataItem(
1156
            np.array(range(10)),
1157
            np.zeros(10),
1158
            pen=palette.c1)
1159
        self.measuring_error_image2 = pg.PlotDataItem(
1160
            np.array(range(10)),
1161
            np.zeros(10),
1162
            pen=palette.c3)
1163
        self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image)
1164
        self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image2)
1165
        self._pe.measuring_error_PlotWidget.setLabel('left', 'measuring error', units='a.u.')
1166
        self._pe.measuring_error_PlotWidget.setLabel('bottom', 'tau', units='ns')
1167
1168
1169
        # set boundaries
1170
        self._pe.slider_conv_std_dev.setRange(1, 200)
1171
        self._pe.conv_std_dev.setRange(1, 200)
1172
1173
        # ---------------------------------------------------------------------
1174
        #                         Connect signals
1175
        # ---------------------------------------------------------------------
1176
        # connect update signals from logic
1177
        self._pulsed_master_logic.sigSignalDataUpdated.connect(self.signal_data_updated)
1178
        self._pulsed_master_logic.sigLaserDataUpdated.connect(self.laser_data_updated)
1179
        self._pulsed_master_logic.sigLaserToShowUpdated.connect(self.laser_to_show_updated)
1180
        self._pulsed_master_logic.sigElapsedTimeUpdated.connect(self.elapsed_time_updated)
1181
        self._pulsed_master_logic.sigFitUpdated.connect(self.fit_data_updated)
1182
        self._pulsed_master_logic.sigMeasurementStatusUpdated.connect(self.measurement_status_updated)
1183
        self._pulsed_master_logic.sigPulserRunningUpdated.connect(self.pulser_running_updated)
1184
        self._pulsed_master_logic.sigFastCounterSettingsUpdated.connect(self.fast_counter_settings_updated)
1185
        self._pulsed_master_logic.sigMeasurementSequenceSettingsUpdated.connect(self.measurement_sequence_settings_updated)
1186
        self._pulsed_master_logic.sigPulserSettingsUpdated.connect(self.pulse_generator_settings_updated)
1187
        self._pulsed_master_logic.sigUploadedAssetsUpdated.connect(self.update_uploaded_assets)
1188
        self._pulsed_master_logic.sigLoadedAssetUpdated.connect(self.update_loaded_asset)
1189
        self._pulsed_master_logic.sigExtMicrowaveSettingsUpdated.connect(self.microwave_settings_updated)
1190
        self._pulsed_master_logic.sigExtMicrowaveRunningUpdated.connect(self.microwave_running_updated)
1191
        self._pulsed_master_logic.sigTimerIntervalUpdated.connect(self.measurement_timer_updated)
1192
        self._pulsed_master_logic.sigAnalysisWindowsUpdated.connect(self.analysis_windows_updated)
1193
        self._pulsed_master_logic.sigAnalysisMethodUpdated.connect(self.analysis_method_updated)
1194
1195
        # connect button click signals
1196
        self._pg.upload_ensemble_PushButton.clicked.connect(self.upload_ensemble_clicked)
1197
        self._pg.load_ensemble_PushButton.clicked.connect(self.load_ensemble_clicked)
1198
        # self._pg.upload_sequence_PushButton.clicked.connect(self.upload_sequence_clicked)
1199
        # self._pg.load_sequence_PushButton.clicked.connect(self.load_sequence_clicked)
1200
        self._mw.pulser_on_off_PushButton.clicked.connect(self.pulser_on_off_clicked)
1201
        self._mw.clear_device_PushButton.clicked.connect(self.clear_pulser_clicked)
1202
        self._pa.fit_param_PushButton.clicked.connect(self.fit_clicked)
1203
1204
        # connect action trigger signals
1205
        self._mw.action_run_stop.triggered.connect(self.measurement_run_stop_clicked)
1206
        self._mw.action_continue_pause.triggered.connect(self.measurement_continue_pause_clicked)
1207
        self._mw.action_pull_data.triggered.connect(self.pull_data_clicked)
1208
        self._mw.action_save.triggered.connect(self.save_clicked)
1209
        self._mw.action_Settings_Analysis.triggered.connect(self.show_analysis_settings)
1210
1211
        # connect checkbox click signals
1212
        self._pa.ext_control_use_mw_CheckBox.stateChanged.connect(self.ext_mw_params_changed)
1213
        self._pa.ana_param_x_axis_defined_CheckBox.stateChanged.connect(self.toggle_laser_xaxis_editor)
1214
        self._pa.ana_param_laserpulse_defined_CheckBox.stateChanged.connect(self.toggle_laser_xaxis_editor)
1215
        self._pa.ana_param_alternating_CheckBox.stateChanged.connect(self.measurement_sequence_settings_changed)
1216
        self._pa.ana_param_ignore_first_CheckBox.stateChanged.connect(self.measurement_sequence_settings_changed)
1217
        self._pa.ana_param_ignore_last_CheckBox.stateChanged.connect(self.measurement_sequence_settings_changed)
1218
        self._pe.laserpulses_display_raw_CheckBox.stateChanged.connect(self.laser_to_show_changed)
1219
        self._pa.ana_param_errorbars_CheckBox.stateChanged.connect(self.toggle_error_bars)
1220
        self._pa.pulser_use_interleave_CheckBox.stateChanged.connect(self.pulse_generator_settings_changed)
1221
1222
        # connect spinbox changed signals
1223
        self._pa.ana_param_num_laser_pulse_SpinBox.editingFinished.connect(self.measurement_sequence_settings_changed)
1224
        self._pa.ana_param_record_length_SpinBox.editingFinished.connect(self.fast_counter_settings_changed)
1225
        self._pa.time_param_ana_periode_DoubleSpinBox.editingFinished.connect(self.measurement_timer_changed)
1226
        self._pa.ext_control_mw_freq_DoubleSpinBox.editingFinished.connect(self.ext_mw_params_changed)
1227
        self._pa.ext_control_mw_power_DoubleSpinBox.editingFinished.connect(self.ext_mw_params_changed)
1228
        self._pa.pulser_sample_freq_DSpinBox.editingFinished.connect(self.pulse_generator_settings_changed)
1229
        self._pa.ana_param_x_axis_start_ScienDSpinBox.editingFinished.connect(self.measurement_sequence_settings_changed)
1230
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.editingFinished.connect(self.measurement_sequence_settings_changed)
1231
        self._pe.extract_param_ana_window_start_SpinBox.editingFinished.connect(self.analysis_windows_changed)
1232
        self._pe.extract_param_ana_window_width_SpinBox.editingFinished.connect(self.analysis_windows_changed)
1233
        self._pe.extract_param_ref_window_start_SpinBox.editingFinished.connect(self.analysis_windows_changed)
1234
        self._pe.extract_param_ref_window_width_SpinBox.editingFinished.connect(self.analysis_windows_changed)
1235
        self._pe.conv_std_dev.valueChanged.connect(self.conv_std_dev_changed)
1236
1237
        # connect combobox changed signals
1238
        self._pa.ana_param_fc_bins_ComboBox.currentIndexChanged.connect(self.fast_counter_settings_changed)
1239
        #self._pa.second_plot_ComboBox.currentIndexChanged.connect(self.change_second_plot)
1240
        self._pa.pulser_activation_config_ComboBox.currentIndexChanged.connect(self.pulse_generator_settings_changed)
1241
        self._pe.laserpulses_ComboBox.currentIndexChanged.connect(self.laser_to_show_changed)
1242
1243
        # connect other widgets changed signals
1244
        self.sig_start_line.sigPositionChanged.connect(self.analysis_windows_line_changed)
1245
        self.sig_end_line.sigPositionChanged.connect(self.analysis_windows_line_changed)
1246
        self.ref_start_line.sigPositionChanged.connect(self.analysis_windows_line_changed)
1247
        self.ref_end_line.sigPositionChanged.connect(self.analysis_windows_line_changed)
1248
        self._pe.slider_conv_std_dev.sliderReleased.connect(self.slider_conv_std_dev_changed)
1249
1250
        # apply hardware constraints
1251
        self._analysis_apply_hardware_constraints()
1252
1253
        # initialize values
1254
        self._pulsed_master_logic.request_measurement_init_values()
1255
        return
1256
1257
    def _deactivate_analysis_ui(self, e):
1258
        """ Disconnects the configuration for 'Analysis' Tab.
1259
1260
       @param object e: Fysom.event object from Fysom class. A more detailed
1261
                         explanation can be found in the method initUI.
1262
        """
1263
        self.measurement_run_stop_clicked(False)
1264
1265
        self._statusVariables['ana_param_x_axis_defined_CheckBox'] = self._pa.ana_param_x_axis_defined_CheckBox.isChecked()
1266
        self._statusVariables['ana_param_laserpulse_defined_CheckBox'] = self._pa.ana_param_laserpulse_defined_CheckBox.isChecked()
1267
        self._statusVariables['ana_param_ignore_first_CheckBox'] = self._pa.ana_param_ignore_first_CheckBox.isChecked()
1268
        self._statusVariables['ana_param_ignore_last_CheckBox'] = self._pa.ana_param_ignore_last_CheckBox.isChecked()
1269
        self._statusVariables['ana_param_errorbars_CheckBox'] = self._pa.ana_param_errorbars_CheckBox.isChecked()
1270
        self._statusVariables['second_plot_ComboBox_text'] = self._pa.second_plot_ComboBox.currentText()
1271
1272
        # disconnect signals
1273
        self._pulsed_master_logic.sigSignalDataUpdated.disconnect()
1274
        self._pulsed_master_logic.sigLaserDataUpdated.disconnect()
1275
        self._pulsed_master_logic.sigLaserToShowUpdated.disconnect()
1276
        self._pulsed_master_logic.sigElapsedTimeUpdated.disconnect()
1277
        self._pulsed_master_logic.sigFitUpdated.disconnect()
1278
        self._pulsed_master_logic.sigMeasurementStatusUpdated.disconnect()
1279
        self._pulsed_master_logic.sigPulserRunningUpdated.disconnect()
1280
        self._pulsed_master_logic.sigFastCounterSettingsUpdated.disconnect()
1281
        self._pulsed_master_logic.sigMeasurementSequenceSettingsUpdated.disconnect()
1282
        self._pulsed_master_logic.sigPulserSettingsUpdated.disconnect()
1283
        self._pulsed_master_logic.sigUploadedAssetsUpdated.disconnect()
1284
        self._pulsed_master_logic.sigLoadedAssetUpdated.disconnect()
1285
        self._pulsed_master_logic.sigExtMicrowaveSettingsUpdated.disconnect()
1286
        self._pulsed_master_logic.sigExtMicrowaveRunningUpdated.disconnect()
1287
        self._pulsed_master_logic.sigTimerIntervalUpdated.disconnect()
1288
        self._pulsed_master_logic.sigAnalysisWindowsUpdated.disconnect()
1289
        self._pulsed_master_logic.sigAnalysisMethodUpdated.disconnect()
1290
        self._pg.upload_ensemble_PushButton.clicked.disconnect()
1291
        self._pg.load_ensemble_PushButton.clicked.disconnect()
1292
        # self._pg.upload_sequence_PushButton.clicked.disconnect()
1293
        # self._pg.load_sequence_PushButton.clicked.disconnect()
1294
        self._mw.pulser_on_off_PushButton.clicked.disconnect()
1295
        self._mw.clear_device_PushButton.clicked.disconnect()
1296
        self._pa.fit_param_PushButton.clicked.disconnect()
1297
        self._mw.action_run_stop.triggered.disconnect()
1298
        self._mw.action_continue_pause.triggered.disconnect()
1299
        self._mw.action_pull_data.triggered.disconnect()
1300
        self._mw.action_save.triggered.disconnect()
1301
        self._mw.action_Settings_Analysis.triggered.disconnect()
1302
        self._pa.ext_control_use_mw_CheckBox.stateChanged.disconnect()
1303
        self._pa.ana_param_x_axis_defined_CheckBox.stateChanged.disconnect()
1304
        self._pa.ana_param_laserpulse_defined_CheckBox.stateChanged.disconnect()
1305
        self._pa.ana_param_alternating_CheckBox.stateChanged.disconnect()
1306
        self._pa.ana_param_ignore_first_CheckBox.stateChanged.disconnect()
1307
        self._pa.ana_param_ignore_last_CheckBox.stateChanged.disconnect()
1308
        self._pe.laserpulses_display_raw_CheckBox.stateChanged.disconnect()
1309
        self._pa.ana_param_errorbars_CheckBox.stateChanged.disconnect()
1310
        self._pa.pulser_use_interleave_CheckBox.stateChanged.disconnect()
1311
        self._pa.ana_param_num_laser_pulse_SpinBox.editingFinished.disconnect()
1312
        self._pa.ana_param_record_length_SpinBox.editingFinished.disconnect()
1313
        self._pa.time_param_ana_periode_DoubleSpinBox.editingFinished.disconnect()
1314
        self._pa.ext_control_mw_freq_DoubleSpinBox.editingFinished.disconnect()
1315
        self._pa.ext_control_mw_power_DoubleSpinBox.editingFinished.disconnect()
1316
        self._pa.pulser_sample_freq_DSpinBox.editingFinished.disconnect()
1317
        self._pa.ana_param_x_axis_start_ScienDSpinBox.editingFinished.disconnect()
1318
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.editingFinished.disconnect()
1319
        self._pe.extract_param_ana_window_start_SpinBox.editingFinished.disconnect()
1320
        self._pe.extract_param_ana_window_width_SpinBox.editingFinished.disconnect()
1321
        self._pe.extract_param_ref_window_start_SpinBox.editingFinished.disconnect()
1322
        self._pe.extract_param_ref_window_width_SpinBox.editingFinished.disconnect()
1323
        self._pe.conv_std_dev.valueChanged.disconnect()
1324
        self._pa.ana_param_fc_bins_ComboBox.currentIndexChanged.disconnect()
1325
        #self._pa.second_plot_ComboBox.currentIndexChanged.disconnect()
1326
        self._pa.pulser_activation_config_ComboBox.currentIndexChanged.disconnect()
1327
        self._pe.laserpulses_ComboBox.currentIndexChanged.disconnect()
1328
        self.sig_start_line.sigPositionChanged.disconnect()
1329
        self.sig_end_line.sigPositionChanged.disconnect()
1330
        self.ref_start_line.sigPositionChanged.disconnect()
1331
        self.ref_end_line.sigPositionChanged.disconnect()
1332
        self._pe.slider_conv_std_dev.sliderReleased.disconnect()
1333
        return
1334
1335
    def _analysis_apply_hardware_constraints(self):
1336
        """
1337
        Retrieve the constraints from pulser and fast counter hardware and apply these constraints
1338
        to the analysis tab GUI elements.
1339
        """
1340
        # block signals
1341
        self._pa.pulser_activation_config_ComboBox.blockSignals(True)
1342
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(True)
1343
        # apply constraints
1344
        pulser_constr, fastcounter_constr = self._pulsed_master_logic.get_hardware_constraints()
1345
        sample_min = pulser_constr['sample_rate']['min']
1346
        sample_max = pulser_constr['sample_rate']['max']
1347
        sample_step = pulser_constr['sample_rate']['step']
1348
        self._pa.pulser_sample_freq_DSpinBox.setMinimum(sample_min)
1349
        self._pa.pulser_sample_freq_DSpinBox.setMaximum(sample_max)
1350
        self._pa.pulser_sample_freq_DSpinBox.setSingleStep(sample_step)
1351
        self._pa.pulser_activation_config_ComboBox.clear()
1352
        self._pa.pulser_activation_config_ComboBox.addItems(list(pulser_constr['activation_config']))
1353
        self._pa.ana_param_fc_bins_ComboBox.clear()
1354
        for binwidth in fastcounter_constr['hardware_binwidth_list']:
1355
            self._pa.ana_param_fc_bins_ComboBox.addItem(str(binwidth))
1356
        # unblock signals
1357
        self._pa.pulser_activation_config_ComboBox.blockSignals(False)
1358
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(False)
1359
        return
1360
1361
    def measurement_run_stop_clicked(self, isChecked):
1362
        """ Manages what happens if pulsed measurement is started or stopped.
1363
1364
        @param bool isChecked: start scan if that is possible
1365
        """
1366
        if isChecked:
1367
            self._pulsed_master_logic.start_measurement()
1368
        else:
1369
            self._pulsed_master_logic.stop_measurement()
1370
        return
1371
1372
    #ToDo: I think that is not really working yet. Yeap, true....
1373
    def measurement_continue_pause_clicked(self, isChecked):
1374
        """ Continues and pauses the measurement. """
1375
        if isChecked:
1376
            self._pulsed_master_logic.pause_measurement()
1377
        else:
1378
            self._pulsed_master_logic.continue_measurement()
1379
        return
1380
1381
    def measurement_status_updated(self, is_running, is_paused):
1382
        """
1383
1384
        @param is_running:
1385
        @param is_paused:
1386
        @return:
1387
        """
1388
        # block signals
1389
        self._mw.action_run_stop.blockSignals(True)
1390
        self._mw.action_continue_pause.blockSignals(True)
1391
1392
        # Enable/Disable widgets
1393
        if is_running:
1394
            self._pa.ext_control_use_mw_CheckBox.setEnabled(False)
1395
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
1396
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
1397
            self._pa.pulser_sample_freq_DSpinBox.setEnabled(False)
1398
            self._pa.pulser_activation_config_ComboBox.setEnabled(False)
1399
            self._pa.ana_param_fc_bins_ComboBox.setEnabled(False)
1400
            self._pa.ana_param_laserpulse_defined_CheckBox.setEnabled(False)
1401
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(False)
1402
            self._pa.ana_param_record_length_SpinBox.setEnabled(False)
1403
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(False)
1404
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(False)
1405
            self._pa.ana_param_alternating_CheckBox.setEnabled(False)
1406
            self._pa.ana_param_x_axis_defined_CheckBox.setEnabled(False)
1407
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(False)
1408
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(False)
1409
            self._pg.load_ensemble_PushButton.setEnabled(False)
1410
            # self._pg.load_sequence_PushButton.setEnabled(False)
1411
            self._mw.pulser_on_off_PushButton.setEnabled(False)
1412
            self._mw.action_continue_pause.setEnabled(True)
1413
            self._mw.action_pull_data.setEnabled(True)
1414
            if not self._mw.action_run_stop.isChecked():
1415
                self._mw.action_run_stop.toggle()
1416
        else:
1417
            self._pa.ext_control_use_mw_CheckBox.setEnabled(True)
1418
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
1419
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
1420
            self._pa.pulser_sample_freq_DSpinBox.setEnabled(True)
1421
            self._pa.pulser_activation_config_ComboBox.setEnabled(True)
1422
            self._pa.ana_param_fc_bins_ComboBox.setEnabled(True)
1423
            self._pa.ana_param_laserpulse_defined_CheckBox.setEnabled(True)
1424
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(True)
1425
            self._pa.ana_param_record_length_SpinBox.setEnabled(True)
1426
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(True)
1427
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(True)
1428
            self._pa.ana_param_alternating_CheckBox.setEnabled(True)
1429
            self._pa.ana_param_x_axis_defined_CheckBox.setEnabled(True)
1430
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(True)
1431
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(True)
1432
            self._pg.load_ensemble_PushButton.setEnabled(True)
1433
            # self._pg.load_sequence_PushButton.setEnabled(True)
1434
            self._mw.pulser_on_off_PushButton.setEnabled(True)
1435
            self._mw.action_continue_pause.setEnabled(False)
1436
            self._mw.action_pull_data.setEnabled(False)
1437
            if self._mw.action_run_stop.isChecked():
1438
                self._mw.action_run_stop.toggle()
1439
        if is_paused:
1440
            if not self._mw.action_continue_pause.isChecked():
1441
                self._mw.action_continue_pause.toggle()
1442
        else:
1443
            if self._mw.action_continue_pause.isChecked():
1444
                self._mw.action_continue_pause.toggle()
1445
        # unblock signals
1446
        self._mw.action_run_stop.blockSignals(False)
1447
        self._mw.action_continue_pause.blockSignals(False)
1448
        return
1449
1450
    def pull_data_clicked(self):
1451
        """ Pulls and analysis the data when the 'action_pull_data'-button is clicked. """
1452
        self._pulsed_master_logic.manually_pull_data()
1453
        return
1454
1455
    def signal_data_updated(self, x_data, y_signal_data, y2_signal_data, y_error_data, y2_error_data):
1456
        """
1457
1458
        @param x_data:
1459
        @param y_signal_data:
1460
        @param y2_signal_data:
1461
        @param y_error_data:
1462
        @param y2_error_data:
1463
        @return:
1464
        """
1465
        show_error_bars = self._pa.ana_param_errorbars_CheckBox.isChecked()
1466
        is_alternating = self._pa.ana_param_alternating_CheckBox.isChecked()
1467
        if show_error_bars:
1468
            beamwidth = np.inf
1469
            for i in range(len(x_data) - 1):
1470
                width = x_data[i + 1] - x_data[i]
1471
                width = width / 3
1472
                if width <= beamwidth:
1473
                    beamwidth = width
1474
            # create ErrorBarItems
1475
            self.signal_image_error_bars.setData(x=x_data, y=y_signal_data, top=y_error_data,
1476
                                                 bottom=y_error_data, beam=beamwidth)
1477
            if is_alternating:
1478
                self.signal_image_error_bars2.setData(x=x_data, y=y2_signal_data, top=y2_error_data,
1479
                                                      bottom=y2_error_data, beam=beamwidth)
1480
            if not self.signal_image_error_bars in self._pa.pulse_analysis_PlotWidget.items():
1481
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars)
1482
                if is_alternating:
1483
                    self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
1484
        else:
1485
            if self.signal_image_error_bars in self._pa.pulse_analysis_PlotWidget.items():
1486
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars)
1487
                if is_alternating:
1488
                    self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
1489
1490
        # dealing with the actual signal
1491
        self.signal_image.setData(x=x_data, y=y_signal_data)
1492
        if is_alternating:
1493
            self.signal_image2.setData(x=x_data, y=y2_signal_data)
1494
1495
        # dealing with the error plot
1496
        self.measuring_error_image.setData(x=x_data, y=y_error_data)
1497
        if is_alternating:
1498
            self.measuring_error_image2.setData(x=x_data, y=y2_error_data)
1499
        return
1500
1501
    def save_clicked(self):
1502
        """Saves the current data"""
1503
        self._mw.action_save.setEnabled(False)
1504
        save_tag = self._mw.save_tag_LineEdit.text()
1505
        self._pulsed_master_logic.save_measurement_data(save_tag)
1506
        self._mw.action_save.setEnabled(True)
1507
        return
1508
1509
    def fit_clicked(self):
1510
        """Fits the current data"""
1511
        current_fit_function = self._pa.fit_param_fit_func_ComboBox.currentText()
1512
        self._pulsed_master_logic.do_fit(current_fit_function)
1513
        return
1514
1515
    def fit_data_updated(self, fit_function, fit_data_x, fit_data_y, param_dict, result_dict):
1516
        """
1517
1518
        @param fit_function:
1519
        @param fit_data_x:
1520
        @param fit_data_y:
1521
        @param param_dict:
1522
        @param result_dict:
1523
        @return:
1524
        """
1525
        # block signals
1526
        self._pa.fit_param_fit_func_ComboBox.blockSignals(True)
1527
        # set widgets
1528
        self._pa.fit_param_results_TextBrowser.clear()
1529
        fit_text = units.create_formatted_output(param_dict)
1530
        self._pa.fit_param_results_TextBrowser.setPlainText(fit_text)
1531
        self.fit_image.setData(x=fit_data_x, y=fit_data_y)
1532
        if fit_function == 'No Fit' and self.fit_image in self._pa.pulse_analysis_PlotWidget.items():
1533
            self._pa.pulse_analysis_PlotWidget.removeItem(self.fit_image)
1534
        elif fit_function != 'No Fit' and self.fit_image not in self._pa.pulse_analysis_PlotWidget.items():
1535
            self._pa.pulse_analysis_PlotWidget.addItem(self.fit_image)
1536
        if self._pa.fit_param_fit_func_ComboBox.currentText() != fit_function:
1537
            index = self._pa.fit_param_fit_func_ComboBox.findText(fit_function)
1538
            if index >= 0:
1539
                self._pa.fit_param_fit_func_ComboBox.setCurrentIndex(index)
1540
        # unblock signals
1541
        self._pa.fit_param_fit_func_ComboBox.blockSignals(False)
1542
        return
1543
1544
    def elapsed_time_updated(self, elapsed_time, elapsed_time_str):
1545
        """
1546
        Refreshes the elapsed time and sweeps of the measurement.
1547
1548
        @param elapsed_time:
1549
        @param elapsed_time_str:
1550
        @return:
1551
        """
1552
        # block signals
1553
        self._pa.time_param_elapsed_time_LineEdit.blockSignals(True)
1554
        # Set widgets
1555
        self._pa.time_param_elapsed_time_LineEdit.setText(elapsed_time_str)
1556
        # unblock signals
1557
        self._pa.time_param_elapsed_time_LineEdit.blockSignals(True)
1558
        return
1559
1560
    def ext_mw_params_changed(self):
1561
        """ Shows or hides input widgets which are necessary if an external mw is turned on"""
1562
        use_ext_microwave = self._pa.ext_control_use_mw_CheckBox.isChecked()
1563
        microwave_freq = self._pa.ext_control_mw_freq_DoubleSpinBox.value()
1564
        microwave_power = self._pa.ext_control_mw_power_DoubleSpinBox.value()
1565 View Code Duplication
        if use_ext_microwave:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1566
            self._pa.ext_control_mw_freq_Label.setEnabled(True)
1567
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
1568
            self._pa.ext_control_mw_power_Label.setEnabled(True)
1569
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
1570
1571
            self._pa.ext_control_mw_freq_Label.setVisible(True)
1572
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(True)
1573
            self._pa.ext_control_mw_power_Label.setVisible(True)
1574
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(True)
1575
        else:
1576
            self._pa.ext_control_mw_freq_Label.setEnabled(False)
1577
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
1578
            self._pa.ext_control_mw_power_Label.setEnabled(False)
1579
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
1580
1581
            self._pa.ext_control_mw_freq_Label.setVisible(False)
1582
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(False)
1583
            self._pa.ext_control_mw_power_Label.setVisible(False)
1584
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(False)
1585
1586
        self._pulsed_master_logic.ext_microwave_settings_changed(microwave_freq, microwave_power,
1587
                                                                 use_ext_microwave)
1588
        return
1589
1590
    def microwave_settings_updated(self, frequency, power, use_ext_microwave):
1591
        """
1592
1593
        @param frequency:
1594
        @param power:
1595
        @param use_ext_microwave:
1596
        @return:
1597
        """
1598
        # block signals
1599
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(True)
1600
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(True)
1601
        self._pa.ext_control_use_mw_CheckBox.blockSignals(True)
1602
        # set widgets
1603
        self._pa.ext_control_mw_freq_DoubleSpinBox.setValue(frequency)
1604
        self._pa.ext_control_mw_power_DoubleSpinBox.setValue(power)
1605
        self._pa.ext_control_use_mw_CheckBox.setChecked(use_ext_microwave)
1606
        # set visibility
1607 View Code Duplication
        if use_ext_microwave:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1608
            self._pa.ext_control_mw_freq_Label.setEnabled(True)
1609
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
1610
            self._pa.ext_control_mw_power_Label.setEnabled(True)
1611
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
1612
1613
            self._pa.ext_control_mw_freq_Label.setVisible(True)
1614
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(True)
1615
            self._pa.ext_control_mw_power_Label.setVisible(True)
1616
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(True)
1617
        else:
1618
            self._pa.ext_control_mw_freq_Label.setEnabled(False)
1619
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
1620
            self._pa.ext_control_mw_power_Label.setEnabled(False)
1621
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
1622
1623
            self._pa.ext_control_mw_freq_Label.setVisible(False)
1624
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(False)
1625
            self._pa.ext_control_mw_power_Label.setVisible(False)
1626
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(False)
1627
        # unblock signals
1628
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(False)
1629
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(False)
1630
        self._pa.ext_control_use_mw_CheckBox.blockSignals(False)
1631
        return
1632
1633
    def microwave_running_updated(self, is_running):
1634
        """
1635
1636
        @return:
1637
        """
1638
        pass
1639
1640
    def pulse_generator_settings_changed(self):
1641
        """
1642
1643
        @return:
1644
        """
1645
        # FIXME: Properly implement amplitude and interleave
1646
        sample_rate_hz = self._pa.pulser_sample_freq_DSpinBox.value()
1647
        activation_config_name = self._pa.pulser_activation_config_ComboBox.currentText()
1648
        analogue_amplitude, dummy = self._pulsed_master_logic._measurement_logic._pulse_generator_device.get_analog_level()
1649
        interleave_on = self._pa.pulser_use_interleave_CheckBox.isChecked()
1650
        self._pulsed_master_logic.pulse_generator_settings_changed(sample_rate_hz,
1651
                                                                   activation_config_name,
1652
                                                                   analogue_amplitude,
1653
                                                                   interleave_on)
1654
        return
1655
1656
    def pulse_generator_settings_updated(self, sample_rate_hz, activation_config_name,
1657
                                         activation_config, analogue_amplitude, interleave_on):
1658
        """
1659
1660
        @param sample_rate_hz:
1661
        @param activation_config_name:
1662
        @param analogue_amplitude:
1663
        @param interleave_on:
1664
        @return:
1665
        """
1666
        # block signals
1667
        self._pa.pulser_sample_freq_DSpinBox.blockSignals(True)
1668
        self._pa.pulser_activation_config_ComboBox.blockSignals(True)
1669
        self._pa.pulser_activation_config_LineEdit.blockSignals(True)
1670
        self._pa.pulser_use_interleave_CheckBox.blockSignals(True)
1671
        # Set widgets
1672
        # FIXME: Properly implement amplitude and interleave
1673
        self._pa.pulser_sample_freq_DSpinBox.setValue(sample_rate_hz)
1674
        index = self._pa.pulser_activation_config_ComboBox.findText(activation_config_name)
1675
        self._pa.pulser_activation_config_ComboBox.setCurrentIndex(index)
1676
        config_display_str = ''
1677
        for channel in activation_config:
1678
            config_display_str += channel + ' | '
1679
        config_display_str = config_display_str[:-3]
1680
        self._pa.pulser_activation_config_LineEdit.setText(config_display_str)
1681
        self._pa.pulser_use_interleave_CheckBox.setChecked(interleave_on)
1682
        # unblock signals
1683
        self._pa.pulser_sample_freq_DSpinBox.blockSignals(False)
1684
        self._pa.pulser_activation_config_ComboBox.blockSignals(False)
1685
        self._pa.pulser_activation_config_LineEdit.blockSignals(False)
1686
        self._pa.pulser_use_interleave_CheckBox.blockSignals(False)
1687
        return
1688
1689
    def fast_counter_settings_changed(self):
1690
        """
1691
1692
        @return:
1693
        """
1694
        record_length_s = self._pa.ana_param_record_length_SpinBox.value()
1695
        bin_width_s = float(self._pa.ana_param_fc_bins_ComboBox.currentText())
1696
        self._pulsed_master_logic.fast_counter_settings_changed(bin_width_s, record_length_s)
1697
        return
1698
1699
    def fast_counter_settings_updated(self, bin_width_s, record_length_s):
1700
        """
1701
1702
        @param bin_width_s:
1703
        @param record_length_s:
1704
        @return:
1705
        """
1706
        # block signals
1707
        self._pa.ana_param_record_length_SpinBox.blockSignals(True)
1708
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(True)
1709
        # set widgets
1710
        self._pa.ana_param_record_length_SpinBox.setValue(record_length_s)
1711
        index = self._pa.ana_param_fc_bins_ComboBox.findText(str(bin_width_s))
1712
        self._pa.ana_param_fc_bins_ComboBox.setCurrentIndex(index)
1713
        # unblock signals
1714
        self._pa.ana_param_record_length_SpinBox.blockSignals(False)
1715
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(False)
1716
        return
1717
1718
    def measurement_sequence_settings_changed(self):
1719
        """
1720
1721
        @return:
1722
        """
1723
        laser_ignore_list = []
1724
        if self._pa.ana_param_ignore_first_CheckBox.isChecked():
1725
            laser_ignore_list.append(0)
1726
        if self._pa.ana_param_ignore_last_CheckBox.isChecked():
1727
            laser_ignore_list.append(-1)
1728
        alternating = self._pa.ana_param_alternating_CheckBox.isChecked()
1729
        num_of_lasers = self._pa.ana_param_num_laser_pulse_SpinBox.value()
1730
        xaxis_start = self._pa.ana_param_x_axis_start_ScienDSpinBox.value()
1731
        xaxis_incr = self._pa.ana_param_x_axis_inc_ScienDSpinBox.value()
1732
        laser_trigger_delay = self._as.ana_param_lasertrigger_delay_ScienDSpinBox.value()
1733
        # FIXME: properly implement sequence_length_s
1734
        sequence_length_s = self._pulsed_master_logic._measurement_logic.sequence_length_s
1735
        num_of_ticks = num_of_lasers - len(laser_ignore_list)
1736
        if alternating:
1737
            num_of_ticks //= 2
1738
        measurement_ticks = np.arange(xaxis_start,
1739
                                      xaxis_start + (xaxis_incr * num_of_ticks) - (xaxis_incr / 2),
1740
                                      xaxis_incr)
1741
1742
        self._pulsed_master_logic.measurement_sequence_settings_changed(measurement_ticks,
1743
                                                                        num_of_lasers,
1744
                                                                        sequence_length_s,
1745
                                                                        laser_ignore_list,
1746
                                                                        alternating,
1747
                                                                        laser_trigger_delay)
1748
        return
1749
1750
    def measurement_sequence_settings_updated(self, measurement_ticks, number_of_lasers,
1751
                                              sequence_length_s, laser_ignore_list, alternating,
1752
                                              laser_trigger_delay):
1753
        """
1754
1755
        @param measurement_ticks:
1756
        @param number_of_lasers:
1757
        @param sequence_length_s:
1758
        @param laser_ignore_list:
1759
        @param alternating:
1760
        @param laser_trigger_delay:
1761
        @return:
1762
        """
1763
        # block signals
1764
        self._pa.ana_param_ignore_first_CheckBox.blockSignals(True)
1765
        self._pa.ana_param_ignore_last_CheckBox.blockSignals(True)
1766
        self._pa.ana_param_alternating_CheckBox.blockSignals(True)
1767
        self._pa.ana_param_num_laser_pulse_SpinBox.blockSignals(True)
1768
        self._pa.ana_param_x_axis_start_ScienDSpinBox.blockSignals(True)
1769
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.blockSignals(True)
1770
        self._as.ana_param_lasertrigger_delay_ScienDSpinBox.blockSignals(True)
1771
        self._pe.laserpulses_ComboBox.blockSignals(True)
1772
        # set widgets
1773
        self._pa.ana_param_ignore_first_CheckBox.setChecked(0 in laser_ignore_list)
1774
        self._pa.ana_param_ignore_last_CheckBox.setChecked(-1 in laser_ignore_list)
1775
        self._pa.ana_param_alternating_CheckBox.setChecked(alternating)
1776
        self._pa.ana_param_num_laser_pulse_SpinBox.setValue(number_of_lasers)
1777
        self._as.ana_param_lasertrigger_delay_ScienDSpinBox.setValue(laser_trigger_delay)
1778
        self._pa.ana_param_x_axis_start_ScienDSpinBox.setValue(measurement_ticks[0])
1779
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.setValue(
1780
            (measurement_ticks[-1] - measurement_ticks[0]) / (len(measurement_ticks)-1))
1781
        self._pe.laserpulses_ComboBox.addItems([str(i) for i in range(number_of_lasers+1)])
1782
        # change plots accordingly
1783
        if alternating:
1784
            if self.signal_image2 not in self._pa.pulse_analysis_PlotWidget.items():
1785
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image2)
1786
            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():
1787
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
1788
            if self.measuring_error_image2 not in self._pe.measuring_error_PlotWidget.items():
1789
                self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image2)
1790
        else:
1791
            if self.signal_image2 in self._pa.pulse_analysis_PlotWidget.items():
1792
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image2)
1793
            if self.signal_image_error_bars2 in self._pa.pulse_analysis_PlotWidget.items():
1794
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars2)
1795
            if self.measuring_error_image2 in self._pe.measuring_error_PlotWidget.items():
1796
                self._pe.measuring_error_PlotWidget.removeItem(self.measuring_error_image2)
1797
        # unblock signals
1798
        self._pa.ana_param_ignore_first_CheckBox.blockSignals(False)
1799
        self._pa.ana_param_ignore_last_CheckBox.blockSignals(False)
1800
        self._pa.ana_param_alternating_CheckBox.blockSignals(False)
1801
        self._pa.ana_param_num_laser_pulse_SpinBox.blockSignals(False)
1802
        self._pa.ana_param_x_axis_start_ScienDSpinBox.blockSignals(False)
1803
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.blockSignals(False)
1804
        self._as.ana_param_lasertrigger_delay_ScienDSpinBox.blockSignals(False)
1805
        self._pe.laserpulses_ComboBox.blockSignals(False)
1806
        return
1807
1808
    def toggle_laser_xaxis_editor(self):
1809
        """ Shows or hides input widgets which are necessary if the x axis id defined or not."""
1810
        if self._pa.ana_param_x_axis_defined_CheckBox.isChecked():
1811
            self._pa.ana_param_x_axis_start_Label.setVisible(True)
1812
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setVisible(True)
1813
            self._pa.ana_param_x_axis_inc_Label.setVisible(True)
1814
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setVisible(True)
1815
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(True)
1816
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(True)
1817
        else:
1818
            self._pa.ana_param_x_axis_start_Label.setVisible(False)
1819
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setVisible(False)
1820
            self._pa.ana_param_x_axis_inc_Label.setVisible(False)
1821
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setVisible(False)
1822
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(False)
1823
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(False)
1824
1825
        if self._pa.ana_param_laserpulse_defined_CheckBox.isChecked():
1826
            self._pa.ana_param_num_laserpulses_Label.setVisible(True)
1827
            self._pa.ana_param_num_laser_pulse_SpinBox.setVisible(True)
1828
            self._pa.ana_param_record_length_Label.setVisible(True)
1829
            self._pa.ana_param_record_length_SpinBox.setVisible(True)
1830
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(True)
1831
            self._pa.ana_param_record_length_SpinBox.setEnabled(True)
1832
        else:
1833
            self._pa.ana_param_num_laserpulses_Label.setVisible(False)
1834
            self._pa.ana_param_num_laser_pulse_SpinBox.setVisible(False)
1835
            self._pa.ana_param_record_length_Label.setVisible(False)
1836
            self._pa.ana_param_record_length_SpinBox.setVisible(False)
1837
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(False)
1838
            self._pa.ana_param_record_length_SpinBox.setEnabled(False)
1839
        return
1840
1841
    def toggle_error_bars(self):
1842
        """
1843
1844
        @return:
1845
        """
1846
        show_bars = self._pa.ana_param_errorbars_CheckBox.isChecked()
1847
        is_alternating = self.signal_image2 in self._pa.pulse_analysis_PlotWidget.items()
1848
        if show_bars:
1849
            if self.signal_image_error_bars not in self._pa.pulse_analysis_PlotWidget.items():
1850
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars)
1851
            if is_alternating and self.signal_image_error_bars2 not in self._pa.pulse_analysis_PlotWidget.items():
1852
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
1853
        else:
1854
            if self.signal_image_error_bars in self._pa.pulse_analysis_PlotWidget.items():
1855
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars)
1856
            if is_alternating and self.signal_image_error_bars2 in self._pa.pulse_analysis_PlotWidget.items():
1857
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars2)
1858
        return
1859
1860
    # def change_second_plot(self):
1861
    #     """ This method handles the second plot"""
1862
    #     if self._mw.second_plot_ComboBox.currentText()=='None':
1863
    #         self._mw.second_plot_GroupBox.setVisible(False)
1864
    #     else:
1865
    #         self._mw.second_plot_GroupBox.setVisible(True)
1866
    #
1867
    #         # Here FFT is seperated from the other option. The reason for that
1868
    #         # is preventing of code doubling
1869
    #         if self._mw.second_plot_ComboBox.currentText() == 'FFT':
1870
    #             fft_x, fft_y = self._pulsed_meas_logic.compute_fft()
1871
    #             self.second_plot_image.setData(fft_x, fft_y)
1872
    #             self._mw.pulse_analysis_second_PlotWidget.setLogMode(x=False, y=False)
1873
    #
1874
    #             self._mw.pulse_analysis_second_PlotWidget.setLabel(axis='bottom',
1875
    #                                                                text=self._as.ana_param_second_plot_x_axis_name_LineEdit.text(),
1876
    #                                                                units=self._as.ana_param_second_plot_x_axis_unit_LineEdit.text())
1877
    #             self._mw.pulse_analysis_second_PlotWidget.setLabel(axis='left',
1878
    #                                                                text=self._as.ana_param_second_plot_y_axis_name_LineEdit.text(),
1879
    #                                                                units=self._as.ana_param_second_plot_y_axis_unit_LineEdit.text())
1880
    #
1881
    #         else:
1882
    #             #FIXME: Is not working when there is a 0 in the values, therefore ignoring the first measurment point
1883
    #             self.second_plot_image.setData(self._pulsed_meas_logic.signal_plot_x[1:], self._pulsed_meas_logic.signal_plot_y[1:])
1884
    #
1885
    #             if self._as.ana_param_second_plot_x_axis_name_LineEdit.text()== '':
1886
    #                 self._mw.pulse_analysis_second_PlotWidget.setLabel(axis='left',
1887
    #                                                                    text=self._as.ana_param_y_axis_name_LineEdit.text(),
1888
    #                                                                    units=self._as.ana_param_y_axis_unit_LineEdit.text())
1889
    #                 self._mw.pulse_analysis_second_PlotWidget.setLabel(axis='bottom',
1890
    #                                                                    text=self._as.ana_param_x_axis_name_LineEdit.text(),
1891
    #                                                                    units=self._as.ana_param_x_axis_unit_LineEdit.text())
1892
    #
1893
    #             else:
1894
    #                 self._mw.pulse_analysis_second_PlotWidget.setLabel(axis='bottom',
1895
    #                                                                    text=self._as.ana_param_second_plot_x_axis_name_LineEdit.text(),
1896
    #                                                                    units=self._as.ana_param_second_plot_x_axis_unit_LineEdit.text())
1897
    #                 self._mw.pulse_analysis_second_PlotWidget.setLabel(axis='left',
1898
    #                                                                    text=self._as.ana_param_second_plot_y_axis_name_LineEdit.text(),
1899
    #                                                                    units=self._as.ana_param_second_plot_y_axis_unit_LineEdit.text())
1900
    #
1901
    #             if self._mw.second_plot_ComboBox.currentText() == 'unchanged data':
1902
    #                 self._mw.pulse_analysis_second_PlotWidget.setLogMode(x=False, y=False)
1903
    #
1904
    #             elif self._mw.second_plot_ComboBox.currentText() == 'Log(x)':
1905
    #                 self._mw.pulse_analysis_second_PlotWidget.setLogMode(x=True, y=False)
1906
    #
1907
    #             elif self._mw.second_plot_ComboBox.currentText() == 'Log(y)':
1908
    #                 self._mw.pulse_analysis_second_PlotWidget.setLogMode(x=False,y=True)
1909
    #
1910
    #             elif self._mw.second_plot_ComboBox.currentText() == 'Log(x)&Log(y)':
1911
    #                 self._mw.pulse_analysis_second_PlotWidget.setLogMode(x=True, y=True)
1912
1913
    def measurement_timer_changed(self):
1914
        """ This method handles the analysis timing"""
1915
        timer_interval = self._pa.time_param_ana_periode_DoubleSpinBox.value()
1916
        self._pulsed_master_logic.analysis_interval_changed(timer_interval)
1917
        return
1918
1919
    def measurement_timer_updated(self, timer_interval_s):
1920
        """
1921
1922
        @param timer_interval_s:
1923
        @return:
1924
        """
1925
        # block signals
1926
        self._pa.time_param_ana_periode_DoubleSpinBox.blockSignals(True)
1927
        # set widget
1928
        self._pa.time_param_ana_periode_DoubleSpinBox.setValue(timer_interval_s)
1929
        # unblock signals
1930
        self._pa.time_param_ana_periode_DoubleSpinBox.blockSignals(False)
1931
        return
1932
1933
    def conv_std_dev_changed(self):
1934
        """
1935
        Uodate new value of standard deviation of gaussian filter
1936
        """
1937
        # block signals
1938
        self._pe.slider_conv_std_dev.blockSignals(True)
1939
        # set widgets
1940
        std_dev = self._pe.conv_std_dev.value()
1941
        self._pe.slider_conv_std_dev.setValue(std_dev)
1942
        # unblock signals
1943
        self._pe.slider_conv_std_dev.blockSignals(False)
1944
1945
        self._pulsed_master_logic.analysis_method_changed(std_dev)
1946
        return
1947
1948
    def slider_conv_std_dev_changed(self):
1949
        """
1950
        Uodate new value of standard deviation of gaussian filter
1951
        from slider
1952
        """
1953
        # block signals
1954
        self._pe.conv_std_dev.blockSignals(True)
1955
        # set widgets
1956
        std_dev = self._pe.slider_conv_std_dev.value()
1957
        self._pe.conv_std_dev.setValue(std_dev)
1958
        # unblock signals
1959
        self._pe.conv_std_dev.blockSignals(False)
1960
1961
        self._pulsed_master_logic.analysis_method_changed(std_dev)
1962
        return
1963
1964
    def analysis_method_updated(self, gaussfilt_std_dev):
1965
        """
1966
1967
        @param gaussfilt_std_dev:
1968
        @return:
1969
        """
1970
        # block signals
1971
        self._pe.slider_conv_std_dev.blockSignals(True)
1972
        self._pe.conv_std_dev.blockSignals(True)
1973
        # set widgets
1974
        self._pe.slider_conv_std_dev.setValue(gaussfilt_std_dev)
1975
        self._pe.conv_std_dev.setValue(gaussfilt_std_dev)
1976
        # unblock signals
1977
        self._pe.slider_conv_std_dev.blockSignals(False)
1978
        self._pe.conv_std_dev.blockSignals(False)
1979
        return
1980
1981
    def analysis_windows_changed(self):
1982
        """
1983
1984
        @return:
1985
        """
1986
        # block signals
1987
        self.sig_start_line.blockSignals(True)
1988
        self.sig_end_line.blockSignals(True)
1989
        self.ref_start_line.blockSignals(True)
1990
        self.ref_end_line.blockSignals(True)
1991
        # get data
1992
        sig_start = self._pe.extract_param_ana_window_start_SpinBox.value()
1993
        sig_length = self._pe.extract_param_ana_window_width_SpinBox.value()
1994
        ref_start = self._pe.extract_param_ref_window_start_SpinBox.value()
1995
        ref_length = self._pe.extract_param_ref_window_width_SpinBox.value()
1996
        # update plots
1997
        self.sig_start_line.setValue(sig_start)
1998
        self.sig_end_line.setValue(sig_start + sig_length)
1999
        self.ref_start_line.setValue(ref_start)
2000
        self.ref_end_line.setValue(ref_start + ref_length)
2001
        # unblock signals
2002
        self.sig_start_line.blockSignals(False)
2003
        self.sig_end_line.blockSignals(False)
2004
        self.ref_start_line.blockSignals(False)
2005
        self.ref_end_line.blockSignals(False)
2006
2007
        self._pulsed_master_logic.analysis_windows_changed(sig_start, sig_length, ref_start,
2008
                                                           ref_length)
2009
        return
2010
2011
    def analysis_windows_line_changed(self):
2012
        """
2013
2014
        @return:
2015
        """
2016
        # block signals
2017
        self._pe.extract_param_ana_window_start_SpinBox.blockSignals(True)
2018
        self._pe.extract_param_ana_window_width_SpinBox.blockSignals(True)
2019
        self._pe.extract_param_ref_window_start_SpinBox.blockSignals(True)
2020
        self._pe.extract_param_ref_window_width_SpinBox.blockSignals(True)
2021
        # get data
2022
        sig_start = self.sig_start_line.value()
2023
        sig_length = self.sig_end_line.value() - sig_start
2024
        ref_start = self.ref_start_line.value()
2025
        ref_length = self.ref_end_line.value() - ref_start
2026
        # set widgets
2027
        self._pe.extract_param_ana_window_start_SpinBox.setValue(sig_start)
2028
        self._pe.extract_param_ana_window_width_SpinBox.setValue(sig_length)
2029
        self._pe.extract_param_ref_window_start_SpinBox.setValue(ref_start)
2030
        self._pe.extract_param_ref_window_width_SpinBox.setValue(ref_length)
2031
        # unblock signals
2032
        self._pe.extract_param_ana_window_start_SpinBox.blockSignals(False)
2033
        self._pe.extract_param_ana_window_width_SpinBox.blockSignals(False)
2034
        self._pe.extract_param_ref_window_start_SpinBox.blockSignals(False)
2035
        self._pe.extract_param_ref_window_width_SpinBox.blockSignals(False)
2036
        return
2037
2038
    def analysis_windows_updated(self, sig_start, sig_length, ref_start, ref_length):
2039
        """
2040
2041
        @param sig_start:
2042
        @param sig_length:
2043
        @param ref_start:
2044
        @param ref_length:
2045
        @return:
2046
        """
2047
        # block signals
2048
        self._pe.extract_param_ana_window_start_SpinBox.blockSignals(True)
2049
        self._pe.extract_param_ana_window_width_SpinBox.blockSignals(True)
2050
        self._pe.extract_param_ref_window_start_SpinBox.blockSignals(True)
2051
        self._pe.extract_param_ref_window_width_SpinBox.blockSignals(True)
2052
        # set widgets
2053
        self._pe.extract_param_ana_window_start_SpinBox.setValue(sig_start)
2054
        self._pe.extract_param_ana_window_width_SpinBox.setValue(sig_length)
2055
        self._pe.extract_param_ref_window_start_SpinBox.setValue(ref_start)
2056
        self._pe.extract_param_ref_window_width_SpinBox.setValue(ref_length)
2057
        # update plots
2058
        self.sig_start_line.setValue(sig_start)
2059
        self.sig_end_line.setValue(sig_start + sig_length)
2060
        self.ref_start_line.setValue(ref_start)
2061
        self.ref_end_line.setValue(ref_start + ref_length)
2062
        # unblock signals
2063
        self._pe.extract_param_ana_window_start_SpinBox.blockSignals(False)
2064
        self._pe.extract_param_ana_window_width_SpinBox.blockSignals(False)
2065
        self._pe.extract_param_ref_window_start_SpinBox.blockSignals(False)
2066
        self._pe.extract_param_ref_window_width_SpinBox.blockSignals(False)
2067
        return
2068
2069
    def laser_to_show_changed(self):
2070
        """
2071
2072
        @return:
2073
        """
2074
        current_laser = self._pe.laserpulses_ComboBox.currentText()
2075
        show_raw_data = self._pe.laserpulses_display_raw_CheckBox.isChecked()
2076
        if current_laser == 'sum':
2077
            show_laser_index = 0
2078
        else:
2079
            show_laser_index = int(current_laser)
2080
2081
        self._pulsed_master_logic.laser_to_show_changed(show_laser_index, show_raw_data)
2082
        return
2083
2084
    def laser_to_show_updated(self, laser_index, show_raw_data):
2085
        """
2086
2087
        @param laser_index:
2088
        @param show_raw_data:
2089
        @return:
2090
        """
2091
        # block signals
2092
        self._pe.laserpulses_ComboBox.blockSignals(True)
2093
        self._pe.laserpulses_display_raw_CheckBox.blockSignals(True)
2094
        # set widgets
2095
        self._pe.laserpulses_ComboBox.setCurrentIndex(laser_index)
2096
        self._pe.laserpulses_display_raw_CheckBox.setChecked(show_raw_data)
2097
        # unblock signals
2098
        self._pe.laserpulses_ComboBox.blockSignals(False)
2099
        self._pe.laserpulses_display_raw_CheckBox.blockSignals(False)
2100
        return
2101
2102
    def laser_data_updated(self, x_data, y_data):
2103
        """
2104
2105
        @param x_data:
2106
        @param y_data:
2107
        @return:
2108
        """
2109
        self.lasertrace_image.setData(x=x_data, y=y_data)
2110
        return
2111
2112
2113
2114
    ###########################################################################
2115
    ###         Methods related to the Tab 'Sequence Generator':            ###
2116
    ###########################################################################
2117
    def pulser_on_off_clicked(self, checked):
2118
        """ Manually switch the pulser output on/off. """
2119
        checked = self._mw.pulser_on_off_PushButton.isChecked()
2120
        if checked:
2121
            self._mw.pulser_on_off_PushButton.setText('Pulser OFF')
2122
            self._pulsed_master_logic.toggle_pulse_generator(True)
2123
        else:
2124
            self._mw.pulser_on_off_PushButton.setText('Pulser ON')
2125
            self._pulsed_master_logic.toggle_pulse_generator(False)
2126
        return
2127
2128
    def pulser_running_updated(self, is_running):
2129
        """
2130
2131
        @param is_running:
2132
        @return:
2133
        """
2134
        # block signals
2135
        self._mw.pulser_on_off_PushButton.blockSignals(True)
2136
        # set widgets
2137
        if is_running:
2138
            self._mw.pulser_on_off_PushButton.setText('Pulser OFF')
2139
            if not self._mw.pulser_on_off_PushButton.isChecked():
2140
                self._mw.pulser_on_off_PushButton.toggle()
2141
        else:
2142
            self._mw.pulser_on_off_PushButton.setText('Pulser ON')
2143
            if self._mw.pulser_on_off_PushButton.isChecked():
2144
                self._mw.pulser_on_off_PushButton.toggle()
2145
        # unblock signals
2146
        self._mw.pulser_on_off_PushButton.blockSignals(False)
2147
        return
2148
2149
    def clear_pulser_clicked(self):
2150
        """ Delete all loaded files in the device's current memory. """
2151
        self._pulsed_master_logic.clear_pulse_generator()
2152
        return
2153
2154
    def upload_ensemble_clicked(self):
2155
        """
2156
2157
        @return:
2158
        """
2159
        # Get the ensemble name from the ComboBox
2160
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
2161
        # Upload the ensemble via logic module
2162
        self._pulsed_master_logic.upload_asset(ensemble_name)
2163
        # disable button
2164
        self._pg.upload_ensemble_PushButton.setEnabled(False)
2165
        self._pg.load_ensemble_PushButton.setEnabled(False)
2166
        return
2167
2168
    # def upload_sequence_clicked(self):
2169
    #     """
2170
    #
2171
    #     @return:
2172
    #     """
2173
    #     # Get the sequence name from the ComboBox
2174
    #     seq_name = self._pg.gen_sequence_ComboBox.currentText()
2175
    #     # Upload the asset via logic module
2176
    #     self._pulsed_master_logic.upload_asset(seq_name)
2177
    #     # disable button
2178
    #     self._pg.upload_sequence_PushButton.setEnabled(False)
2179
    #     self._pg.load_sequence_PushButton.setEnabled(False)
2180
    #     return
2181
2182
    def update_uploaded_assets(self, asset_names_list):
2183
        """
2184
2185
        @param asset_names_list:
2186
        @return:
2187
        """
2188
        # enable buttons
2189
        # self._pg.upload_sequence_PushButton.setEnabled(True)
2190
        self._pg.upload_ensemble_PushButton.setEnabled(True)
2191
        self._pg.load_ensemble_PushButton.setEnabled(True)
2192
        # self._pg.load_sequence_PushButton.setEnabled(True)
2193
        return
2194
2195
    def load_ensemble_clicked(self):
2196
        """
2197
2198
        @return:
2199
        """
2200
        # Get the asset name to be uploaded from the ComboBox
2201
        asset_name = self._pg.gen_ensemble_ComboBox.currentText()
2202
        # Load asset into channles via logic module
2203
        self._pulsed_master_logic.load_asset_into_channels(asset_name, {}, False)
2204
        # disable button
2205
        self._pg.load_ensemble_PushButton.setEnabled(False)
2206
        return
2207
2208
    # def load_sequence_clicked(self):
2209
    #     """
2210
    #
2211
    #     @return:
2212
    #     """
2213
    #     # Get the asset name to be uploaded from the ComboBox
2214
    #     asset_name = self._pg.gen_sequence_ComboBox.currentText()
2215
    #     # Load asset into channles via logic module
2216
    #     self._pulsed_master_logic.load_asset_into_channels(asset_name, {}, False)
2217
    #     # disable button
2218
    #     self._pg.load_sequence_PushButton.setEnabled(False)
2219
    #     return
2220
2221
    def update_loaded_asset(self, asset_name, asset_type):
2222
        """ Check the current loaded asset from the logic and update the display. """
2223
        label = self._mw.current_loaded_asset_Label
2224
        if asset_name is None:
2225
            label.setText(asset_type)
2226
        elif asset_type == 'PulseBlockEnsemble' or asset_type == 'PulseSequence':
2227
            label.setText('  {0} ({1})'.format(asset_name, asset_type))
2228
        else:
2229
            label.setText('  Unknown asset type')
2230
        # enable buttons
2231
        if asset_type == 'PulseBlockEnsemble':
2232
            self._pg.load_ensemble_PushButton.setEnabled(True)
2233
        elif asset_type == 'PulseSequence':
2234
            self._pg.load_sequence_PushButton.setEnabled(True)
2235
        return
2236
2237
2238
    # def save_plots(self):
2239
    #     """ Save plot from analysis graph as a picture. """
2240
    #     timestamp = datetime.datetime.now()
2241
    #     filetag = self._mw.save_tag_LineEdit.text()
2242
    #     filepath = self._save_logic.get_path_for_module(module_name='PulsedMeasurement')
2243
    #     if len(filetag) > 0:
2244
    #         filename = os.path.join(filepath, '{}_{}_pulsed'.format(timestamp.strftime('%Y%m%d-%H%M-%S'), filetag))
2245
    #     else:
2246
    #         filename = os.path.join(filepath, '{}_pulsed'.format(timestamp.strftime('%Y%m%d-%H%M-%S')))
2247
    #
2248
    #     # print(type(self._mw.second_plot_ComboBox.currentText()), self._mw.second_plot_ComboBox.currentText())
2249
    #     # pulse plot
2250
    #     # exporter = pg.exporters.SVGExporter(self._pa.pulse_analysis_PlotWidget.plotItem.scene())
2251
    #     # exporter.export(filename+'.svg')
2252
    #     #
2253
    #     # # auxiliary plot
2254
    #     # if 'None' not in self._mw.second_plot_ComboBox.currentText():
2255
    #     #     exporter_aux = pg.exporters.SVGExporter(self._mw.pulse_analysis_second_PlotWidget.plotItem.scene())
2256
    #     #     exporter_aux.export(filename + '_aux' + '.svg')
2257
    #
2258
    #     self._pulsed_meas_logic._save_data(filetag, timestamp)
2259
2260
2261
2262