Completed
Pull Request — master (#384)
by
unknown
01:25
created

PulsedMeasurementGui._create_pm_global_params()   F

Complexity

Conditions 20

Size

Total Lines 89

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
dl 0
loc 89
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like PulsedMeasurementGui._create_pm_global_params() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
3
"""
4
This file contains the QuDi main GUI for pulsed measurements.
5
6
QuDi is free software: you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation, either version 3 of the License, or
9
(at your option) any later version.
10
11
QuDi is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
16
You should have received a copy of the GNU General Public License
17
along with QuDi. If not, see <http://www.gnu.org/licenses/>.
18
19
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the
20
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/>
21
"""
22
23
import numpy as np
24
import os
25
import pyqtgraph as pg
26
import datetime
27
28
from core.module import Connector, StatusVar
29
from core.util import units
30
from gui.colordefs import QudiPalettePale as palette
31
from gui.fitsettings import FitSettingsDialog
32
from gui.guibase import GUIBase
33
from qtpy import QtCore, QtWidgets, uic
34
from qtwidgets.scientific_spinbox import ScienDSpinBox, ScienSpinBox
35
36
37
# TODO: Display the Pulse graphically (similar to AWG application)
38
39
40
class PulsedMeasurementMainWindow(QtWidgets.QMainWindow):
41
    def __init__(self):
42
        # Get the path to the *.ui file
43
        this_dir = os.path.dirname(__file__)
44
        ui_file = os.path.join(this_dir, 'ui_pulsed_maingui.ui')
45
46
        # Load it
47
        super(PulsedMeasurementMainWindow, self).__init__()
48
49
        uic.loadUi(ui_file, self)
50
        self.show()
51
52
53
class PulseAnalysisTab(QtWidgets.QWidget):
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_pulse_analysis.ui')
58
        # Load it
59
        super().__init__()
60
        uic.loadUi(ui_file, self)
61
62
63
class PulseGeneratorTab(QtWidgets.QWidget):
64
    def __init__(self):
65
        # Get the path to the *.ui file
66
        this_dir = os.path.dirname(__file__)
67
        ui_file = os.path.join(this_dir, 'ui_pulse_editor.ui')
68
        # Load it
69
        super().__init__()
70
        uic.loadUi(ui_file, self)
71
72
73
class SequenceGeneratorTab(QtWidgets.QWidget):
74
    def __init__(self):
75
        # Get the path to the *.ui file
76
        this_dir = os.path.dirname(__file__)
77
        ui_file = os.path.join(this_dir, 'ui_sequence_editor.ui')
78
        # Load it
79
        super().__init__()
80
        uic.loadUi(ui_file, self)
81
82
83
class PulseExtractionTab(QtWidgets.QWidget):
84
    def __init__(self):
85
        # Get the path to the *.ui file
86
        this_dir = os.path.dirname(__file__)
87
        ui_file = os.path.join(this_dir, 'ui_pulse_extraction.ui')
88
        # Load it
89
        super().__init__()
90
        uic.loadUi(ui_file, self)
91
92
93
class AnalysisSettingDialog(QtWidgets.QDialog):
94
    def __init__(self):
95
        # Get the path to the *.ui file
96
        this_dir = os.path.dirname(__file__)
97
        ui_file = os.path.join(this_dir, 'ui_pulsed_main_gui_settings_analysis.ui')
98
99
        # Load it
100
        super().__init__()
101
102
        uic.loadUi(ui_file, self)
103
104
105
class PredefinedMethodsTab(QtWidgets.QWidget):
106
    def __init__(self):
107
        # Get the path to the *.ui file
108
        this_dir = os.path.dirname(__file__)
109
        ui_file = os.path.join(this_dir, 'ui_predefined_methods.ui')
110
111
        # Load it
112
        super().__init__()
113
114
        uic.loadUi(ui_file, self)
115
116
117
class PredefinedMethodsConfigDialog(QtWidgets.QDialog):
118
    def __init__(self):
119
        # Get the path to the *.ui file
120
        this_dir = os.path.dirname(__file__)
121
        ui_file = os.path.join(this_dir, 'ui_predefined_methods_config.ui')
122
123
        # Load it
124
        super().__init__()
125
126
        uic.loadUi(ui_file, self)
127
128
129
class PulsedMeasurementGui(GUIBase):
130
    """ This is the main GUI Class for pulsed measurements. """
131
132
    _modclass = 'PulsedMeasurementGui'
133
    _modtype = 'gui'
134
135
    ## declare connectors
136
    pulsedmasterlogic = Connector(interface='PulsedMasterLogic')
137
138
    # status var
139
    _ana_param_x_axis_name_text = StatusVar('ana_param_x_axis_name_LineEdit', 'Tau')
140
    _ana_param_x_axis_unit_text = StatusVar('ana_param_x_axis_unit_LineEdit', 's')
141
    _ana_param_y_axis_name_text = StatusVar('ana_param_y_axis_name_LineEdit', 'Normalized Signal')
142
    _ana_param_y_axis_unit_text = StatusVar('ana_param_y_axis_unit_LineEdit', '')
143
    _ana_param_second_plot_x_axis_name_text = StatusVar('ana_param_second_plot_x_axis_name_LineEdit', 'Frequency')
144
    _ana_param_second_plot_x_axis_unit_text = StatusVar('ana_param_second_plot_x_axis_unit_LineEdit', 'Hz')
145
    _ana_param_second_plot_y_axis_name_text = StatusVar('ana_param_second_plot_y_axis_name_LineEdit', 'Ft Signal')
146
    _ana_param_second_plot_y_axis_unit_text = StatusVar('ana_param_second_plot_y_axis_unit_LineEdit', '')
147
148
    _show_raw_data = StatusVar(default=False)
149
    _show_laser_index = StatusVar(default=0)
150
    _ana_param_errorbars = StatusVar('ana_param_errorbars_CheckBox', False)
151
    _predefined_methods_to_show = StatusVar('predefined_methods_to_show', [])
152
153
    def __init__(self, config, **kwargs):
154
        super().__init__(config=config, **kwargs)
155
156
    def on_activate(self):
157
        """ Initialize, connect and configure the pulsed measurement GUI.
158
159
        Establish general connectivity and activate the different tabs of the
160
        GUI.
161
        """
162
        self._mw = PulsedMeasurementMainWindow()
163
        self._pa = PulseAnalysisTab()
164
        self._pg = PulseGeneratorTab()
165
        self._pe = PulseExtractionTab()
166
        self._pm = PredefinedMethodsTab()
167
        self._sg = SequenceGeneratorTab()
168
        self._as = AnalysisSettingDialog()
169
        self._pm_cfg = PredefinedMethodsConfigDialog()
170
171
        self._mw.tabWidget.addTab(self._pa, 'Analysis')
172
        self._mw.tabWidget.addTab(self._pe, 'Pulse Extraction')
173
        self._mw.tabWidget.addTab(self._pg, 'Pulse Generator')
174
        self._mw.tabWidget.addTab(self._sg, 'Sequence Generator')
175
        self._mw.tabWidget.addTab(self._pm, 'Predefined Methods')
176
177
        self._activate_main_window_ui()
178
        self._activate_extraction_ui()
179
        self._activate_analysis_ui()
180
        self._activate_pulse_generator_ui()
181
        self._activate_predefined_methods_ui()
182
        self._activate_sequence_generator_ui()
183
        self._activate_analysis_settings_ui()
184
        self._activate_predefined_methods_settings_ui()
185
186
        self._connect_main_window_signals()
187
        self._connect_analysis_tab_signals()
188
        self._connect_extraction_tab_signals()
189
        self._connect_pulse_generator_tab_signals()
190
        self._connect_predefined_methods_tab_signals()
191
        self._connect_sequence_generator_tab_signals()
192
        self._connect_dialog_signals()
193
        self._connect_logic_signals()
194
195
        self.show()
196
        return
197
198
    def on_deactivate(self):
199
        """ Undo the Definition, configuration and initialisation of the pulsed
200
            measurement GUI.
201
202
        This deactivation disconnects all the graphic modules, which were
203
        connected in the initUI method.
204
        """
205
        self._deactivate_predefined_methods_settings_ui()
206
        self._deactivate_analysis_settings_ui()
207
        self._deactivate_sequence_generator_ui()
208
        self._deactivate_predefined_methods_ui()
209
        self._deactivate_pulse_generator_ui()
210
        self._deactivate_analysis_ui()
211
        self._deactivate_extraction_ui()
212
        self._deactivate_main_window_ui()
213
214
        self._disconnect_main_window_signals()
215
        self._disconnect_analysis_tab_signals()
216
        self._disconnect_extraction_tab_signals()
217
        self._disconnect_pulse_generator_tab_signals()
218
        self._disconnect_predefined_methods_tab_signals()
219
        self._disconnect_sequence_generator_tab_signals()
220
        self._disconnect_dialog_signals()
221
        self._disconnect_logic_signals()
222
223
        self._mw.close()
224
        return
225
226
    def show(self):
227
        """Make main window visible and put it above all other windows. """
228
        QtWidgets.QMainWindow.show(self._mw)
229
        self._mw.activateWindow()
230
        self._mw.raise_()
231
        return
232
233
    ###########################################################################
234
    #                          Signal (dis-)connections                       #
235
    ###########################################################################
236 View Code Duplication
    def _connect_main_window_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
237
        # Connect main window actions and toolbar
238
        self._mw.action_Predefined_Methods_Config.triggered.connect(
239
            self.show_predefined_methods_config)
240
        self._mw.pulser_on_off_PushButton.clicked.connect(self.pulser_on_off_clicked)
241
        self._mw.clear_device_PushButton.clicked.connect(self.clear_pulser_clicked)
242
        self._mw.action_run_stop.triggered.connect(self.measurement_run_stop_clicked)
243
        self._mw.action_continue_pause.triggered.connect(self.measurement_continue_pause_clicked)
244
        self._mw.action_pull_data.triggered.connect(self.pull_data_clicked)
245
        self._mw.action_save.triggered.connect(self.save_clicked)
246
        self._mw.actionSave.triggered.connect(self.save_clicked)
247
        self._mw.action_Settings_Analysis.triggered.connect(self.show_analysis_settings)
248
        self._mw.action_FitSettings.triggered.connect(self._fsd.show)
249
        return
250
251 View Code Duplication
    def _connect_dialog_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
252
        # Connect signals used in predefined methods config dialog
253
        self._pm_cfg.accepted.connect(self.apply_predefined_methods_config)
254
        self._pm_cfg.rejected.connect(self.keep_former_predefined_methods_config)
255
        self._pm_cfg.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.apply_predefined_methods_config)
256
257
        # Connect signals used in analysis settings dialog
258
        self._as.accepted.connect(self.update_analysis_settings)
259
        self._as.rejected.connect(self.keep_former_analysis_settings)
260
        self._as.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.update_analysis_settings)
261
262
        # Connect signals used in fit settings dialog
263
        self._fsd.sigFitsUpdated.connect(self._pa.fit_param_fit_func_ComboBox.setFitFunctions)
264
        return
265
266 View Code Duplication
    def _connect_pulse_generator_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
267
        # Connect Block/Ensemble editor tab signals
268
        self._pg.gen_laserchannel_ComboBox.currentIndexChanged.connect(self.generation_parameters_changed)
269
        self._pg.gen_syncchannel_ComboBox.currentIndexChanged.connect(self.generation_parameters_changed)
270
        self._pg.gen_gatechannel_ComboBox.currentIndexChanged.connect(self.generation_parameters_changed)
271
272
        self._pg.sample_ensemble_PushButton.clicked.connect(self.sample_ensemble_clicked)
273
        self._pg.samplo_ensemble_PushButton.clicked.connect(self.samplo_ensemble_clicked)
274
        self._pg.load_ensemble_PushButton.clicked.connect(self.load_ensemble_clicked)
275
276
        self._pg.block_add_last_PushButton.clicked.connect(self.block_add_last_clicked)
277
        self._pg.block_del_last_PushButton.clicked.connect(self.block_del_last_clicked)
278
        self._pg.block_add_sel_PushButton.clicked.connect(self.block_add_sel_clicked)
279
        self._pg.block_del_sel_PushButton.clicked.connect(self.block_del_sel_clicked)
280
        self._pg.block_clear_PushButton.clicked.connect(self.block_clear_clicked)
281
        self._pg.organizer_add_last_PushButton.clicked.connect(self.organizer_add_last_clicked)
282
        self._pg.organizer_del_last_PushButton.clicked.connect(self.organizer_del_last_clicked)
283
        self._pg.organizer_add_sel_PushButton.clicked.connect(self.organizer_add_sel_clicked)
284
        self._pg.organizer_del_sel_PushButton.clicked.connect(self.organizer_del_sel_clicked)
285
        self._pg.organizer_clear_PushButton.clicked.connect(self.organizer_clear_clicked)
286
        self._pg.curr_block_generate_PushButton.clicked.connect(self.editor_generate_block_clicked)
287
        self._pg.curr_block_del_PushButton.clicked.connect(self.editor_delete_block_clicked)
288
        self._pg.curr_block_load_PushButton.clicked.connect(self.editor_load_block_clicked)
289
        self._pg.curr_ensemble_generate_PushButton.clicked.connect(self.editor_generate_ensemble_clicked)
290
        self._pg.curr_ensemble_del_PushButton.clicked.connect(self.editor_delete_ensemble_clicked)
291
        self._pg.curr_ensemble_load_PushButton.clicked.connect(self.editor_load_ensemble_clicked)
292
293
        self._pg.gen_use_interleave_CheckBox.stateChanged.connect(self.pulse_generator_settings_changed)
294
        self._pg.gen_activation_config_ComboBox.currentIndexChanged.connect(self.pulse_generator_settings_changed)
295
        self._pg.gen_sample_freq_DSpinBox.editingFinished.connect(self.pulse_generator_settings_changed)
296
        return
297
298 View Code Duplication
    def _connect_sequence_generator_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
299
        # Connect Sequence editor tab signals
300
        self._sg.sample_sequence_PushButton.clicked.connect(self.sample_sequence_clicked)
301
        self._sg.samplo_sequence_PushButton.clicked.connect(self.samplo_sequence_clicked)
302
        self._sg.load_sequence_PushButton.clicked.connect(self.load_sequence_clicked)
303
304
        self._sg.sequence_add_last_PushButton.clicked.connect(self.sequence_add_last_clicked)
305
        self._sg.sequence_del_last_PushButton.clicked.connect(self.sequence_del_last_clicked)
306
        self._sg.sequence_add_sel_PushButton.clicked.connect(self.sequence_add_sel_clicked)
307
        self._sg.sequence_del_sel_PushButton.clicked.connect(self.sequence_del_sel_clicked)
308
        self._sg.sequence_clear_PushButton.clicked.connect(self.sequence_clear_clicked)
309
        self._sg.curr_sequence_generate_PushButton.clicked.connect(self.editor_generate_sequence_clicked)
310
        self._sg.curr_sequence_del_PushButton.clicked.connect(self.editor_delete_sequence_clicked)
311
        self._sg.curr_sequence_load_PushButton.clicked.connect(self.editor_load_sequence_clicked)
312
        return
313
314 View Code Duplication
    def _connect_analysis_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
315
        # Connect pulse analysis tab signals
316
        self._pa.fit_param_PushButton.clicked.connect(self.fit_clicked)
317
318
        self._pa.ext_control_use_mw_CheckBox.stateChanged.connect(self.microwave_settings_changed)
319
        self._pa.ext_control_mw_freq_DoubleSpinBox.editingFinished.connect(self.microwave_settings_changed)
320
        self._pa.ext_control_mw_power_DoubleSpinBox.editingFinished.connect(self.microwave_settings_changed)
321
322
        self._pa.ana_param_invoke_settings_CheckBox.stateChanged.connect(self.measurement_settings_changed)
323
        self._pa.ana_param_alternating_CheckBox.stateChanged.connect(self.measurement_settings_changed)
324
        self._pa.ana_param_ignore_first_CheckBox.stateChanged.connect(self.measurement_settings_changed)
325
        self._pa.ana_param_ignore_last_CheckBox.stateChanged.connect(self.measurement_settings_changed)
326
        self._pa.ana_param_x_axis_start_ScienDSpinBox.editingFinished.connect(self.measurement_settings_changed)
327
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.editingFinished.connect(self.measurement_settings_changed)
328
        self._pa.ana_param_num_laser_pulse_SpinBox.editingFinished.connect(self.measurement_settings_changed)
329
330
        self._pa.ana_param_record_length_DoubleSpinBox.editingFinished.connect(self.fast_counter_settings_changed)
331
        self._pa.ana_param_fc_bins_ComboBox.currentIndexChanged.connect(self.fast_counter_settings_changed)
332
333
        self._pa.time_param_ana_periode_DoubleSpinBox.editingFinished.connect(self.measurement_timer_changed)
334
        self._pa.ana_param_errorbars_CheckBox.toggled.connect(self.toggle_error_bars)
335
        self._pa.second_plot_ComboBox.currentIndexChanged[str].connect(self.second_plot_changed)
336
        return
337
338 View Code Duplication
    def _connect_extraction_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
339
        # Connect pulse extraction tab signals
340
        self._pe.extract_param_ana_window_start_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
341
        self._pe.extract_param_ana_window_width_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
342
        self._pe.extract_param_ref_window_start_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
343
        self._pe.extract_param_ref_window_width_DSpinBox.editingFinished.connect(self.analysis_settings_changed)
344
        self.sig_start_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
345
        self.sig_end_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
346
        self.ref_start_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
347
        self.ref_end_line.sigPositionChangeFinished.connect(self.analysis_settings_changed)
348
        self._pe.extract_param_analysis_method_comboBox.currentIndexChanged.connect(self.analysis_settings_changed)
349
        self._pe.extract_param_method_comboBox.currentIndexChanged.connect(self.extraction_settings_changed)
350
351
        self._pe.laserpulses_ComboBox.currentIndexChanged.connect(self.update_laser_data)
352
        self._pe.laserpulses_display_raw_CheckBox.stateChanged.connect(self.update_laser_data)
353
        return
354
355
    def _connect_predefined_methods_tab_signals(self):
356
        pass
357
358 View Code Duplication
    def _connect_logic_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
359
        # Connect update signals from pulsed_master_logic
360
        self.pulsedmasterlogic().sigMeasurementDataUpdated.connect(self.measurement_data_updated)
361
        self.pulsedmasterlogic().sigTimerUpdated.connect(self.measurement_timer_updated)
362
        self.pulsedmasterlogic().sigFitUpdated.connect(self.fit_data_updated)
363
        self.pulsedmasterlogic().sigMeasurementStatusUpdated.connect(self.measurement_status_updated)
364
        self.pulsedmasterlogic().sigPulserRunningUpdated.connect(self.pulser_running_updated)
365
        self.pulsedmasterlogic().sigExtMicrowaveRunningUpdated.connect(self.microwave_running_updated)
366
        self.pulsedmasterlogic().sigExtMicrowaveSettingsUpdated.connect(self.microwave_settings_updated)
367
        self.pulsedmasterlogic().sigFastCounterSettingsUpdated.connect(self.fast_counter_settings_updated)
368
        self.pulsedmasterlogic().sigMeasurementSettingsUpdated.connect(self.measurement_settings_updated)
369
        self.pulsedmasterlogic().sigAnalysisSettingsUpdated.connect(self.analysis_settings_updated)
370
        self.pulsedmasterlogic().sigExtractionSettingsUpdated.connect(self.extraction_settings_updated)
371
372
        self.pulsedmasterlogic().sigBlockDictUpdated.connect(self.update_block_dict)
373
        self.pulsedmasterlogic().sigEnsembleDictUpdated.connect(self.update_ensemble_dict)
374
        self.pulsedmasterlogic().sigSequenceDictUpdated.connect(self.update_sequence_dict)
375
        self.pulsedmasterlogic().sigAvailableWaveformsUpdated.connect(self.waveform_list_updated)
376
        self.pulsedmasterlogic().sigAvailableSequencesUpdated.connect(self.sequence_list_updated)
377
        self.pulsedmasterlogic().sigSampleEnsembleComplete.connect(self.sample_ensemble_finished)
378
        self.pulsedmasterlogic().sigSampleSequenceComplete.connect(self.sample_sequence_finished)
379
        self.pulsedmasterlogic().sigLoadedAssetUpdated.connect(self.loaded_asset_updated)
380
        self.pulsedmasterlogic().sigGeneratorSettingsUpdated.connect(self.pulse_generator_settings_updated)
381
        self.pulsedmasterlogic().sigSamplingSettingsUpdated.connect(self.generation_parameters_updated)
382
        # self.pulsedmasterlogic().sigPredefinedSequenceGenerated.connect()
383
        return
384
385 View Code Duplication
    def _disconnect_main_window_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
386
        # Connect main window actions and toolbar
387
        self._mw.action_Predefined_Methods_Config.triggered.disconnect()
388
        self._mw.pulser_on_off_PushButton.clicked.disconnect()
389
        self._mw.clear_device_PushButton.clicked.disconnect()
390
        self._mw.action_run_stop.triggered.disconnect()
391
        self._mw.action_continue_pause.triggered.disconnect()
392
        self._mw.action_pull_data.triggered.disconnect()
393
        self._mw.action_save.triggered.disconnect()
394
        self._mw.actionSave.triggered.disconnect()
395
        self._mw.action_Settings_Analysis.triggered.disconnect()
396
        self._mw.action_FitSettings.triggered.disconnect()
397
        return
398
399 View Code Duplication
    def _disconnect_dialog_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
400
        # Connect signals used in predefined methods config dialog
401
        self._pm_cfg.accepted.disconnect()
402
        self._pm_cfg.rejected.disconnect()
403
        self._pm_cfg.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
404
405
        # Connect signals used in analysis settings dialog
406
        self._as.accepted.disconnect()
407
        self._as.rejected.disconnect()
408
        self._as.buttonBox.button(QtWidgets.QDialogButtonBox.Apply).clicked.disconnect()
409
410
        # Connect signals used in fit settings dialog
411
        self._fsd.sigFitsUpdated.disconnect()
412
        return
413
414 View Code Duplication
    def _disconnect_pulse_generator_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
415
        # Connect Block/Ensemble editor tab signals
416
        self._pg.gen_laserchannel_ComboBox.currentIndexChanged.disconnect()
417
        self._pg.gen_syncchannel_ComboBox.currentIndexChanged.disconnect()
418
        self._pg.gen_gatechannel_ComboBox.currentIndexChanged.disconnect()
419
420
        self._pg.sample_ensemble_PushButton.clicked.disconnect()
421
        self._pg.samplo_ensemble_PushButton.clicked.disconnect()
422
        self._pg.load_ensemble_PushButton.clicked.disconnect()
423
424
        self._pg.block_add_last_PushButton.clicked.disconnect()
425
        self._pg.block_del_last_PushButton.clicked.disconnect()
426
        self._pg.block_add_sel_PushButton.clicked.disconnect()
427
        self._pg.block_del_sel_PushButton.clicked.disconnect()
428
        self._pg.block_clear_PushButton.clicked.disconnect()
429
        self._pg.organizer_add_last_PushButton.clicked.disconnect()
430
        self._pg.organizer_del_last_PushButton.clicked.disconnect()
431
        self._pg.organizer_add_sel_PushButton.clicked.disconnect()
432
        self._pg.organizer_del_sel_PushButton.clicked.disconnect()
433
        self._pg.organizer_clear_PushButton.clicked.disconnect()
434
        self._pg.curr_block_generate_PushButton.clicked.disconnect()
435
        self._pg.curr_block_del_PushButton.clicked.disconnect()
436
        self._pg.curr_block_load_PushButton.clicked.disconnect()
437
        self._pg.curr_ensemble_generate_PushButton.clicked.disconnect()
438
        self._pg.curr_ensemble_del_PushButton.clicked.disconnect()
439
        self._pg.curr_ensemble_load_PushButton.clicked.disconnect()
440
441
        self._pg.gen_use_interleave_CheckBox.stateChanged.disconnect()
442
        self._pg.gen_activation_config_ComboBox.currentIndexChanged.disconnect()
443
        self._pg.gen_sample_freq_DSpinBox.editingFinished.disconnect()
444
        return
445
446 View Code Duplication
    def _disconnect_sequence_generator_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
447
        # Connect Sequence editor tab signals
448
        self._sg.sample_sequence_PushButton.clicked.disconnect()
449
        self._sg.samplo_sequence_PushButton.clicked.disconnect()
450
        self._sg.load_sequence_PushButton.clicked.disconnect()
451
452
        self._sg.sequence_add_last_PushButton.clicked.disconnect()
453
        self._sg.sequence_del_last_PushButton.clicked.disconnect()
454
        self._sg.sequence_add_sel_PushButton.clicked.disconnect()
455
        self._sg.sequence_del_sel_PushButton.clicked.disconnect()
456
        self._sg.sequence_clear_PushButton.clicked.disconnect()
457
        self._sg.curr_sequence_generate_PushButton.clicked.disconnect()
458
        self._sg.curr_sequence_del_PushButton.clicked.disconnect()
459
        self._sg.curr_sequence_load_PushButton.clicked.disconnect()
460
        return
461
462 View Code Duplication
    def _disconnect_analysis_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
463
        # Connect pulse analysis tab signals
464
        self._pa.fit_param_PushButton.clicked.disconnect()
465
        self._pa.ext_control_use_mw_CheckBox.stateChanged.disconnect()
466
        self._pa.ext_control_mw_freq_DoubleSpinBox.editingFinished.disconnect()
467
        self._pa.ext_control_mw_power_DoubleSpinBox.editingFinished.disconnect()
468
469
        self._pa.ana_param_invoke_settings_CheckBox.stateChanged.disconnect()
470
        self._pa.ana_param_alternating_CheckBox.stateChanged.disconnect()
471
        self._pa.ana_param_ignore_first_CheckBox.stateChanged.disconnect()
472
        self._pa.ana_param_ignore_last_CheckBox.stateChanged.disconnect()
473
        self._pa.ana_param_x_axis_start_ScienDSpinBox.editingFinished.disconnect()
474
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.editingFinished.disconnect()
475
        self._pa.ana_param_num_laser_pulse_SpinBox.editingFinished.disconnect()
476
477
        self._pa.ana_param_record_length_DoubleSpinBox.editingFinished.disconnect()
478
        self._pa.ana_param_fc_bins_ComboBox.currentIndexChanged.disconnect()
479
480
        self._pa.time_param_ana_periode_DoubleSpinBox.editingFinished.disconnect()
481
        self._pa.ana_param_errorbars_CheckBox.toggled.disconnect()
482
        self._pa.second_plot_ComboBox.currentIndexChanged[str].disconnect()
483
        return
484
485 View Code Duplication
    def _disconnect_extraction_tab_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
486
        # Connect pulse extraction tab signals
487
        self._pe.extract_param_ana_window_start_DSpinBox.editingFinished.disconnect()
488
        self._pe.extract_param_ana_window_width_DSpinBox.editingFinished.disconnect()
489
        self._pe.extract_param_ref_window_start_DSpinBox.editingFinished.disconnect()
490
        self._pe.extract_param_ref_window_width_DSpinBox.editingFinished.disconnect()
491
        self.sig_start_line.sigPositionChangeFinished.disconnect()
492
        self.sig_end_line.sigPositionChangeFinished.disconnect()
493
        self.ref_start_line.sigPositionChangeFinished.disconnect()
494
        self.ref_end_line.sigPositionChangeFinished.disconnect()
495
        self._pe.extract_param_analysis_method_comboBox.currentIndexChanged.disconnect()
496
        self._pe.extract_param_method_comboBox.currentIndexChanged.disconnect()
497
498
        self._pe.laserpulses_ComboBox.currentIndexChanged.disconnect()
499
        self._pe.laserpulses_display_raw_CheckBox.stateChanged.disconnect()
500
        return
501
502
    def _disconnect_predefined_methods_tab_signals(self):
503
        for combobox in self._channel_selection_comboboxes:
504
            combobox.currentIndexChanged.disconnect()
505
        for widget in self._global_param_widgets:
506
            if hasattr(widget, 'isChecked'):
507
                widget.stateChanged.disconnect()
508
            else:
509
                widget.editingFinished.disconnect()
510
        return
511
512 View Code Duplication
    def _disconnect_logic_signals(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
513
        # Disconnect update signals from pulsed_master_logic
514
        self.pulsedmasterlogic().sigMeasurementDataUpdated.disconnect()
515
        self.pulsedmasterlogic().sigTimerUpdated.disconnect()
516
        self.pulsedmasterlogic().sigFitUpdated.disconnect()
517
        self.pulsedmasterlogic().sigMeasurementStatusUpdated.disconnect()
518
        self.pulsedmasterlogic().sigPulserRunningUpdated.disconnect()
519
        self.pulsedmasterlogic().sigExtMicrowaveRunningUpdated.disconnect()
520
        self.pulsedmasterlogic().sigExtMicrowaveSettingsUpdated.disconnect()
521
        self.pulsedmasterlogic().sigFastCounterSettingsUpdated.disconnect()
522
        self.pulsedmasterlogic().sigMeasurementSettingsUpdated.disconnect()
523
        self.pulsedmasterlogic().sigAnalysisSettingsUpdated.disconnect()
524
        self.pulsedmasterlogic().sigExtractionSettingsUpdated.disconnect()
525
526
        self.pulsedmasterlogic().sigBlockDictUpdated.disconnect()
527
        self.pulsedmasterlogic().sigEnsembleDictUpdated.disconnect()
528
        self.pulsedmasterlogic().sigSequenceDictUpdated.disconnect()
529
        self.pulsedmasterlogic().sigAvailableWaveformsUpdated.disconnect()
530
        self.pulsedmasterlogic().sigAvailableSequencesUpdated.disconnect()
531
        self.pulsedmasterlogic().sigSampleEnsembleComplete.disconnect()
532
        self.pulsedmasterlogic().sigSampleSequenceComplete.disconnect()
533
        self.pulsedmasterlogic().sigLoadedAssetUpdated.disconnect()
534
        self.pulsedmasterlogic().sigGeneratorSettingsUpdated.disconnect()
535
        self.pulsedmasterlogic().sigSamplingSettingsUpdated.disconnect()
536
        # self.pulsedmasterlogic().sigPredefinedSequenceGenerated.disconnect()
537
        return
538
539
    ###########################################################################
540
    #                    Main window related methods                          #
541
    ###########################################################################
542
    def _activate_main_window_ui(self):
543
        self._setup_toolbar()
544
        self.loaded_asset_updated(*self.pulsedmasterlogic().loaded_asset)
545
        return
546
547
    def _deactivate_main_window_ui(self):
548
        pass
549
550
    def _setup_toolbar(self):
551
        # create all the needed control widgets on the fly
552
        self._mw.pulser_on_off_PushButton = QtWidgets.QPushButton()
553
        self._mw.pulser_on_off_PushButton.setText('Pulser ON')
554
        self._mw.pulser_on_off_PushButton.setToolTip('Switch the device on and off.')
555
        self._mw.pulser_on_off_PushButton.setCheckable(True)
556
        self._mw.control_ToolBar.addWidget(self._mw.pulser_on_off_PushButton)
557
558
        self._mw.clear_device_PushButton = QtWidgets.QPushButton(self._mw)
559
        self._mw.clear_device_PushButton.setText('Clear Pulser')
560
        self._mw.clear_device_PushButton.setToolTip('Clear the Pulser Device Memory\n'
561
                                                    'from all loaded files.')
562
        self._mw.control_ToolBar.addWidget(self._mw.clear_device_PushButton)
563
564
        self._mw.current_loaded_asset_Label = QtWidgets.QLabel(self._mw)
565
        sizepolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
566
                                           QtWidgets.QSizePolicy.Fixed)
567
        sizepolicy.setHorizontalStretch(0)
568
        sizepolicy.setVerticalStretch(0)
569
        sizepolicy.setHeightForWidth(
570
            self._mw.current_loaded_asset_Label.sizePolicy().hasHeightForWidth())
571
        self._mw.current_loaded_asset_Label.setSizePolicy(sizepolicy)
572
        self._mw.current_loaded_asset_Label.setText('  No Asset Loaded')
573
        self._mw.current_loaded_asset_Label.setToolTip('Display the currently loaded asset.')
574
        self._mw.control_ToolBar.addWidget(self._mw.current_loaded_asset_Label)
575
576
        self._mw.save_tag_LineEdit = QtWidgets.QLineEdit()
577
        self._mw.save_tag_LineEdit.setMaximumWidth(200)
578
        self._mw.save_ToolBar.addWidget(self._mw.save_tag_LineEdit)
579
        return
580
581
    @QtCore.Slot(bool)
582
    def pulser_on_off_clicked(self, checked):
583
        """ Manually switch the pulser output on/off. """
584
        if checked:
585
            self._mw.pulser_on_off_PushButton.setText('Pulser OFF')
586
        else:
587
            self._mw.pulser_on_off_PushButton.setText('Pulser ON')
588
        self.pulsedmasterlogic().toggle_pulse_generator(checked)
589
        return
590
591
    @QtCore.Slot(bool)
592
    def pulser_running_updated(self, is_running):
593
        """
594
595
        @param is_running:
596
        @return:
597
        """
598
        # block signals
599
        self._mw.pulser_on_off_PushButton.blockSignals(True)
600
        # set widgets
601
        if is_running:
602
            self._mw.pulser_on_off_PushButton.setText('Pulser OFF')
603
            if not self._mw.pulser_on_off_PushButton.isChecked():
604
                self._mw.pulser_on_off_PushButton.toggle()
605
        else:
606
            self._mw.pulser_on_off_PushButton.setText('Pulser ON')
607
            if self._mw.pulser_on_off_PushButton.isChecked():
608
                self._mw.pulser_on_off_PushButton.toggle()
609
        # unblock signals
610
        self._mw.pulser_on_off_PushButton.blockSignals(False)
611
        return
612
613
    @QtCore.Slot()
614
    def clear_pulser_clicked(self):
615
        """ Delete all loaded files in the device's current memory. """
616
        self.pulsedmasterlogic().clear_pulse_generator()
617
        return
618
619
    @QtCore.Slot(str, str)
620
    def loaded_asset_updated(self, asset_name, asset_type):
621
        """ Check the current loaded asset from the logic and update the display. """
622
        label = self._mw.current_loaded_asset_Label
623
        if not asset_name:
624
            label.setText('  No asset loaded')
625
        elif asset_type in ('PulseBlockEnsemble', 'PulseSequence'):
626
            label.setText('  {0} ({1})'.format(asset_name, asset_type))
627
        else:
628
            label.setText('  Unknown asset type')
629
        # enable buttons
630
        self._pg.load_ensemble_PushButton.setEnabled(True)
631
        self._pg.samplo_ensemble_PushButton.setEnabled(True)
632
        self._pg.sample_ensemble_PushButton.setEnabled(True)
633
        self._sg.load_sequence_PushButton.setEnabled(True)
634
        self._sg.samplo_sequence_PushButton.setEnabled(True)
635
        self._sg.sample_sequence_PushButton.setEnabled(True)
636
        return
637
638
    @QtCore.Slot(bool)
639
    def measurement_run_stop_clicked(self, isChecked):
640
        """ Manages what happens if pulsed measurement is started or stopped.
641
642
        @param bool isChecked: start scan if that is possible
643
        """
644
        self.pulsedmasterlogic().toggle_pulsed_measurement(isChecked)
645
        return
646
647
    @QtCore.Slot(bool)
648
    def measurement_continue_pause_clicked(self, isChecked):
649
        """ Continues and pauses the measurement. """
650
        self.pulsedmasterlogic().toggle_pulsed_measurement_pause(isChecked)
651
        return
652
653
    @QtCore.Slot(bool, bool)
654
    def measurement_status_updated(self, is_running, is_paused):
655
        """
656
657
        @param is_running:
658
        @param is_paused:
659
        @return:
660
        """
661
        # block signals
662
        self._mw.action_run_stop.blockSignals(True)
663
        self._mw.action_continue_pause.blockSignals(True)
664
665
        # Enable/Disable widgets
666
        if is_running:
667
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
668
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
669
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(False)
670
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(False)
671
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(False)
672
            self._pa.ana_param_record_length_DoubleSpinBox.setEnabled(False)
673
            self._pa.ext_control_use_mw_CheckBox.setEnabled(False)
674
            self._pa.ana_param_fc_bins_ComboBox.setEnabled(False)
675
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(False)
676
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(False)
677
            self._pa.ana_param_alternating_CheckBox.setEnabled(False)
678
            self._pa.ana_param_invoke_settings_CheckBox.setEnabled(False)
679
            self._pg.gen_use_interleave_CheckBox.setEnabled(False)
680
            self._pg.load_ensemble_PushButton.setEnabled(False)
681
            self._pg.gen_sample_freq_DSpinBox.setEnabled(False)
682
            self._pg.gen_activation_config_ComboBox.setEnabled(False)
683
            self._sg.load_sequence_PushButton.setEnabled(False)
684
            self._mw.pulser_on_off_PushButton.setEnabled(False)
685
            self._mw.action_continue_pause.setEnabled(True)
686
            self._mw.action_pull_data.setEnabled(True)
687
            if not self._mw.action_run_stop.isChecked():
688
                self._mw.action_run_stop.toggle()
689
        else:
690
            self._pa.ext_control_use_mw_CheckBox.setEnabled(True)
691
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
692
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
693
            self._pa.ana_param_fc_bins_ComboBox.setEnabled(True)
694
            self._pg.gen_use_interleave_CheckBox.setEnabled(True)
695
            self._pg.load_ensemble_PushButton.setEnabled(True)
696
            self._pg.gen_sample_freq_DSpinBox.setEnabled(True)
697
            self._pg.gen_activation_config_ComboBox.setEnabled(True)
698
            self._sg.load_sequence_PushButton.setEnabled(True)
699
            self._mw.pulser_on_off_PushButton.setEnabled(True)
700
            self._mw.action_continue_pause.setEnabled(False)
701
            self._mw.action_pull_data.setEnabled(False)
702
            self._pa.ana_param_invoke_settings_CheckBox.setEnabled(True)
703
            if not self._pa.ana_param_invoke_settings_CheckBox.isChecked():
704
                self._pa.ana_param_ignore_first_CheckBox.setEnabled(True)
705
                self._pa.ana_param_ignore_last_CheckBox.setEnabled(True)
706
                self._pa.ana_param_alternating_CheckBox.setEnabled(True)
707
                self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(True)
708
                self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(True)
709
                self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(True)
710
                self._pa.ana_param_record_length_DoubleSpinBox.setEnabled(True)
711
            if self._mw.action_run_stop.isChecked():
712
                self._mw.action_run_stop.toggle()
713
        if is_paused:
714
            if not self._mw.action_continue_pause.isChecked():
715
                self._mw.action_continue_pause.toggle()
716
        else:
717
            if self._mw.action_continue_pause.isChecked():
718
                self._mw.action_continue_pause.toggle()
719
        # unblock signals
720
        self._mw.action_run_stop.blockSignals(False)
721
        self._mw.action_continue_pause.blockSignals(False)
722
        return
723
724
    @QtCore.Slot()
725
    def pull_data_clicked(self):
726
        """ Pulls and analysis the data when the 'action_pull_data'-button is clicked. """
727
        self.pulsedmasterlogic().manually_pull_data()
728
        return
729
730
    def save_clicked(self):
731
        """Saves the current data"""
732
        self._mw.action_save.setEnabled(False)
733
        self._mw.actionSave.setEnabled(False)
734
        save_tag = self._mw.save_tag_LineEdit.text()
735
        with_error = self._pa.ana_param_errorbars_CheckBox.isChecked()
736
737
        self.pulsedmasterlogic().save_measurement_data(tag=save_tag,
738
                                                       with_error=with_error)
739
        self._mw.action_save.setEnabled(True)
740
        self._mw.actionSave.setEnabled(True)
741
        return
742
743
    @QtCore.Slot()
744
    def measurement_timer_changed(self):
745
        """ This method handles the analysis timing"""
746
        timer_interval = self._pa.time_param_ana_periode_DoubleSpinBox.value()
747
        self.pulsedmasterlogic().set_timer_interval(timer_interval)
748
        return
749
750
    @QtCore.Slot(float, int, float)
751
    def measurement_timer_updated(self, elapsed_time, elapsed_sweeps, timer_interval):
752
        """
753
        Refreshes the elapsed time and sweeps of the measurement.
754
755
        @param float elapsed_time:
756
        @param int elapsed_sweeps:
757
        @param float timer_interval:
758
        @return:
759
        """
760
        time_str = str(datetime.timedelta(seconds=elapsed_time)).rsplit('.', 1)[0]
761
        # block signals
762
        self._pa.time_param_elapsed_time_LineEdit.blockSignals(True)
763
        self._pa.time_param_ana_periode_DoubleSpinBox.blockSignals(True)
764
        self._pa.time_param_elapsed_sweep_SpinBox.blockSignals(True)
765
        # Set widgets
766
        self._pa.time_param_elapsed_time_LineEdit.setText(time_str)
767
        self._pa.time_param_ana_periode_DoubleSpinBox.setValue(timer_interval)
768
        self._pa.time_param_elapsed_sweep_SpinBox.setValue(elapsed_sweeps)
769
        # unblock signals
770
        self._pa.time_param_elapsed_time_LineEdit.blockSignals(False)
771
        self._pa.time_param_ana_periode_DoubleSpinBox.blockSignals(False)
772
        self._pa.time_param_elapsed_sweep_SpinBox.blockSignals(False)
773
        return
774
775
    ###########################################################################
776
    #                 Analysis settings dialog related methods                #
777
    ###########################################################################
778 View Code Duplication
    def _activate_analysis_settings_ui(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
779
        """
780
        Initialize the settings dialog for 'Analysis' Tab.
781
        """
782
        self._as.ana_param_x_axis_name_LineEdit.setText(self._ana_param_x_axis_name_text)
783
        self._as.ana_param_x_axis_unit_LineEdit.setText(self._ana_param_x_axis_unit_text)
784
        self._as.ana_param_y_axis_name_LineEdit.setText(self._ana_param_y_axis_name_text)
785
        self._as.ana_param_y_axis_unit_LineEdit.setText(self._ana_param_y_axis_unit_text)
786
        self._as.ana_param_second_plot_x_axis_name_LineEdit.setText(self._ana_param_second_plot_x_axis_name_text)
787
        self._as.ana_param_second_plot_x_axis_unit_LineEdit.setText(self._ana_param_second_plot_x_axis_unit_text)
788
        self._as.ana_param_second_plot_y_axis_name_LineEdit.setText(self._ana_param_second_plot_y_axis_name_text)
789
        self._as.ana_param_second_plot_y_axis_unit_LineEdit.setText(self._ana_param_second_plot_y_axis_unit_text)
790
        self.update_analysis_settings()
791
        return
792
793
    def _deactivate_analysis_settings_ui(self):
794
        """
795
        De-initialize the settings dialog for 'Analysis' Tab.
796
        """
797
        self._as.close()
798
        return
799
800
    def update_analysis_settings(self):
801
        """ Apply the new settings """
802
        self._ana_param_x_axis_name_text = self._as.ana_param_x_axis_name_LineEdit.text()
803
        self._ana_param_x_axis_unit_text = self._as.ana_param_x_axis_unit_LineEdit.text()
804
        self._ana_param_y_axis_name_text = self._as.ana_param_y_axis_name_LineEdit.text()
805
        self._ana_param_y_axis_unit_text = self._as.ana_param_y_axis_unit_LineEdit.text()
806
807
        self._ana_param_second_plot_x_axis_name_text = self._as.ana_param_second_plot_x_axis_name_LineEdit.text()
808
        self._ana_param_second_plot_x_axis_unit_text = self._as.ana_param_second_plot_x_axis_unit_LineEdit.text()
809
        self._ana_param_second_plot_y_axis_name_text = self._as.ana_param_second_plot_y_axis_name_LineEdit.text()
810
        self._ana_param_second_plot_y_axis_unit_text = self._as.ana_param_second_plot_y_axis_unit_LineEdit.text()
811
812
        self._pa.pulse_analysis_PlotWidget.setLabel(
813
            axis='bottom',
814
            text=self._ana_param_x_axis_name_text,
815
            units=self._ana_param_x_axis_unit_text)
816
        self._pa.pulse_analysis_PlotWidget.setLabel(
817
            axis='left',
818
            text=self._ana_param_y_axis_name_text,
819
            units=self._ana_param_y_axis_unit_text)
820
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
821
            axis='bottom',
822
            text=self._ana_param_second_plot_x_axis_name_text,
823
            units=self._ana_param_second_plot_x_axis_unit_text)
824
        self._pa.pulse_analysis_second_PlotWidget.setLabel(
825
            axis='left',
826
            text=self._ana_param_second_plot_y_axis_name_text,
827
            units=self._ana_param_second_plot_y_axis_unit_text)
828
        self._pe.measuring_error_PlotWidget.setLabel(
829
            axis='bottom',
830
            text=self._ana_param_x_axis_name_text,
831
            units=self._ana_param_x_axis_unit_text)
832
833
        # FIXME: Not very elegant
834
        self.pulsedmasterlogic().fit_container.set_units(
835
            [self._ana_param_x_axis_unit_text, self._ana_param_y_axis_unit_text])
836
        return
837
838 View Code Duplication
    def keep_former_analysis_settings(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
839
        """ Keep the old settings """
840
        self._as.ana_param_x_axis_name_LineEdit.setText(self._ana_param_x_axis_name_text)
841
        self._as.ana_param_x_axis_unit_LineEdit.setText(self._ana_param_x_axis_unit_text)
842
        self._as.ana_param_y_axis_name_LineEdit.setText(self._ana_param_y_axis_name_text)
843
        self._as.ana_param_y_axis_unit_LineEdit.setText(self._ana_param_y_axis_unit_text)
844
        self._as.ana_param_second_plot_x_axis_name_LineEdit.setText(
845
            self._ana_param_second_plot_x_axis_name_text)
846
        self._as.ana_param_second_plot_x_axis_unit_LineEdit.setText(
847
            self._ana_param_second_plot_x_axis_unit_text)
848
        self._as.ana_param_second_plot_y_axis_name_LineEdit.setText(
849
            self._ana_param_second_plot_y_axis_name_text)
850
        self._as.ana_param_second_plot_y_axis_unit_LineEdit.setText(
851
            self._ana_param_second_plot_y_axis_unit_text)
852
        return
853
854
    def show_analysis_settings(self):
855
        """ Open the Analysis Settings Window. """
856
        self._as.exec_()
857
        return
858
859
    ###########################################################################
860
    #          Predefined methods settings dialog related methods             #
861
    ###########################################################################
862
    def _activate_predefined_methods_settings_ui(self):
863
        """ Initialize, connect and configure the pulse generator settings to be displayed in the
864
        editor.
865
        """
866
        # create all GUI elements and check all boxes listed in the methods to show
867
        for method_name in sorted(self.pulsedmasterlogic().generate_methods):
868
            # create checkboxes for the config dialogue
869
            name_checkbox = 'checkbox_' + method_name
870
            setattr(self._pm_cfg, name_checkbox, QtWidgets.QCheckBox(self._pm_cfg.scrollArea))
871
            checkbox = getattr(self._pm_cfg, name_checkbox)
872
            checkbox.setObjectName(name_checkbox)
873
            checkbox.setText(method_name)
874
            checkbox.setChecked(method_name in self._predefined_methods_to_show)
875
            self._pm_cfg.verticalLayout.addWidget(checkbox)
876
877
        # apply the chosen methods to the methods dialogue
878
        self.apply_predefined_methods_config()
879
        return
880
881
    def _deactivate_predefined_methods_settings_ui(self):
882
        self._pm_cfg.close()
883
        return
884
885
    def show_predefined_methods_config(self):
886
        """ Opens the Window for the config of predefined methods."""
887
        self._pm_cfg.show()
888
        self._pm_cfg.raise_()
889
        return
890
891
    def keep_former_predefined_methods_config(self):
892
        for method_name in self.pulsedmasterlogic().generate_methods:
893
            groupbox = getattr(self._pm, method_name + '_GroupBox')
894
            checkbox = getattr(self._pm_cfg, 'checkbox_' + method_name)
895
            checkbox.setChecked(groupbox.isVisible())
896
        return
897
898
    def apply_predefined_methods_config(self):
899
        self._predefined_methods_to_show = list()
900
        for method_name in self.pulsedmasterlogic().generate_methods:
901
            groupbox = getattr(self._pm, method_name + '_GroupBox')
902
            checkbox = getattr(self._pm_cfg, 'checkbox_' + method_name)
903
            groupbox.setVisible(checkbox.isChecked())
904
            if checkbox.isChecked():
905
                self._predefined_methods_to_show.append(method_name)
906
907
        self._pm.hintLabel.setVisible(len(self._predefined_methods_to_show) == 0)
908
        return
909
910
    ###########################################################################
911
    #                Predefined Methods tab related methods                   #
912
    ###########################################################################
913
    def _activate_predefined_methods_ui(self):
914
        # Set ranges for the global parameters and default values
915
        # self._pm.pm_mw_amp_Widget.setRange(0, np.inf)
916
        # self._pm.pm_mw_freq_Widget.setRange(0, np.inf)
917
        # self._pm.pm_channel_amp_Widget.setRange(0, np.inf)
918
        # self._pm.pm_delay_length_Widget.setRange(0, np.inf)
919
        # self._pm.pm_wait_time_Widget.setRange(0, np.inf)
920
        # self._pm.pm_laser_length_Widget.setRange(0, np.inf)
921
        # self._pm.pm_rabi_period_Widget.setRange(0, np.inf)
922
        #
923
        # self._pm.pm_mw_amp_Widget.setValue('0.125')
924
        # self._pm.pm_mw_freq_Widget.setValue('2.87e6')
925
        # self._pm.pm_channel_amp_Widget.setValue(0)
926
        # self._pm.pm_delay_length_Widget.setValue('500.0e-9')
927
        # self._pm.pm_wait_time_Widget.setValue('1.5e-6')
928
        # self._pm.pm_laser_length_Widget.setValue('3.0e-6')
929
        # self._pm.pm_rabi_period_Widget.setValue('200.0e-9')
930
931
        # Contraint some widgets by hardware constraints
932
        self._pm_apply_hardware_constraints()
933
934
        # Dynamically create GUI elements for global parameters
935
        self._channel_selection_comboboxes = list()  # List of created channel selection ComboBoxes
936
        self._global_param_widgets = list()  # List of all other created global parameter widgets
937
        self._create_pm_global_params()
938
        self.generation_parameters_updated(self.pulsedmasterlogic().generation_parameters)
939
940
        # Dynamically create GUI elements for predefined methods
941
        self._create_predefined_methods()
942
        return
943
944
    def _deactivate_predefined_methods_ui(self):
945
        # TODO: Implement
946
        pass
947
948
    def _pm_apply_hardware_constraints(self):
949
        # TODO: Implement
950
        pass
951
952
    def _create_pm_global_params(self):
953
        """
954
        Create GUI elements for global parameters of sequence generation
955
        """
956
        col_count = 0
957
        row_count = 1
958
        combo_count = 0
959
        for param, value in self.pulsedmasterlogic().generation_parameters.items():
960
            # Do not create widget for laser_channel since this widget is already part of the pulse
961
            # editor tab.
962
            if param in ('laser_channel', 'sync_channel', 'gate_channel'):
963
                continue
964
965
            # Create ComboBoxes for parameters ending on '_channel' to only be able to select
966
            # active channels. Also save references to those widgets in a list for easy access in
967
            # case of a change of channel activation config.
968
            if param.endswith('_channel') and (value is None or type(value) is str):
969
                widget = QtWidgets.QComboBox()
970
                widget.setObjectName('global_param_' + param)
971
                widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
972
                widget.addItem('')
973
                widget.addItems(sorted(self.pulsedmasterlogic().digital_channels))
974
                widget.addItems(sorted(self.pulsedmasterlogic().analog_channels))
975
                index = widget.findText(value)
976
                if index >= 0:
977
                    widget.setCurrentIndex(index)
978
                label = QtWidgets.QLabel(param + ':')
979
                label.setAlignment(QtCore.Qt.AlignRight)
980
                self._pm.global_param_gridLayout.addWidget(label, 0, combo_count, QtCore.Qt.AlignVCenter)
981
                self._pm.global_param_gridLayout.addWidget(widget, 0, combo_count + 1)
982
                combo_count += 2
983
                self._channel_selection_comboboxes.append(widget)
984
                widget.currentIndexChanged.connect(self.generation_parameters_changed)
985
                continue
986
987
            # Create all other widgets for int, float, bool and str and save them in a list for
988
            # later access. Also connect edited signals.
989
            if isinstance(value, str) or value is None:
990
                if value is None:
991
                    value = ''
992
                widget = QtWidgets.QLineEdit()
993
                widget.setText(value)
994
                widget.editingFinished.connect(self.generation_parameters_changed)
995
            elif type(value) is int:
996
                widget = ScienSpinBox()
997
                widget.setValue(value)
998
                widget.editingFinished.connect(self.generation_parameters_changed)
999
            elif type(value) is float:
1000
                widget = ScienDSpinBox()
1001
                widget.setValue(value)
1002
                if 'amp' in param or 'volt' in param:
1003
                    widget.setSuffix('V')
1004
                elif 'freq' in param:
1005
                    widget.setSuffix('Hz')
1006
                elif any(x in param for x in ('tau', 'period', 'time', 'delay', 'laser_length')):
1007
                    widget.setSuffix('s')
1008
                widget.editingFinished.connect(self.generation_parameters_changed)
1009
            elif type(value) is bool:
1010
                widget = QtWidgets.QCheckBox()
1011
                widget.setChecked(value)
1012
                widget.stateChanged.connect(self.generation_parameters_changed)
1013
1014
            widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
1015
1016
            # Create label
1017
            label = QtWidgets.QLabel(param + ':')
1018
            label.setAlignment(QtCore.Qt.AlignRight)
1019
1020
            # Rename widget to a naming convention
1021
            widget.setObjectName('global_param_' + param)
1022
1023
            # Save widget in list
1024
            self._global_param_widgets.append(widget)
1025
1026
            # Add widget to GUI layout
1027
            if col_count > 4:
1028
                col_count = 0
1029
                row_count += 1
1030
            self._pm.global_param_gridLayout.addWidget(label, row_count, col_count, QtCore.Qt.AlignVCenter)
1031
            self._pm.global_param_gridLayout.addWidget(widget, row_count, col_count + 1)
1032
            col_count += 2
1033
        spacer = QtWidgets.QSpacerItem(20, 0,
1034
                                       QtWidgets.QSizePolicy.Expanding,
1035
                                       QtWidgets.QSizePolicy.Minimum)
1036
        if row_count > 1:
1037
            self._pm.global_param_gridLayout.addItem(spacer, 1, 6)
1038
        else:
1039
            self._pm.global_param_gridLayout.addItem(spacer, 0, max(col_count, combo_count))
1040
        return
1041
1042
    def _create_predefined_methods(self):
1043
        """
1044
        Initializes the GUI elements for the predefined methods
1045
        """
1046
        method_params = self.pulsedmasterlogic().generate_method_params
1047
        for method_name in sorted(self.pulsedmasterlogic().generate_methods):
1048
            # Create the widgets for the predefined methods dialogue
1049
            # Create GroupBox for the method to reside in
1050
            groupBox = QtWidgets.QGroupBox(self._pm)
1051
            groupBox.setAlignment(QtCore.Qt.AlignLeft)
1052
            groupBox.setTitle(method_name)
1053
            # Create layout within the GroupBox
1054
            gridLayout = QtWidgets.QGridLayout(groupBox)
1055
            # Create generate buttons
1056
            gen_button = QtWidgets.QPushButton(groupBox)
1057
            gen_button.setText('Generate')
1058
            gen_button.setObjectName('gen_' + method_name)
1059
            gen_button.clicked.connect(self.generate_predefined_clicked)
1060
            samplo_button = QtWidgets.QPushButton(groupBox)
1061
            samplo_button.setText('GenSampLo')
1062
            samplo_button.setObjectName('samplo_' + method_name)
1063
            samplo_button.clicked.connect(self.samplo_predefined_clicked)
1064
            gridLayout.addWidget(gen_button, 0, 0, 1, 1)
1065
            gridLayout.addWidget(samplo_button, 1, 0, 1, 1)
1066
1067
            # run through all parameters of the current method and create the widgets
1068
            for param_index, (param_name, param) in enumerate(method_params[method_name].items()):
1069
                    # create a label for the parameter
1070
                    param_label = QtWidgets.QLabel(groupBox)
1071
                    param_label.setText(param_name)
1072
                    # create proper input widget for the parameter depending on default value type
1073
                    if type(param) is bool:
1074
                        input_obj = QtWidgets.QCheckBox(groupBox)
1075
                        input_obj.setChecked(param)
1076
                    elif type(param) is float:
1077
                        input_obj = ScienDSpinBox(groupBox)
1078
                        if 'amp' in param_name or 'volt' in param_name:
1079
                            input_obj.setSuffix('V')
1080
                        elif 'freq' in param_name:
1081
                            input_obj.setSuffix('Hz')
1082
                        elif 'time' in param_name or 'period' in param_name or 'tau' in param_name:
1083
                            input_obj.setSuffix('s')
1084
                        input_obj.setMinimumSize(QtCore.QSize(80, 0))
1085
                        input_obj.setValue(param)
1086
                    elif type(param) is int:
1087
                        input_obj = ScienSpinBox(groupBox)
1088
                        input_obj.setValue(param)
1089
                    elif type(param) is str:
1090
                        input_obj = QtWidgets.QLineEdit(groupBox)
1091
                        input_obj.setMinimumSize(QtCore.QSize(80, 0))
1092
                        input_obj.setText(param)
1093
                    else:
1094
                        self.log.error('The predefined method "{0}" has an argument "{1}" which is '
1095
                                       'has no default argument or an invalid type (str, float, '
1096
                                       'int or bool allowed)!\nCreation of the viewbox aborted.'
1097
                                       ''.format('generate_' + method_name, param_name))
1098
                        continue
1099
                    # Adjust size policy
1100
                    input_obj.setMinimumWidth(75)
1101
                    input_obj.setMaximumWidth(100)
1102
                    gridLayout.addWidget(param_label, 0, param_index + 1, 1, 1)
1103
                    gridLayout.addWidget(input_obj, 1, param_index + 1, 1, 1)
1104
                    setattr(self._pm, method_name + '_param_' + param_name + '_Widget', input_obj)
1105
            h_spacer = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Expanding,
1106
                                             QtWidgets.QSizePolicy.Minimum)
1107
            gridLayout.addItem(h_spacer, 1, param_index + 2, 1, 1)
1108
1109
            # attach the GroupBox widget to the predefined methods widget.
1110
            setattr(self._pm, method_name + '_GroupBox', groupBox)
1111
            self._pm.verticalLayout.addWidget(groupBox)
1112
        self._pm.verticalLayout.addStretch()
1113
        return
1114
1115
    ###########################################################################
1116
    #                   Pulse Generator tab related methods                   #
1117
    ###########################################################################
1118
    def _activate_pulse_generator_ui(self):
1119
        """ Initialize, connect and configure the 'Pulse Generator' Tab.
1120
        """
1121
        # Apply hardware constraints to input widgets
1122
        self._pg_apply_hardware_constraints()
1123
1124
        # Configure widgets
1125
        self._pg.curr_ensemble_length_DSpinBox.setRange(0, np.inf)
1126
        self._pg.curr_ensemble_length_DSpinBox.setDecimals(6, dynamic_precision=False)
1127
        self._pg.curr_ensemble_bins_SpinBox.setRange(0, 2**63-1)
1128
        self._pg.curr_ensemble_laserpulses_SpinBox.setRange(0, 2**31-1)
1129
1130
        # initialize widgets
1131
        self.pulse_generator_settings_updated(self.pulsedmasterlogic().pulse_generator_settings)
1132
        self.generation_parameters_updated(self.pulsedmasterlogic().generation_parameters)
1133
        self.fast_counter_settings_updated(self.pulsedmasterlogic().fast_counter_settings)
1134
        self.update_block_dict(self.pulsedmasterlogic().saved_pulse_blocks)
1135
        self.update_ensemble_dict(self.pulsedmasterlogic().saved_pulse_block_ensembles)
1136
        return
1137
1138
    def _deactivate_pulse_generator_ui(self):
1139
        """ Disconnects the configuration for 'Pulse Generator Tab.
1140
        """
1141
        # TODO: implement
1142
        pass
1143
1144
    def _pg_apply_hardware_constraints(self):
1145
        """
1146
        Retrieve the constraints from pulser hardware and apply these constraints to the pulse
1147
        generator GUI elements.
1148
        """
1149
        # block signals
1150
        self._pg.gen_activation_config_ComboBox.blockSignals(True)
1151
        self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
1152
        # apply constraints
1153
        pulser_constr = self.pulsedmasterlogic().pulse_generator_constraints
1154
        self._pg.gen_activation_config_ComboBox.addItems(list(pulser_constr.activation_config))
1155
        self._pg.gen_sample_freq_DSpinBox.setMinimum(pulser_constr.sample_rate.min)
1156
        self._pg.gen_sample_freq_DSpinBox.setMaximum(pulser_constr.sample_rate.max)
1157
        # unblock signals
1158
        self._pg.gen_activation_config_ComboBox.blockSignals(False)
1159
        self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
1160
        return
1161
1162
    @QtCore.Slot()
1163
    def pulse_generator_settings_changed(self):
1164
        """
1165
1166
        @return:
1167
        """
1168
        if self._mw.action_run_stop.isChecked():
1169
            return
1170
        # FIXME: Properly implement amplitude
1171
        settings_dict = dict()
1172
        settings_dict['sample_rate'] = self._pg.gen_sample_freq_DSpinBox.value()
1173
        settings_dict['activation_config'] = self._pg.gen_activation_config_ComboBox.currentText()
1174
        settings_dict['interleave'] = self._pg.gen_use_interleave_CheckBox.isChecked()
1175
        self.pulsedmasterlogic().set_pulse_generator_settings(settings_dict)
1176
        return
1177
1178
    @QtCore.Slot(dict)
1179
    def pulse_generator_settings_updated(self, settings_dict):
1180
        """
1181
1182
        @param settings_dict
1183
        @return:
1184
        """
1185
        # block signals
1186
        self._pg.gen_sample_freq_DSpinBox.blockSignals(True)
1187
        self._pg.gen_use_interleave_CheckBox.blockSignals(True)
1188
        self._pg.gen_activation_config_ComboBox.blockSignals(True)
1189
        self._pg.gen_analog_channels_lineEdit.blockSignals(True)
1190
        self._pg.gen_digital_channels_lineEdit.blockSignals(True)
1191
        self._pg.gen_laserchannel_ComboBox.blockSignals(True)
1192
        self._pg.gen_syncchannel_ComboBox.blockSignals(True)
1193
        self._pg.gen_gatechannel_ComboBox.blockSignals(True)
1194
        if hasattr(self, '_channel_selection_comboboxes'):
1195
            for widget in self._channel_selection_comboboxes:
1196
                widget.blockSignals(True)
1197
1198
        # Set widgets
1199
        # FIXME: Properly implement amplitude and interleave
1200
        if 'sample_rate' in settings_dict:
1201
            self._pg.gen_sample_freq_DSpinBox.setValue(settings_dict['sample_rate'])
1202
        if 'activation_config' in settings_dict:
1203
            config_name = settings_dict['activation_config'][0]
1204
            index = self._pg.gen_activation_config_ComboBox.findText(config_name)
1205
            self._pg.gen_activation_config_ComboBox.setCurrentIndex(index)
1206
            digital_str = str(sorted(
1207
                [chnl for chnl in settings_dict['activation_config'][1] if chnl.startswith('d')]))
1208
            analog_str = str(sorted(
1209
                [chnl for chnl in settings_dict['activation_config'][1] if chnl.startswith('a')]))
1210
            digital_str = digital_str.strip('[]').replace('\'', '').replace(',', ' |')
1211
            analog_str = analog_str.strip('[]').replace('\'', '').replace(',', ' |')
1212
            self._pg.gen_digital_channels_lineEdit.setText(digital_str)
1213
            self._pg.gen_analog_channels_lineEdit.setText(analog_str)
1214
1215
            # Update channel ComboBoxes
1216
            former_laser_channel = self._pg.gen_laserchannel_ComboBox.currentText()
1217
            self._pg.gen_laserchannel_ComboBox.clear()
1218
            self._pg.gen_laserchannel_ComboBox.addItems(
1219
                sorted(settings_dict['activation_config'][1]))
1220
            if former_laser_channel in settings_dict['activation_config'][1]:
1221
                index = self._pg.gen_laserchannel_ComboBox.findText(former_laser_channel)
1222
                self._pg.gen_laserchannel_ComboBox.setCurrentIndex(index)
1223
1224
            former_sync_channel = self._pg.gen_syncchannel_ComboBox.currentText()
1225
            self._pg.gen_syncchannel_ComboBox.clear()
1226
            self._pg.gen_syncchannel_ComboBox.addItem('')
1227
            self._pg.gen_syncchannel_ComboBox.addItems(
1228
                sorted(settings_dict['activation_config'][1]))
1229
            if former_sync_channel in settings_dict['activation_config'][1]:
1230
                index = self._pg.gen_syncchannel_ComboBox.findText(former_sync_channel)
1231
                self._pg.gen_syncchannel_ComboBox.setCurrentIndex(index)
1232
1233
            former_gate_channel = self._pg.gen_gatechannel_ComboBox.currentText()
1234
            self._pg.gen_gatechannel_ComboBox.clear()
1235
            self._pg.gen_gatechannel_ComboBox.addItem('')
1236
            self._pg.gen_gatechannel_ComboBox.addItems(
1237
                sorted(settings_dict['activation_config'][1]))
1238
            if former_gate_channel in settings_dict['activation_config'][1]:
1239
                index = self._pg.gen_gatechannel_ComboBox.findText(former_gate_channel)
1240
                self._pg.gen_gatechannel_ComboBox.setCurrentIndex(index)
1241
1242
            if hasattr(self, '_channel_selection_comboboxes'):
1243
                for widget in self._channel_selection_comboboxes:
1244
                    former_channel = widget.currentText()
1245
                    widget.clear()
1246
                    widget.addItem('')
1247
                    widget.addItems(sorted(settings_dict['activation_config'][1]))
1248
                    if former_channel in settings_dict['activation_config'][1]:
1249
                        index = widget.findText(former_channel)
1250
                        widget.setCurrentIndex(index)
1251
1252
            # Set activation config in block editor
1253
            self._pg.block_editor.set_activation_config(settings_dict['activation_config'][1])
1254
        if 'interleave' in settings_dict:
1255
            self._pg.gen_use_interleave_CheckBox.setChecked(settings_dict['interleave'])
1256
1257
        # unblock signals
1258
        self._pg.gen_sample_freq_DSpinBox.blockSignals(False)
1259
        self._pg.gen_use_interleave_CheckBox.blockSignals(False)
1260
        self._pg.gen_activation_config_ComboBox.blockSignals(False)
1261
        self._pg.gen_analog_channels_lineEdit.blockSignals(False)
1262
        self._pg.gen_digital_channels_lineEdit.blockSignals(False)
1263
        self._pg.gen_laserchannel_ComboBox.blockSignals(False)
1264
        self._pg.gen_syncchannel_ComboBox.blockSignals(False)
1265
        self._pg.gen_gatechannel_ComboBox.blockSignals(False)
1266
        if hasattr(self, '_channel_selection_comboboxes'):
1267
            for widget in self._channel_selection_comboboxes:
1268
                widget.blockSignals(False)
1269
        return
1270
1271
    @QtCore.Slot()
1272
    def generation_parameters_changed(self):
1273
        """
1274
1275
        @return:
1276
        """
1277
        settings_dict = dict()
1278
        settings_dict['laser_channel'] = self._pg.gen_laserchannel_ComboBox.currentText()
1279
        settings_dict['sync_channel'] = self._pg.gen_syncchannel_ComboBox.currentText()
1280
        settings_dict['gate_channel'] = self._pg.gen_gatechannel_ComboBox.currentText()
1281
        # Add channel specifiers from predefined methods tab
1282
        if hasattr(self, '_channel_selection_comboboxes'):
1283
            for combobox in self._channel_selection_comboboxes:
1284
                # cut away 'global_param_' from beginning of the objectName
1285
                param_name = combobox.objectName()[13:]
1286
                settings_dict[param_name] = combobox.currentText()
1287
        # Add remaining global parameter widgets
1288 View Code Duplication
        if hasattr(self, '_global_param_widgets'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1289
            for widget in self._global_param_widgets:
1290
                # cut away 'global_param_' from beginning of the objectName
1291
                param_name = widget.objectName()[13:]
1292
                if hasattr(widget, 'isChecked'):
1293
                    settings_dict[param_name] = widget.isChecked()
1294
                elif hasattr(widget, 'value'):
1295
                    settings_dict[param_name] = widget.value()
1296
                elif hasattr(widget, 'text'):
1297
                    settings_dict[param_name] = widget.text()
1298
1299
        self.pulsedmasterlogic().set_generation_parameters(settings_dict)
1300
        return
1301
1302
    @QtCore.Slot(dict)
1303
    def generation_parameters_updated(self, settings_dict):
1304
        """
1305
1306
        @param settings_dict:
1307
        @return:
1308
        """
1309
        # block signals
1310
        self._pg.gen_laserchannel_ComboBox.blockSignals(True)
1311
        self._pg.gen_syncchannel_ComboBox.blockSignals(True)
1312
        self._pg.gen_gatechannel_ComboBox.blockSignals(True)
1313
1314
        if 'laser_channel' in settings_dict:
1315
            index = self._pg.gen_laserchannel_ComboBox.findText(settings_dict['laser_channel'])
1316
            self._pg.gen_laserchannel_ComboBox.setCurrentIndex(index)
1317
        if 'sync_channel' in settings_dict:
1318
            index = self._pg.gen_syncchannel_ComboBox.findText(settings_dict['sync_channel'])
1319
            self._pg.gen_syncchannel_ComboBox.setCurrentIndex(index)
1320
        if 'gate_channel' in settings_dict:
1321
            index = self._pg.gen_gatechannel_ComboBox.findText(settings_dict['gate_channel'])
1322
            self._pg.gen_gatechannel_ComboBox.setCurrentIndex(index)
1323
        if hasattr(self, '_channel_selection_comboboxes'):
1324
            for combobox in self._channel_selection_comboboxes:
1325
                param_name = combobox.objectName()[13:]
1326
                if param_name in settings_dict:
1327
                    combobox.blockSignals(True)
1328
                    index = combobox.findText(settings_dict[param_name])
1329
                    combobox.setCurrentIndex(index)
1330
                    combobox.blockSignals(False)
1331
        if hasattr(self, '_global_param_widgets'):
1332
            for widget in self._global_param_widgets:
1333
                param_name = widget.objectName()[13:]
1334
                if param_name in settings_dict:
1335
                    widget.blockSignals(True)
1336
                    if hasattr(widget, 'setChecked'):
1337
                        widget.setChecked(settings_dict[param_name])
1338
                    elif hasattr(widget, 'setValue'):
1339
                        widget.setValue(settings_dict[param_name])
1340
                    elif hasattr(widget, 'setText'):
1341
                        widget.setText(settings_dict[param_name])
1342
                    widget.blockSignals(False)
1343
1344
        # unblock signals
1345
        self._pg.gen_laserchannel_ComboBox.blockSignals(False)
1346
        self._pg.gen_syncchannel_ComboBox.blockSignals(False)
1347
        self._pg.gen_gatechannel_ComboBox.blockSignals(False)
1348
        return
1349
1350
    @QtCore.Slot()
1351
    def block_add_last_clicked(self):
1352
        """
1353
1354
        @return:
1355
        """
1356
        self._pg.block_editor.add_elements(1, self._pg.block_editor.rowCount())
1357
        return
1358
1359
    @QtCore.Slot()
1360
    def block_del_last_clicked(self):
1361
        """
1362
1363
        @return:
1364
        """
1365
        self._pg.block_editor.remove_elements(1, self._pg.block_editor.rowCount() - 1)
1366
        return
1367
1368
    @QtCore.Slot()
1369
    def block_add_sel_clicked(self):
1370
        """
1371
1372
        @return:
1373
        """
1374
        index = self._pg.block_editor.currentRow()
1375
        self._pg.block_editor.add_elements(1, index + 1)
1376
        return
1377
1378
    @QtCore.Slot()
1379
    def block_del_sel_clicked(self):
1380
        """
1381
1382
        @return:
1383
        """
1384
        index = self._pg.block_editor.currentRow()
1385
        self._pg.block_editor.remove_elements(1, index)
1386
        return
1387
1388
    @QtCore.Slot()
1389
    def block_clear_clicked(self):
1390
        """
1391
1392
        @return:
1393
        """
1394
        self._pg.block_editor.clear()
1395
        return
1396
1397
    @QtCore.Slot()
1398
    def organizer_add_last_clicked(self):
1399
        """
1400
1401
        @return:
1402
        """
1403
        self._pg.block_organizer.add_blocks(1, self._pg.block_organizer.rowCount())
1404
        return
1405
1406
    @QtCore.Slot()
1407
    def organizer_del_last_clicked(self):
1408
        """
1409
1410
        @return:
1411
        """
1412
        self._pg.block_organizer.remove_blocks(1, self._pg.block_organizer.rowCount() - 1)
1413
        return
1414
1415
    @QtCore.Slot()
1416
    def organizer_add_sel_clicked(self):
1417
        """
1418
1419
        @return:
1420
        """
1421
        index = self._pg.block_organizer.currentRow()
1422
        self._pg.block_organizer.add_blocks(1, index + 1)
1423
        return
1424
1425
    @QtCore.Slot()
1426
    def organizer_del_sel_clicked(self):
1427
        """
1428
1429
        @return:
1430
        """
1431
        index = self._pg.block_organizer.currentRow()
1432
        self._pg.block_organizer.remove_blocks(1, index)
1433
        return
1434
1435
    @QtCore.Slot()
1436
    def organizer_clear_clicked(self):
1437
        """
1438
1439
        @return:
1440
        """
1441
        self._pg.block_organizer.clear()
1442
        return
1443
1444
    @QtCore.Slot()
1445
    def editor_generate_block_clicked(self):
1446
        name = self._pg.curr_block_name_LineEdit.text()
1447
        if not name:
1448
            self.log.error('No name has been entered for the PulseBlock to be generated.')
1449
            return
1450
        block_object = self._pg.block_editor.get_block()
1451
        block_object.name = name
1452
        self.pulsedmasterlogic().save_pulse_block(block_object)
1453
        return
1454
1455
    @QtCore.Slot()
1456
    def editor_delete_block_clicked(self):
1457
        name = self._pg.saved_blocks_ComboBox.currentText()
1458
        self.pulsedmasterlogic().delete_pulse_block(name)
1459
        return
1460
1461
    @QtCore.Slot()
1462
    def editor_load_block_clicked(self):
1463
        name = self._pg.saved_blocks_ComboBox.currentText()
1464
        block = self.pulsedmasterlogic().saved_pulse_blocks[name]
1465
1466
        # Do not load PulseBlock into editor if channel activations do not match
1467
        current_channels = self.pulsedmasterlogic().pulse_generator_settings['activation_config'][1]
1468
        if block.channel_set != current_channels:
1469
            self.log.error('Can not load PulseBlock "{0}" into editor.\nCurrent channel activation '
1470
                           '"{1}" does not match channel activation "{2}" used during generation '
1471
                           'of PulseBlock to load.'
1472
                           ''.format(name, current_channels, block.channel_set))
1473
            return
1474
1475
        self._pg.block_editor.load_block(block)
1476
        self._pg.curr_block_name_LineEdit.setText(name)
1477
        return
1478
1479
    @QtCore.Slot()
1480
    def editor_generate_ensemble_clicked(self):
1481
        name = self._pg.curr_ensemble_name_LineEdit.text()
1482
        if not name:
1483
            self.log.error('No name has been entered for the PulseBlockEnsemble to be generated.')
1484
            return
1485
        rotating_frame = self._pg.curr_ensemble_rot_frame_CheckBox.isChecked()
1486
        self._pg.block_organizer.set_rotating_frame(rotating_frame)
1487
        ensemble_object = self._pg.block_organizer.get_ensemble()
1488
        ensemble_object.name = name
1489
        self.pulsedmasterlogic().save_block_ensemble(ensemble_object)
1490
        length_s, length_bins, lasers = self.pulsedmasterlogic().get_ensemble_info(ensemble_object)
1491
        self._pg.curr_ensemble_length_DSpinBox.setValue(length_s)
1492
        self._pg.curr_ensemble_bins_SpinBox.setValue(length_bins)
1493
        self._pg.curr_ensemble_laserpulses_SpinBox.setValue(lasers)
1494
        return
1495
1496
    @QtCore.Slot()
1497
    def editor_delete_ensemble_clicked(self):
1498
        name = self._pg.saved_ensembles_ComboBox.currentText()
1499
        self.pulsedmasterlogic().delete_block_ensemble(name)
1500
        return
1501
1502
    @QtCore.Slot()
1503
    def editor_load_ensemble_clicked(self):
1504
        name = self._pg.saved_ensembles_ComboBox.currentText()
1505
        ensemble = self.pulsedmasterlogic().saved_pulse_block_ensembles[name]
1506
        self._pg.block_organizer.load_ensemble(ensemble)
1507
        self._pg.curr_ensemble_name_LineEdit.setText(name)
1508
        self._pg.curr_ensemble_rot_frame_CheckBox.setChecked(ensemble.rotating_frame)
1509
1510
        length_s, length_bins, lasers = self.pulsedmasterlogic().get_ensemble_info(ensemble)
1511
        self._pg.curr_ensemble_length_DSpinBox.setValue(length_s)
1512
        self._pg.curr_ensemble_bins_SpinBox.setValue(length_bins)
1513
        self._pg.curr_ensemble_laserpulses_SpinBox.setValue(lasers)
1514
        return
1515
1516
    @QtCore.Slot(dict)
1517
    def update_block_dict(self, block_dict):
1518
        """
1519
1520
        @param block_dict:
1521
        @return:
1522
        """
1523
        block_names = sorted(list(block_dict))
1524
        # Check if a block has been added. In that case set the current index to the new one.
1525
        # In all other cases try to maintain the current item and if it was removed, set the first.
1526
        text_to_set = None
1527
        if len(block_names) == self._pg.saved_blocks_ComboBox.count() + 1:
1528
            for name in block_names:
1529
                if self._pg.saved_blocks_ComboBox.findText(name) < 0:
1530
                    text_to_set = name
1531
        if text_to_set is None:
1532
            text_to_set = self._pg.saved_blocks_ComboBox.currentText()
1533
1534
        self._pg.block_organizer.set_available_pulse_blocks(block_names)
1535
        self._pg.saved_blocks_ComboBox.blockSignals(True)
1536
        self._pg.saved_blocks_ComboBox.clear()
1537
        self._pg.saved_blocks_ComboBox.addItems(block_names)
1538
        index = self._pg.saved_blocks_ComboBox.findText(text_to_set)
1539
        if index >= 0:
1540
            self._pg.saved_blocks_ComboBox.setCurrentIndex(index)
1541
        self._pg.block_organizer.set_available_pulse_blocks(block_names)
1542
        self._pg.saved_blocks_ComboBox.blockSignals(False)
1543
        return
1544
1545
    @QtCore.Slot(dict)
1546
    def update_ensemble_dict(self, ensemble_dict):
1547
        """
1548
1549
        @param ensemble_dict:
1550
        @return:
1551
        """
1552
        ensemble_names = sorted(ensemble_dict)
1553
        # Check if an ensemble has been added. In that case set the current index to the new one.
1554
        # In all other cases try to maintain the current item and if it was removed, set the first.
1555
        text_to_set = None
1556
        if len(ensemble_names) == self._pg.gen_ensemble_ComboBox.count() + 1:
1557
            for name in ensemble_names:
1558
                if self._pg.gen_ensemble_ComboBox.findText(name) < 0:
1559
                    text_to_set = name
1560
        if text_to_set is None:
1561
            text_to_set = self._pg.gen_ensemble_ComboBox.currentText()
1562
1563
        self._sg.sequence_editor.set_available_block_ensembles(ensemble_names)
1564
        # block signals
1565
        self._pg.gen_ensemble_ComboBox.blockSignals(True)
1566
        self._pg.saved_ensembles_ComboBox.blockSignals(True)
1567
        # update gen_sequence_ComboBox items
1568
        self._pg.gen_ensemble_ComboBox.clear()
1569
        self._pg.gen_ensemble_ComboBox.addItems(ensemble_names)
1570
        self._pg.saved_ensembles_ComboBox.clear()
1571
        self._pg.saved_ensembles_ComboBox.addItems(ensemble_names)
1572
        index = self._pg.gen_ensemble_ComboBox.findText(text_to_set)
1573
        if index >= 0:
1574
            self._pg.gen_ensemble_ComboBox.setCurrentIndex(index)
1575
            self._pg.saved_ensembles_ComboBox.setCurrentIndex(index)
1576
        self._sg.sequence_editor.set_available_block_ensembles(ensemble_names)
1577
        # unblock signals
1578
        self._pg.gen_ensemble_ComboBox.blockSignals(False)
1579
        self._pg.saved_ensembles_ComboBox.blockSignals(False)
1580
        return
1581
1582
    @QtCore.Slot()
1583
    def sample_ensemble_clicked(self):
1584
        """
1585
        This method is called when the user clicks on "Sample Ensemble"
1586
        """
1587
        # disable buttons
1588
        self._pg.sample_ensemble_PushButton.setEnabled(False)
1589
        self._pg.samplo_ensemble_PushButton.setEnabled(False)
1590
        # Get the ensemble name from the ComboBox
1591
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
1592
        # Sample and upload the ensemble via logic module
1593
        self.pulsedmasterlogic().sample_ensemble(ensemble_name, False)
1594
        return
1595
1596
    @QtCore.Slot(object)
1597
    def sample_ensemble_finished(self, ensemble):
1598
        """
1599
        This method
1600
        """
1601
        # enable buttons
1602
        if not self.pulsedmasterlogic().status_dict['sampload_busy']:
1603
            self._pg.sample_ensemble_PushButton.setEnabled(True)
1604
            self._pg.samplo_ensemble_PushButton.setEnabled(True)
1605
        return
1606
1607
    @QtCore.Slot()
1608
    def samplo_ensemble_clicked(self):
1609
        """
1610
        This method is called when the user clicks on "Sample + Load Ensemble"
1611
        """
1612
        # disable buttons
1613
        self._pg.sample_ensemble_PushButton.setEnabled(False)
1614
        self._pg.samplo_ensemble_PushButton.setEnabled(False)
1615
        self._pg.load_ensemble_PushButton.setEnabled(False)
1616
        # Get the ensemble name from the ComboBox
1617
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
1618
        # Sample, upload and load the ensemble via logic module
1619
        self.pulsedmasterlogic().sample_ensemble(ensemble_name, True)
1620
        return
1621
1622
    @QtCore.Slot()
1623
    def load_ensemble_clicked(self):
1624
        """
1625
        This method
1626
        """
1627
        # disable button
1628
        self._pg.load_ensemble_PushButton.setEnabled(False)
1629
        # Get the ensemble name to be loaded from the ComboBox
1630
        ensemble_name = self._pg.gen_ensemble_ComboBox.currentText()
1631
        # Load ensemble into channles via logic module
1632
        self.pulsedmasterlogic().load_ensemble(ensemble_name)
1633
        return
1634
1635
    @QtCore.Slot(bool)
1636
    def generate_predefined_clicked(self, button_obj=None):
1637
        """
1638
1639
        @param button_obj:
1640
        @return:
1641
        """
1642
        if isinstance(button_obj, bool):
1643
            button_obj = self.sender()
1644
        method_name = button_obj.objectName()
1645
        if method_name.startswith('gen_'):
1646
            method_name = method_name[4:]
1647
        elif method_name.startswith('samplo_'):
1648
            method_name = method_name[7:]
1649
        else:
1650
            self.log.error('Strange naming of generate buttons in predefined methods occured.')
1651
            return
1652
1653
        # get parameters from input widgets
1654
        param_searchstr = method_name + '_param_'
1655
        param_widgets = [widget for widget in dir(self._pm) if widget.startswith(param_searchstr)]
1656
        # Store parameters together with the parameter names in a dictionary
1657
        param_dict = dict()
1658
        for widget_name in param_widgets:
1659
            input_obj = getattr(self._pm, widget_name)
1660
            param_name = widget_name.replace(param_searchstr, '').replace('_Widget', '')
1661
1662
            if hasattr(input_obj, 'isChecked'):
1663
                param_dict[param_name] = input_obj.isChecked()
1664
            elif hasattr(input_obj, 'value'):
1665
                param_dict[param_name] = input_obj.value()
1666
            elif hasattr(input_obj, 'text'):
1667
                param_dict[param_name] = input_obj.text()
1668
            else:
1669
                self.log.error('Not possible to get the value from the widgets, since it does not '
1670
                               'have one of the possible access methods!')
1671
                return
1672
1673
        self.pulsedmasterlogic().generate_predefined_sequence(method_name, param_dict)
1674
        return
1675
1676
    @QtCore.Slot()
1677
    def samplo_predefined_clicked(self):
1678
        button_obj = self.sender()
1679
        method_name = button_obj.objectName()[7:]
1680
        self.generate_predefined_clicked(button_obj)
1681
        # get name of the generated ensemble
1682
        if not hasattr(self._pm, method_name + '_param_name_Widget'):
1683
            self.log.error('Predefined sequence methods must have an argument called "name" in '
1684
                           'order to use the sample/upload/load functionality. It must be the '
1685
                           'naming of the generated asset.\n"{0}" has probably been generated '
1686
                           'but not sampled/uploaded/loaded'.format(method_name))
1687
            return
1688
        input_obj = getattr(self._pm, method_name + '_param_name_Widget')
1689
        if not hasattr(input_obj, 'text'):
1690
            self.log.error('Predefined sequence methods must have as first argument the name of '
1691
                           'the asset to be generated.')
1692
            return
1693
        asset_name = input_obj.text()
1694
1695
        # disable buttons
1696
        self._pg.sample_ensemble_PushButton.setEnabled(False)
1697
        self._pg.samplo_ensemble_PushButton.setEnabled(False)
1698
        self._pg.load_ensemble_PushButton.setEnabled(False)
1699
1700
        self.pulsedmasterlogic().sample_ensemble(asset_name, True)
1701
        return
1702
1703
    @QtCore.Slot(list)
1704
    def waveform_list_updated(self, waveform_list):
1705
        """
1706
1707
        @param list waveform_list:
1708
        """
1709
        # TODO: This method will be needed later on to implement an upload center
1710
        pass
1711
1712
    ###########################################################################
1713
    #                   Sequence Generator tab related methods                #
1714
    ###########################################################################
1715
    def _activate_sequence_generator_ui(self):
1716
        self.update_sequence_dict(self.pulsedmasterlogic().saved_pulse_sequences)
1717
        self._sg.curr_sequence_length_DSpinBox.setRange(0, np.inf)
1718
        pulser_constr = self.pulsedmasterlogic().pulse_generator_constraints
1719
        self._sg.sequence_editor.set_available_triggers(pulser_constr.event_triggers)
1720
        self._sg.sequence_editor.set_available_flags(pulser_constr.flags)
1721
        return
1722
1723
    def _deactivate_sequence_generator_ui(self):
1724
        pass
1725
1726
    @QtCore.Slot()
1727
    def sequence_add_last_clicked(self):
1728
        """
1729
1730
        @return:
1731
        """
1732
        self._sg.sequence_editor.add_steps(1, self._sg.sequence_editor.rowCount())
1733
        return
1734
1735
    @QtCore.Slot()
1736
    def sequence_del_last_clicked(self):
1737
        """
1738
1739
        @return:
1740
        """
1741
        self._sg.sequence_editor.remove_steps(1, self._sg.sequence_editor.rowCount() - 1)
1742
        return
1743
1744
    @QtCore.Slot()
1745
    def sequence_add_sel_clicked(self):
1746
        """
1747
1748
        @return:
1749
        """
1750
        index = self._sg.sequence_editor.currentRow()
1751
        self._sg.sequence_editor.add_steps(1, index + 1)
1752
        return
1753
1754
    @QtCore.Slot()
1755
    def sequence_del_sel_clicked(self):
1756
        """
1757
1758
        @return:
1759
        """
1760
        index = self._sg.sequence_editor.currentRow()
1761
        self._sg.sequence_editor.remove_steps(1, index)
1762
        return
1763
1764
    @QtCore.Slot()
1765
    def sequence_clear_clicked(self):
1766
        """
1767
1768
        @return:
1769
        """
1770
        self._sg.sequence_editor.clear()
1771
        return
1772
1773
    @QtCore.Slot()
1774
    def editor_generate_sequence_clicked(self):
1775
        name = self._sg.curr_sequence_name_LineEdit.text()
1776
        if not name:
1777
            self.log.error('No name has been entered for the PulseSequence to be generated.')
1778
            return
1779
        rotating_frame = self._sg.curr_sequence_rot_frame_CheckBox.isChecked()
1780
        self._sg.sequence_editor.set_rotating_frame(rotating_frame)
1781
        sequence_object = self._sg.sequence_editor.get_sequence()
1782
        sequence_object.name = name
1783
        self.pulsedmasterlogic().save_sequence(sequence_object)
1784
        length_s, length_bins, lasers = self.pulsedmasterlogic().get_sequence_info(sequence_object)
1785
        self._sg.curr_sequence_length_DSpinBox.setValue(length_s)
1786
        self._sg.curr_sequence_bins_SpinBox.setValue(length_bins)
1787
        self._sg.curr_sequence_laserpulses_SpinBox.setValue(lasers)
1788
        return
1789
1790
    @QtCore.Slot()
1791
    def editor_delete_sequence_clicked(self):
1792
        name = self._sg.saved_sequences_ComboBox.currentText()
1793
        self.pulsedmasterlogic().delete_sequence(name)
1794
        return
1795
1796
    @QtCore.Slot()
1797
    def editor_load_sequence_clicked(self):
1798
        name = self._sg.saved_sequences_ComboBox.currentText()
1799
        sequence = self.pulsedmasterlogic().saved_pulse_sequences[name]
1800
        self._sg.sequence_editor.load_sequence(sequence)
1801
        self._sg.curr_sequence_name_LineEdit.setText(name)
1802
        self._sg.curr_sequence_rot_frame_CheckBox.setChecked(sequence.rotating_frame)
1803
1804
        length_s, length_bins, lasers = self.pulsedmasterlogic().get_sequence_info(sequence)
1805
        self._sg.curr_sequence_length_DSpinBox.setValue(length_s)
1806
        self._sg.curr_sequence_bins_SpinBox.setValue(length_bins)
1807
        self._sg.curr_sequence_laserpulses_SpinBox.setValue(lasers)
1808
        return
1809
1810
    @QtCore.Slot(dict)
1811
    def update_sequence_dict(self, sequence_dict):
1812
        """
1813
1814
        @param sequence_dict:
1815
        @return:
1816
        """
1817
        sequence_names = sorted(list(sequence_dict))
1818
        # Check if a sequence has been added. In that case set the current index to the new one.
1819
        # In all other cases try to maintain the current item and if it was removed, set the first.
1820
        text_to_set = None
1821
        if len(sequence_names) == self._sg.gen_sequence_ComboBox.count() + 1:
1822
            for name in sequence_names:
1823
                if self._sg.gen_sequence_ComboBox.findText(name) == -1:
1824
                    text_to_set = name
1825
        if text_to_set is None:
1826
            text_to_set = self._sg.gen_sequence_ComboBox.currentText()
1827
1828
        # block signals
1829
        self._sg.gen_sequence_ComboBox.blockSignals(True)
1830
        self._sg.saved_sequences_ComboBox.blockSignals(True)
1831
        # update gen_sequence_ComboBox items
1832
        self._sg.gen_sequence_ComboBox.clear()
1833
        self._sg.gen_sequence_ComboBox.addItems(sequence_names)
1834
        self._sg.saved_sequences_ComboBox.clear()
1835
        self._sg.saved_sequences_ComboBox.addItems(sequence_names)
1836
        index = self._sg.gen_sequence_ComboBox.findText(text_to_set)
1837
        if index >= 0:
1838
            self._sg.gen_sequence_ComboBox.setCurrentIndex(index)
1839
            self._sg.saved_sequences_ComboBox.setCurrentIndex(index)
1840
        # unblock signals
1841
        self._sg.gen_sequence_ComboBox.blockSignals(False)
1842
        self._sg.saved_sequences_ComboBox.blockSignals(False)
1843
        return
1844
1845
    @QtCore.Slot()
1846
    def sample_sequence_clicked(self):
1847
        """
1848
        This method is called when the user clicks on "Sample + Upload Sequence"
1849
        """
1850
        # disable buttons
1851
        self._sg.sample_sequence_PushButton.setEnabled(False)
1852
        self._sg.samplo_sequence_PushButton.setEnabled(False)
1853
        # Get the sequence name from the ComboBox
1854
        sequence_name = self._sg.gen_sequence_ComboBox.currentText()
1855
        # Sample the sequence via logic module
1856
        self.pulsedmasterlogic().sample_sequence(sequence_name, False)
1857
        return
1858
1859
    @QtCore.Slot(object)
1860
    def sample_sequence_finished(self, sequence):
1861
        """
1862
        This method
1863
        """
1864
        # enable buttons
1865
        if not self.pulsedmasterlogic().status_dict['sampload_busy']:
1866
            self._sg.sample_sequence_PushButton.setEnabled(True)
1867
            self._sg.samplo_sequence_PushButton.setEnabled(True)
1868
        return
1869
1870
    @QtCore.Slot()
1871
    def samplo_sequence_clicked(self):
1872
        """
1873
        This method is called when the user clicks on "Sample + Load Sequence"
1874
        """
1875
        # disable buttons
1876
        self._sg.sample_sequence_PushButton.setEnabled(False)
1877
        self._sg.samplo_sequence_PushButton.setEnabled(False)
1878
        self._sg.load_sequence_PushButton.setEnabled(False)
1879
        # Get the sequence name from the ComboBox
1880
        sequence_name = self._sg.gen_sequence_ComboBox.currentText()
1881
        # Sample the sequence via logic module
1882
        self.pulsedmasterlogic().sample_sequence(sequence_name, True)
1883
        return
1884
1885
    @QtCore.Slot()
1886
    def load_sequence_clicked(self):
1887
        """
1888
        This method
1889
        """
1890
        # disable button
1891
        self._sg.load_sequence_PushButton.setEnabled(False)
1892
        # Get the sequence name to be loaded from the ComboBox
1893
        sequence_name = self._sg.gen_sequence_ComboBox.currentText()
1894
        # Load sequence into channles via logic module
1895
        self.pulsedmasterlogic().load_sequence(sequence_name)
1896
        return
1897
1898
    @QtCore.Slot(list)
1899
    def sequence_list_updated(self, sequence_list):
1900
        """
1901
1902
        @param list sequence_list:
1903
        """
1904
        # TODO: This method will be needed later on to implement an upload center
1905
        pass
1906
1907
    ###########################################################################
1908
    #                      Analysis tab related methods                       #
1909
    ###########################################################################
1910
    def _activate_analysis_ui(self):
1911
        """ Initialize, connect and configure the 'Analysis' Tab.
1912
        """
1913
        # Configure the main pulse analysis display:
1914
        self.signal_image = pg.PlotDataItem(pen=pg.mkPen(palette.c1, style=QtCore.Qt.DotLine),
1915
                                            style=QtCore.Qt.DotLine,
1916
                                            symbol='o',
1917
                                            symbolPen=palette.c1,
1918
                                            symbolBrush=palette.c1,
1919
                                            symbolSize=7)
1920
        self.signal_image2 = pg.PlotDataItem(pen=pg.mkPen(palette.c4, style=QtCore.Qt.DotLine),
1921
                                             style=QtCore.Qt.DotLine,
1922
                                             symbol='o',
1923
                                             symbolPen=palette.c4,
1924
                                             symbolBrush=palette.c4,
1925
                                             symbolSize=7)
1926
        self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image)
1927
        self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image2)
1928
        self._pa.pulse_analysis_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
1929
1930
        # Configure the fit of the data in the main pulse analysis display:
1931
        self.fit_image = pg.PlotDataItem(pen=palette.c3)
1932
        self._pa.pulse_analysis_PlotWidget.addItem(self.fit_image)
1933
1934
        # Configure the errorbars of the data in the main pulse analysis display:
1935
        self.signal_image_error_bars = pg.ErrorBarItem(x=np.arange(10),
1936
                                                       y=np.zeros(10),
1937
                                                       top=0.,
1938
                                                       bottom=0.,
1939
                                                       pen=palette.c2)
1940
        self.signal_image_error_bars2 = pg.ErrorBarItem(x=np.arange(10),
1941
                                                        y=np.zeros(10),
1942
                                                        top=0.,
1943
                                                        bottom=0.,
1944
                                                        pen=palette.c5)
1945
1946
        # Configure the second pulse analysis plot display:
1947
        self.second_plot_image = pg.PlotDataItem(np.arange(10), np.zeros(10), pen=palette.c1)
1948
        self.second_plot_image2 = pg.PlotDataItem(pen=palette.c4)
1949
        self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image)
1950
        self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image2)
1951
        self._pa.pulse_analysis_second_PlotWidget.showGrid(x=True, y=True, alpha=0.8)
1952
1953
        # Fit settings dialog
1954
        self._fsd = FitSettingsDialog(self.pulsedmasterlogic().fit_container)
1955
        self._fsd.applySettings()
1956
        self._pa.fit_param_fit_func_ComboBox.setFitFunctions(self._fsd.currentFits)
1957
1958
        # set boundaries
1959
        self._pa.ana_param_num_laser_pulse_SpinBox.setMinimum(1)
1960
        self._pa.ana_param_record_length_DoubleSpinBox.setMinimum(0)
1961
        self._pa.time_param_ana_periode_DoubleSpinBox.setMinimum(0)
1962
        self._pa.time_param_ana_periode_DoubleSpinBox.setMinimalStep(1)
1963
        self._pa.ext_control_mw_freq_DoubleSpinBox.setMinimum(0)
1964
1965
        # apply hardware constraints
1966
        self._pa_apply_hardware_constraints()
1967
1968
        # Recall StatusVars into widgets
1969
        self._pa.ana_param_errorbars_CheckBox.blockSignals(True)
1970
        self._pa.ana_param_errorbars_CheckBox.setChecked(self._ana_param_errorbars)
1971
        self._pa.ana_param_errorbars_CheckBox.blockSignals(False)
1972
        self.second_plot_changed(self.pulsedmasterlogic().alternative_data_type)
1973
        self._pa.ana_param_delta_CheckBox.setEnabled(False)  # FIXME: non-functional CheckBox
1974
1975
        # Update measurement, microwave and fast counter settings from logic
1976
        self.measurement_settings_updated(self.pulsedmasterlogic().measurement_settings)
1977
        self.fast_counter_settings_updated(self.pulsedmasterlogic().fast_counter_settings)
1978
        self.microwave_settings_updated(self.pulsedmasterlogic().ext_microwave_settings)
1979
        # Update analysis interval from logic
1980
        self._pa.time_param_ana_periode_DoubleSpinBox.setValue(
1981
            self.pulsedmasterlogic().timer_interval)
1982
1983
        self.toggle_error_bars(self._ana_param_errorbars)
1984
        self.second_plot_changed(self.pulsedmasterlogic().alternative_data_type)
1985
        self.measurement_data_updated()
1986
        return
1987
1988
    def _deactivate_analysis_ui(self):
1989
        """ Disconnects the configuration for 'Analysis' Tab.
1990
        """
1991
        self._ana_param_errorbars = self._pa.ana_param_errorbars_CheckBox.isChecked()
1992
        return
1993
1994
    def _pa_apply_hardware_constraints(self):
1995
        """
1996
        Retrieve the constraints from pulser and fast counter hardware and apply these constraints
1997
        to the analysis tab GUI elements.
1998
        """
1999
        mw_constraints = self.pulsedmasterlogic().ext_microwave_constraints
2000
        fc_constraints = self.pulsedmasterlogic().fast_counter_constraints
2001
        # block signals
2002
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(True)
2003
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(True)
2004
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(True)
2005
        # apply constraints
2006
        self._pa.ext_control_mw_freq_DoubleSpinBox.setRange(mw_constraints.min_frequency,
2007
                                                            mw_constraints.max_frequency)
2008
        self._pa.ext_control_mw_power_DoubleSpinBox.setRange(mw_constraints.min_power,
2009
                                                             mw_constraints.max_power)
2010
        self._pa.ana_param_fc_bins_ComboBox.clear()
2011
        for binwidth in fc_constraints['hardware_binwidth_list']:
2012
            self._pa.ana_param_fc_bins_ComboBox.addItem(str(binwidth))
2013
        # unblock signals
2014
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(False)
2015
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(False)
2016
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(False)
2017
        return
2018
2019
    @QtCore.Slot()
2020
    def measurement_data_updated(self):
2021
        """
2022
2023
        @return:
2024
        """
2025
        signal_data = self.pulsedmasterlogic().signal_data
2026
        signal_alt_data = self.pulsedmasterlogic().signal_alt_data
2027
        measurement_error = self.pulsedmasterlogic().measurement_error
2028
2029
        # Adjust number of data sets to plot
2030
        self.set_plot_dimensions()
2031
2032
        # Change second plot combobox if it has been changed in the logic
2033
        self.second_plot_changed(self.pulsedmasterlogic().alternative_data_type)
2034
2035
        # create ErrorBarItems
2036
        tmp_array = signal_data[0, 1:] - signal_data[0, :-1]
2037
        beamwidth = tmp_array.min() if tmp_array.min() > 0 else tmp_array.max()
2038
        del tmp_array
2039
        beamwidth /= 3
2040
        self.signal_image_error_bars.setData(x=signal_data[0],
2041
                                             y=signal_data[1],
2042
                                             top=measurement_error[1],
2043
                                             bottom=measurement_error[1],
2044
                                             beam=beamwidth)
2045
        if signal_data.shape[0] > 2 and measurement_error.shape[0] > 2:
2046
            self.signal_image_error_bars2.setData(x=signal_data[0],
2047
                                                  y=signal_data[2],
2048
                                                  top=measurement_error[2],
2049
                                                  bottom=measurement_error[2],
2050
                                                  beam=beamwidth)
2051
2052
        # dealing with the actual signal plot
2053
        self.signal_image.setData(x=signal_data[0], y=signal_data[1])
2054
        if signal_data.shape[0] > 2:
2055
            self.signal_image2.setData(x=signal_data[0], y=signal_data[2])
2056
2057
        # dealing with the secondary plot
2058
        self.second_plot_image.setData(x=signal_alt_data[0], y=signal_alt_data[1])
2059
        if signal_alt_data.shape[0] > 2:
2060
            self.second_plot_image2.setData(x=signal_alt_data[0], y=signal_alt_data[2])
2061
2062
        # dealing with the error plot
2063
        self.measuring_error_image.setData(x=measurement_error[0], y=measurement_error[1])
2064
        if measurement_error.shape[0] > 2:
2065
            self.measuring_error_image2.setData(x=measurement_error[0], y=measurement_error[2])
2066
2067
        # dealing with the laser plot
2068
        self.update_laser_data()
2069
        return
2070
2071
    @QtCore.Slot()
2072
    def fit_clicked(self):
2073
        """Fits the current data"""
2074
        current_fit_method = self._pa.fit_param_fit_func_ComboBox.getCurrentFit()[0]
2075
        self.pulsedmasterlogic().do_fit(current_fit_method)
2076
        return
2077
2078
    @QtCore.Slot(str, np.ndarray, object)
2079
    def fit_data_updated(self, fit_method, fit_data, result):
2080
        """
2081
2082
        @param fit_method:
2083
        @param fit_data:
2084
        @param result:
2085
        @return:
2086
        """
2087
        # block signals
2088
        self._pa.fit_param_fit_func_ComboBox.blockSignals(True)
2089
        # set widgets
2090
        self._pa.fit_param_results_TextBrowser.clear()
2091
        if fit_method == 'No Fit':
2092
            formatted_fitresult = 'No Fit'
2093
        else:
2094
            try:
2095
                formatted_fitresult = units.create_formatted_output(result.result_str_dict)
2096
            except:
2097
                formatted_fitresult = 'This fit does not return formatted results'
2098
        self._pa.fit_param_results_TextBrowser.setPlainText(formatted_fitresult)
2099
2100
        self.fit_image.setData(x=fit_data[0], y=fit_data[1])
2101
        if fit_method == 'No Fit' and self.fit_image in self._pa.pulse_analysis_PlotWidget.items():
2102
            self._pa.pulse_analysis_PlotWidget.removeItem(self.fit_image)
2103
        elif fit_method != 'No Fit' and self.fit_image not in self._pa.pulse_analysis_PlotWidget.items():
2104
            self._pa.pulse_analysis_PlotWidget.addItem(self.fit_image)
2105
        if fit_method:
2106
            self._pa.fit_param_fit_func_ComboBox.setCurrentFit(fit_method)
2107
        # unblock signals
2108
        self._pa.fit_param_fit_func_ComboBox.blockSignals(False)
2109
        return
2110
2111
    @QtCore.Slot()
2112
    def microwave_settings_changed(self):
2113
        """ Shows or hides input widgets which are necessary if an external mw is turned on"""
2114
        if self._mw.action_run_stop.isChecked():
2115
            return
2116
2117
        use_ext_microwave = self._pa.ext_control_use_mw_CheckBox.isChecked()
2118
2119
        settings_dict = dict()
2120
        settings_dict['use_ext_microwave'] = use_ext_microwave
2121
        settings_dict['frequency'] = self._pa.ext_control_mw_freq_DoubleSpinBox.value()
2122
        settings_dict['power'] = self._pa.ext_control_mw_power_DoubleSpinBox.value()
2123
2124 View Code Duplication
        if use_ext_microwave and not self._pa.ext_control_mw_freq_DoubleSpinBox.isVisible():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2125
            self._pa.ext_control_mw_freq_Label.setVisible(True)
2126
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(True)
2127
            self._pa.ext_control_mw_power_Label.setVisible(True)
2128
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(True)
2129
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
2130
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
2131
        elif not use_ext_microwave and self._pa.ext_control_mw_freq_DoubleSpinBox.isVisible():
2132
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
2133
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
2134
            self._pa.ext_control_mw_freq_Label.setVisible(False)
2135
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(False)
2136
            self._pa.ext_control_mw_power_Label.setVisible(False)
2137
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(False)
2138
2139
        self.pulsedmasterlogic().set_ext_microwave_settings(settings_dict)
2140
        return
2141
2142
    @QtCore.Slot(dict)
2143
    def microwave_settings_updated(self, settings_dict):
2144
        """
2145
2146
        @param dict settings_dict:
2147
        """
2148
        # block signals
2149
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(True)
2150
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(True)
2151
        self._pa.ext_control_use_mw_CheckBox.blockSignals(True)
2152
2153
        if 'use_ext_microwave' in settings_dict:
2154
            use_ext_microwave = settings_dict['use_ext_microwave']
2155
            self._pa.ext_control_use_mw_CheckBox.setChecked(use_ext_microwave)
2156
            # Set visibility
2157
            self.toggle_microwave_settings_editor(settings_dict['use_ext_microwave'])
2158
        if 'frequency' in settings_dict:
2159
            self._pa.ext_control_mw_freq_DoubleSpinBox.setValue(settings_dict['frequency'])
2160
        if 'power' in settings_dict:
2161
            self._pa.ext_control_mw_power_DoubleSpinBox.setValue(settings_dict['power'])
2162
2163
        # unblock signals
2164
        self._pa.ext_control_mw_freq_DoubleSpinBox.blockSignals(False)
2165
        self._pa.ext_control_mw_power_DoubleSpinBox.blockSignals(False)
2166
        self._pa.ext_control_use_mw_CheckBox.blockSignals(False)
2167
        return
2168
2169
    def toggle_microwave_settings_editor(self, show_editor):
2170
        """
2171
2172
        @param show_editor:
2173
        @return:
2174
        """
2175 View Code Duplication
        if show_editor:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2176
            self._pa.ext_control_mw_freq_Label.setVisible(True)
2177
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(True)
2178
            self._pa.ext_control_mw_power_Label.setVisible(True)
2179
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(True)
2180
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(True)
2181
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(True)
2182
        else:
2183
            self._pa.ext_control_mw_freq_DoubleSpinBox.setEnabled(False)
2184
            self._pa.ext_control_mw_power_DoubleSpinBox.setEnabled(False)
2185
            self._pa.ext_control_mw_freq_Label.setVisible(False)
2186
            self._pa.ext_control_mw_freq_DoubleSpinBox.setVisible(False)
2187
            self._pa.ext_control_mw_power_Label.setVisible(False)
2188
            self._pa.ext_control_mw_power_DoubleSpinBox.setVisible(False)
2189
        return
2190
2191
    @QtCore.Slot(bool)
2192
    def microwave_running_updated(self, is_running):
2193
        """
2194
2195
        @return:
2196
        """
2197
        pass
2198
2199
    @QtCore.Slot()
2200
    def fast_counter_settings_changed(self):
2201
        """
2202
2203
        @return:
2204
        """
2205
        if self._mw.action_run_stop.isChecked():
2206
            return
2207
        settings_dict = dict()
2208
        settings_dict['record_length'] = self._pa.ana_param_record_length_DoubleSpinBox.value()
2209
        settings_dict['bin_width'] = float(self._pa.ana_param_fc_bins_ComboBox.currentText())
2210
        self.pulsedmasterlogic().set_fast_counter_settings(settings_dict)
2211
        return
2212
2213
    @QtCore.Slot(dict)
2214
    def fast_counter_settings_updated(self, settings_dict):
2215
        """
2216
2217
        @param dict settings_dict:
2218
        """
2219
        # block signals
2220
        self._pa.ana_param_record_length_DoubleSpinBox.blockSignals(True)
2221
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(True)
2222
        # set widgets
2223
        if 'record_length' in settings_dict:
2224
            self._pa.ana_param_record_length_DoubleSpinBox.setValue(settings_dict['record_length'])
2225
        if 'bin_width' in settings_dict:
2226
            index = self._pa.ana_param_fc_bins_ComboBox.findText(str(settings_dict['bin_width']))
2227
            self._pa.ana_param_fc_bins_ComboBox.setCurrentIndex(index)
2228
        if 'is_gated' in settings_dict:
2229
            if settings_dict.get('is_gated'):
2230
                self._pg.gen_gatechannel_ComboBox.setEnabled(True)
2231
            else:
2232
                self._pg.gen_gatechannel_ComboBox.setEnabled(False)
2233
                self.pulsedmasterlogic().set_generation_parameters(gate_channel='')
2234
2235
        # unblock signals
2236
        self._pa.ana_param_record_length_DoubleSpinBox.blockSignals(False)
2237
        self._pa.ana_param_fc_bins_ComboBox.blockSignals(False)
2238
        return
2239
2240
    @QtCore.Slot()
2241
    def measurement_settings_changed(self):
2242
        """
2243
2244
        @return:
2245
        """
2246
        # Do nothing if measurement is already running
2247
        if self._mw.action_run_stop.isChecked():
2248
            return
2249
2250
        settings_dict = dict()
2251
        settings_dict['invoke_settings'] = self._pa.ana_param_invoke_settings_CheckBox.isChecked()
2252
        settings_dict['laser_ignore_list'] = list()
2253
        if self._pa.ana_param_ignore_first_CheckBox.isChecked():
2254
            settings_dict['laser_ignore_list'].append(0)
2255
        if self._pa.ana_param_ignore_last_CheckBox.isChecked():
2256
            settings_dict['laser_ignore_list'].append(-1)
2257
        settings_dict['alternating'] = self._pa.ana_param_alternating_CheckBox.isChecked()
2258
        settings_dict['number_of_lasers'] = self._pa.ana_param_num_laser_pulse_SpinBox.value()
2259
        vals_start = self._pa.ana_param_x_axis_start_ScienDSpinBox.value()
2260
        vals_incr = self._pa.ana_param_x_axis_inc_ScienDSpinBox.value()
2261
        num_of_ticks = max(1, settings_dict['number_of_lasers'] - len(
2262
            settings_dict['laser_ignore_list']))
2263
        if settings_dict['alternating'] and num_of_ticks > 1:
2264
            num_of_ticks //= 2
2265
        controlled_variable = np.arange(num_of_ticks, dtype=float)
2266
        settings_dict['controlled_variable'] = controlled_variable * vals_incr + vals_start
2267
2268
        self.pulsedmasterlogic().set_measurement_settings(settings_dict)
2269
        return
2270
2271
    @QtCore.Slot(dict)
2272
    def measurement_settings_updated(self, settings_dict):
2273
        """
2274
2275
        @param dict settings_dict:
2276
        """
2277
        # block signals
2278
        self._pa.ana_param_ignore_first_CheckBox.blockSignals(True)
2279
        self._pa.ana_param_ignore_last_CheckBox.blockSignals(True)
2280
        self._pa.ana_param_alternating_CheckBox.blockSignals(True)
2281
        self._pa.ana_param_num_laser_pulse_SpinBox.blockSignals(True)
2282
        self._pa.ana_param_x_axis_start_ScienDSpinBox.blockSignals(True)
2283
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.blockSignals(True)
2284
        self._pa.ana_param_invoke_settings_CheckBox.blockSignals(True)
2285
        self._pe.laserpulses_ComboBox.blockSignals(True)
2286
2287
        # set widgets
2288
        if 'number_of_lasers' in settings_dict:
2289
            self._pa.ana_param_num_laser_pulse_SpinBox.setValue(settings_dict['number_of_lasers'])
2290
            self._pe.laserpulses_ComboBox.clear()
2291
            self._pe.laserpulses_ComboBox.addItem('sum')
2292
            self._pe.laserpulses_ComboBox.addItems(
2293
                [str(i) for i in range(1, settings_dict['number_of_lasers'] + 1)])
2294
        if 'alternating' in settings_dict:
2295
            self._pa.ana_param_alternating_CheckBox.setChecked(settings_dict['alternating'])
2296
            # self.toggle_alternating_plots(settings_dict['alternating'])
2297
        if 'laser_ignore_list' in settings_dict:
2298
            self._pa.ana_param_ignore_first_CheckBox.setChecked(
2299
                0 in settings_dict['laser_ignore_list'])
2300
            if -1 in settings_dict['laser_ignore_list'] or self._pa.ana_param_num_laser_pulse_SpinBox.value() - 1 in settings_dict['laser_ignore_list']:
2301
                self._pa.ana_param_ignore_last_CheckBox.setChecked(True)
2302
            else:
2303
                self._pa.ana_param_ignore_last_CheckBox.setChecked(False)
2304
        if 'controlled_variable' in settings_dict:
2305
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setValue(
2306
                settings_dict['controlled_variable'][0])
2307
            if len(settings_dict['controlled_variable']) > 1:
2308
                self._pa.ana_param_x_axis_inc_ScienDSpinBox.setValue(
2309
                    settings_dict['controlled_variable'][1] - settings_dict['controlled_variable'][
2310
                        0])
2311
            else:
2312
                self._pa.ana_param_x_axis_inc_ScienDSpinBox.setValue(
2313
                    settings_dict['controlled_variable'][0])
2314
        if 'invoke_settings' in settings_dict:
2315
            self._pa.ana_param_invoke_settings_CheckBox.setChecked(settings_dict['invoke_settings'])
2316
            self.toggle_measurement_settings_editor(settings_dict['invoke_settings'])
2317
2318
        # unblock signals
2319
        self._pa.ana_param_ignore_first_CheckBox.blockSignals(False)
2320
        self._pa.ana_param_ignore_last_CheckBox.blockSignals(False)
2321
        self._pa.ana_param_alternating_CheckBox.blockSignals(False)
2322
        self._pa.ana_param_num_laser_pulse_SpinBox.blockSignals(False)
2323
        self._pa.ana_param_x_axis_start_ScienDSpinBox.blockSignals(False)
2324
        self._pa.ana_param_x_axis_inc_ScienDSpinBox.blockSignals(False)
2325
        self._pa.ana_param_invoke_settings_CheckBox.blockSignals(False)
2326
        self._pe.laserpulses_ComboBox.blockSignals(False)
2327
        return
2328
2329
    def set_plot_dimensions(self):
2330
        """
2331
2332
        @param alternating:
2333
        @return:
2334
        """
2335
        number_of_signals = self.pulsedmasterlogic().signal_data.shape[0] - 1
2336
        number_of_alt_signals = self.pulsedmasterlogic().signal_alt_data.shape[0] - 1
2337
2338
        if number_of_signals == 1:
2339
            if self.signal_image2 in self._pa.pulse_analysis_PlotWidget.items():
2340
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image2)
2341
            if self.signal_image_error_bars2 in self._pa.pulse_analysis_PlotWidget.items():
2342
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars2)
2343
            if self.measuring_error_image2 in self._pe.measuring_error_PlotWidget.items():
2344
                self._pe.measuring_error_PlotWidget.removeItem(self.measuring_error_image2)
2345
        else:
2346
            if self.signal_image2 not in self._pa.pulse_analysis_PlotWidget.items():
2347
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image2)
2348
            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():
2349
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
2350
            if self.measuring_error_image2 not in self._pe.measuring_error_PlotWidget.items():
2351
                self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image2)
2352
2353
        if number_of_alt_signals == 1:
2354
            if self.second_plot_image2 in self._pa.pulse_analysis_second_PlotWidget.items():
2355
                self._pa.pulse_analysis_second_PlotWidget.removeItem(self.second_plot_image2)
2356
        else:
2357
            if self.second_plot_image2 not in self._pa.pulse_analysis_second_PlotWidget.items():
2358
                self._pa.pulse_analysis_second_PlotWidget.addItem(self.second_plot_image2)
2359
        return
2360
2361
    def toggle_measurement_settings_editor(self, hide_editor):
2362
        """
2363
        Shows or hides input widgets for measurement settings and fast counter settings
2364
        """
2365
        if hide_editor:
2366
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(False)
2367
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(False)
2368
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(False)
2369
            self._pa.ana_param_record_length_DoubleSpinBox.setEnabled(False)
2370
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(False)
2371
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(False)
2372
            self._pa.ana_param_alternating_CheckBox.setEnabled(False)
2373
        else:
2374
            self._pa.ana_param_x_axis_start_ScienDSpinBox.setEnabled(True)
2375
            self._pa.ana_param_x_axis_inc_ScienDSpinBox.setEnabled(True)
2376
            self._pa.ana_param_num_laser_pulse_SpinBox.setEnabled(True)
2377
            self._pa.ana_param_record_length_DoubleSpinBox.setEnabled(True)
2378
            self._pa.ana_param_ignore_first_CheckBox.setEnabled(True)
2379
            self._pa.ana_param_ignore_last_CheckBox.setEnabled(True)
2380
            self._pa.ana_param_alternating_CheckBox.setEnabled(True)
2381
        return
2382
2383
    @QtCore.Slot(bool)
2384
    def toggle_error_bars(self, show_bars):
2385
        """
2386
2387
        @return:
2388
        """
2389
        is_alternating = self.signal_image2 in self._pa.pulse_analysis_PlotWidget.items()
2390
        if show_bars:
2391
            if self.signal_image_error_bars not in self._pa.pulse_analysis_PlotWidget.items():
2392
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars)
2393
            if is_alternating and self.signal_image_error_bars2 not in self._pa.pulse_analysis_PlotWidget.items():
2394
                self._pa.pulse_analysis_PlotWidget.addItem(self.signal_image_error_bars2)
2395
        else:
2396
            if self.signal_image_error_bars in self._pa.pulse_analysis_PlotWidget.items():
2397
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars)
2398
            if is_alternating and self.signal_image_error_bars2 in self._pa.pulse_analysis_PlotWidget.items():
2399
                self._pa.pulse_analysis_PlotWidget.removeItem(self.signal_image_error_bars2)
2400
        return
2401
2402
    @QtCore.Slot(str)
2403
    def second_plot_changed(self, second_plot):
2404
        """ This method handles the second plot"""
2405
        self._pa.second_plot_GroupBox.setVisible(second_plot != 'None')
2406
        self._pa.second_plot_GroupBox.setTitle(second_plot)
2407
2408
        if second_plot != self._pa.second_plot_ComboBox.currentText():
2409
            self._pa.second_plot_ComboBox.blockSignals(True)
2410
            index = self._pa.second_plot_ComboBox.findText(second_plot)
2411
            self._pa.second_plot_ComboBox.setCurrentIndex(index)
2412
            self._pa.second_plot_ComboBox.blockSignals(False)
2413
2414
        if second_plot != self.pulsedmasterlogic().alternative_data_type:
2415
            self.pulsedmasterlogic().set_alternative_data_type(second_plot)
2416
        return
2417
2418
    ###########################################################################
2419
    #                      Extraction tab related methods                     #
2420
    ###########################################################################
2421
    def _activate_extraction_ui(self):
2422
        # Configure the lasertrace plot display:
2423
        self.sig_start_line = pg.InfiniteLine(pos=0,
2424
                                              pen={'color': palette.c3, 'width': 1},
2425
                                              movable=True)
2426
        self.sig_end_line = pg.InfiniteLine(pos=0,
2427
                                            pen={'color': palette.c3, 'width': 1},
2428
                                            movable=True)
2429
        self.ref_start_line = pg.InfiniteLine(pos=0,
2430
                                              pen={'color': palette.c4, 'width': 1},
2431
                                              movable=True)
2432
        self.ref_end_line = pg.InfiniteLine(pos=0,
2433
                                            pen={'color': palette.c4, 'width': 1},
2434
                                            movable=True)
2435
        self.lasertrace_image = pg.PlotDataItem(np.arange(10), np.zeros(10), pen=palette.c1)
2436
        self._pe.laserpulses_PlotWidget.addItem(self.lasertrace_image)
2437
        self._pe.laserpulses_PlotWidget.addItem(self.sig_start_line)
2438
        self._pe.laserpulses_PlotWidget.addItem(self.sig_end_line)
2439
        self._pe.laserpulses_PlotWidget.addItem(self.ref_start_line)
2440
        self._pe.laserpulses_PlotWidget.addItem(self.ref_end_line)
2441
        self._pe.laserpulses_PlotWidget.setLabel(axis='bottom', text='time', units='s')
2442
        self._pe.laserpulses_PlotWidget.setLabel(axis='left', text='events', units='#')
2443
2444
        # Configure the measuring error plot display:
2445
        self.measuring_error_image = pg.PlotDataItem(np.arange(10), np.zeros(10), pen=palette.c1)
2446
        self.measuring_error_image2 = pg.PlotDataItem(np.arange(10), np.zeros(10), pen=palette.c3)
2447
        self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image)
2448
        self._pe.measuring_error_PlotWidget.addItem(self.measuring_error_image2)
2449
        self._pe.measuring_error_PlotWidget.setLabel('left', 'measuring error',  units='arb.u.')
2450
2451
        # Initialize widgets
2452
        number_of_lasers = self.pulsedmasterlogic().measurement_settings['number_of_lasers']
2453
        self._pe.laserpulses_display_raw_CheckBox.blockSignals(True)
2454
        self._pe.laserpulses_ComboBox.blockSignals(True)
2455
        self._pe.extract_param_analysis_method_comboBox.blockSignals(True)
2456
        self._pe.extract_param_method_comboBox.blockSignals(True)
2457
2458
        self._pe.laserpulses_display_raw_CheckBox.setChecked(self._show_raw_data)
2459
2460
        self._pe.laserpulses_ComboBox.clear()
2461
        self._pe.laserpulses_ComboBox.addItem('sum')
2462
        for ii in range(1, number_of_lasers + 1):
2463
            self._pe.laserpulses_ComboBox.addItem(str(ii))
2464
        self._pe.laserpulses_ComboBox.setCurrentIndex(self._show_laser_index)
2465
2466
        self._pe.extract_param_analysis_method_comboBox.clear()
2467
        self._pe.extract_param_analysis_method_comboBox.addItems(
2468
            list(self.pulsedmasterlogic().analysis_methods))
2469
        self._pe.extract_param_method_comboBox.clear()
2470
        self._pe.extract_param_method_comboBox.addItems(
2471
            list(self.pulsedmasterlogic().extraction_methods))
2472
2473
        self._pe.laserpulses_display_raw_CheckBox.blockSignals(False)
2474
        self._pe.laserpulses_ComboBox.blockSignals(False)
2475
        self._pe.extract_param_analysis_method_comboBox.blockSignals(False)
2476
        self._pe.extract_param_method_comboBox.blockSignals(False)
2477
2478
        # variable holding all dynamically generated widgets for the selected extraction method
2479
        self._extraction_param_widgets = None
2480
2481
        # Initialize from logic values
2482
        self.analysis_settings_updated(self.pulsedmasterlogic().analysis_settings)
2483
        self.extraction_settings_updated(self.pulsedmasterlogic().extraction_settings)
2484
        self.update_laser_data()
2485
        return
2486
2487
    def _deactivate_extraction_ui(self):
2488
        self._show_laser_index = self._pe.laserpulses_ComboBox.currentIndex()
2489
        self._show_raw_data = self._pe.laserpulses_display_raw_CheckBox.isChecked()
2490
        return
2491
2492
    @QtCore.Slot()
2493
    def extraction_settings_changed(self):
2494
        """
2495
        Uodate new value of standard deviation of gaussian filter
2496
        """
2497
        settings_dict = dict()
2498
        settings_dict['method'] = self._pe.extract_param_method_comboBox.currentText()
2499
        # Check if the method has been changed
2500 View Code Duplication
        if settings_dict['method'] == self.pulsedmasterlogic().extraction_settings['method']:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2501
            for label, widget in self._extraction_param_widgets:
2502
                param_name = widget.objectName()[14:]
2503
                if hasattr(widget, 'isChecked'):
2504
                    settings_dict[param_name] = widget.isChecked()
2505
                elif hasattr(widget, 'value'):
2506
                    settings_dict[param_name] = widget.value()
2507
                elif hasattr(widget, 'text'):
2508
                    settings_dict[param_name] = widget.text()
2509
        else:
2510
            self._delete_extraction_param_widgets()
2511
2512
        self.pulsedmasterlogic().set_extraction_settings(settings_dict)
2513
        return
2514
2515
    @QtCore.Slot(dict)
2516
    def extraction_settings_updated(self, settings_dict):
2517
        """
2518
2519
        @param dict settings_dict: dictionary with parameters to update
2520
        @return:
2521
        """
2522
        # If no widgets have been generated yet, generate them now.
2523
        if self._extraction_param_widgets is None:
2524
            self._create_extraction_param_widgets(extraction_settings=settings_dict)
2525
2526
        # If the method is unchanged, just update the widget values.
2527
        # Otherwise delete all widgets and create new ones for the changed method.
2528
        if settings_dict.get('method') == self._pe.extract_param_method_comboBox.currentText():
2529
            for label, widget in self._extraction_param_widgets:
2530
                param_name = widget.objectName()[14:]
2531
                widget.blockSignals(True)
2532
                if hasattr(widget, 'setValue'):
2533
                    widget.setValue(settings_dict.get(param_name))
2534
                elif hasattr(widget, 'setChecked'):
2535
                    widget.setChecked(settings_dict.get(param_name))
2536
                elif hasattr(widget, 'setText'):
2537
                    widget.setText(settings_dict.get(param_name))
2538
                else:
2539
                    self.log.error('Unable to update widget value for parameter "{0}".\n'
2540
                                   'Widget is of unknown type.'.format(param_name))
2541
                widget.blockSignals(False)
2542
        else:
2543
            self._delete_extraction_param_widgets()
2544
            self._create_extraction_param_widgets(extraction_settings=settings_dict)
2545
2546
        # Update the method combobox
2547
        self._pe.extract_param_method_comboBox.blockSignals(True)
2548
        index = self._pe.extract_param_method_comboBox.findText(settings_dict.get('method'))
2549
        self._pe.extract_param_method_comboBox.setCurrentIndex(index)
2550
        self._pe.extract_param_method_comboBox.blockSignals(False)
2551
        return
2552
2553
    def _delete_extraction_param_widgets(self):
2554
        """
2555
2556
        @return:
2557
        """
2558
        for index in reversed(range(len(self._extraction_param_widgets))):
2559
            label = self._extraction_param_widgets[index][0]
2560
            widget = self._extraction_param_widgets[index][1]
2561
            # Disconnect signals
2562
            if hasattr(widget, 'setChecked'):
2563
                widget.stateChanged.disconnect()
2564
            else:
2565
                widget.editingFinished.disconnect()
2566
            # Remove label and widget from layout
2567
            self._pe.extraction_param_gridLayout.removeWidget(label)
2568
            self._pe.extraction_param_gridLayout.removeWidget(widget)
2569
            # Stage label and widget for deletion
2570
            label.deleteLater()
2571
            widget.deleteLater()
2572
            del self._extraction_param_widgets[index]
2573
        self._extraction_param_widgets = None
2574
        return
2575
2576
    def _create_extraction_param_widgets(self, extraction_settings):
2577
        """
2578
2579
        @param extraction_settings:
2580
        @return:
2581
        """
2582
        self._extraction_param_widgets = list()
2583
        layout_row = 1
2584
        for param_name, value in extraction_settings.items():
2585
            if param_name == 'method':
2586
                continue
2587
2588
            # Create label for the parameter
2589
            label = QtWidgets.QLabel(param_name + ':')
2590
            label.setObjectName('extract_param_label_' + param_name)
2591
2592
            # Create widget for parameter and connect update signal
2593
            if isinstance(value, float):
2594
                widget = ScienDSpinBox()
2595
                widget.setValue(value)
2596
                widget.editingFinished.connect(self.extraction_settings_changed)
2597
            elif isinstance(value, int):
2598
                widget = ScienSpinBox()
2599
                widget.setValue(value)
2600
                widget.editingFinished.connect(self.extraction_settings_changed)
2601
            elif isinstance(value, str):
2602
                widget = QtWidgets.QLineEdit()
2603
                widget.setText(value)
2604
                widget.editingFinished.connect(self.extraction_settings_changed)
2605
            elif isinstance(value, bool):
2606
                widget = QtWidgets.QCheckBox()
2607
                widget.setChecked(value)
2608
                widget.stateChanged.connect(self.extraction_settings_changed)
2609
            else:
2610
                self.log.error('Could not create widget for extraction parameter "{0}".\n'
2611
                               'Default parameter value is of invalid type.'.format(param_name))
2612
                continue
2613
            widget.setObjectName('extract_param_' + param_name)
2614
            widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
2615
2616
            # Add label and widget to the main grid layout
2617
            self._pe.extraction_param_gridLayout.addWidget(label, layout_row, 0)
2618
            self._pe.extraction_param_gridLayout.addWidget(widget, layout_row, 1)
2619
2620
            # Add label and widget to the list
2621
            self._extraction_param_widgets.append((label, widget))
2622
            layout_row += 1
2623
2624
    @QtCore.Slot()
2625
    def analysis_settings_changed(self):
2626
        """
2627
2628
        @return:
2629
        """
2630
        settings_dict = dict()
2631
2632
        # Check if the signal has been emitted by a dragged line in the laser plot
2633
        if self.sender().__class__.__name__ == 'InfiniteLine':
2634
            sig_start = self.sig_start_line.value()
2635
            sig_end = self.sig_end_line.value()
2636
            ref_start = self.ref_start_line.value()
2637
            ref_end = self.ref_end_line.value()
2638
            settings_dict['signal_start'] = sig_start if sig_start <= sig_end else sig_end
2639
            settings_dict['signal_end'] = sig_end if sig_end >= sig_start else sig_start
2640
            settings_dict['norm_start'] = ref_start if ref_start <= ref_end else ref_end
2641
            settings_dict['norm_end'] = ref_end if ref_end >= ref_start else ref_start
2642
        else:
2643
            signal_width = self._pe.extract_param_ana_window_width_DSpinBox.value()
2644
            settings_dict['signal_start'] = self._pe.extract_param_ana_window_start_DSpinBox.value()
2645
            settings_dict['signal_end'] = settings_dict['signal_start'] + signal_width
2646
            norm_width = self._pe.extract_param_ref_window_width_DSpinBox.value()
2647
            settings_dict['norm_start'] = self._pe.extract_param_ref_window_start_DSpinBox.value()
2648
            settings_dict['norm_end'] = settings_dict['norm_start'] + norm_width
2649
2650
        settings_dict['method'] = self._pe.extract_param_analysis_method_comboBox.currentText()
2651
2652
        self.pulsedmasterlogic().set_analysis_settings(settings_dict)
2653
        return
2654
2655
    @QtCore.Slot(dict)
2656
    def analysis_settings_updated(self, settings_dict):
2657
        """
2658
2659
        @param dict settings_dict: dictionary with parameters to update
2660
        @return:
2661
        """
2662
2663
        # block signals
2664
        self._pe.extract_param_analysis_method_comboBox.blockSignals(True)
2665
        self._pe.extract_param_ana_window_start_DSpinBox.blockSignals(True)
2666
        self._pe.extract_param_ana_window_width_DSpinBox.blockSignals(True)
2667
        self._pe.extract_param_ref_window_start_DSpinBox.blockSignals(True)
2668
        self._pe.extract_param_ref_window_width_DSpinBox.blockSignals(True)
2669
        self.sig_start_line.blockSignals(True)
2670
        self.sig_end_line.blockSignals(True)
2671
        self.ref_start_line.blockSignals(True)
2672
        self.ref_end_line.blockSignals(True)
2673
2674
        if 'signal_start' in settings_dict:
2675
            self._pe.extract_param_ana_window_start_DSpinBox.setValue(
2676
                settings_dict['signal_start'])
2677
            self.sig_start_line.setValue(settings_dict['signal_start'])
2678
        if 'norm_start' in settings_dict:
2679
            self._pe.extract_param_ref_window_start_DSpinBox.setValue(settings_dict['norm_start'])
2680
            self.ref_start_line.setValue(settings_dict['norm_start'])
2681
        if 'signal_end' in settings_dict:
2682
            signal_start = self._pe.extract_param_ana_window_start_DSpinBox.value()
2683
            self._pe.extract_param_ana_window_width_DSpinBox.setValue(
2684
                settings_dict['signal_end'] - signal_start)
2685
            self.sig_end_line.setValue(settings_dict['signal_end'])
2686
        if 'norm_end' in settings_dict:
2687
            norm_start = self._pe.extract_param_ref_window_start_DSpinBox.value()
2688
            self._pe.extract_param_ref_window_width_DSpinBox.setValue(
2689
                settings_dict['norm_end'] - norm_start)
2690
            self.ref_end_line.setValue(settings_dict['norm_end'])
2691
        if 'method' in settings_dict:
2692
            index = self._pe.extract_param_analysis_method_comboBox.findText(settings_dict['method'])
2693
            self._pe.extract_param_analysis_method_comboBox.setCurrentIndex(index)
2694
2695
        # unblock signals
2696
        self._pe.extract_param_analysis_method_comboBox.blockSignals(False)
2697
        self._pe.extract_param_ana_window_start_DSpinBox.blockSignals(False)
2698
        self._pe.extract_param_ana_window_width_DSpinBox.blockSignals(False)
2699
        self._pe.extract_param_ref_window_start_DSpinBox.blockSignals(False)
2700
        self._pe.extract_param_ref_window_width_DSpinBox.blockSignals(False)
2701
        self.sig_start_line.blockSignals(False)
2702
        self.sig_end_line.blockSignals(False)
2703
        self.ref_start_line.blockSignals(False)
2704
        self.ref_end_line.blockSignals(False)
2705
        return
2706
2707
    @QtCore.Slot()
2708
    def update_laser_data(self):
2709
        """
2710
2711
        @return:
2712
        """
2713
        laser_index = self._pe.laserpulses_ComboBox.currentIndex()
2714
        show_raw = self._pe.laserpulses_display_raw_CheckBox.isChecked()
2715
        is_gated = len(self.pulsedmasterlogic().raw_data.shape) > 1
2716
2717
        # Determine the right array to plot as y-data
2718
        if show_raw:
2719
            if is_gated:
2720
                if laser_index == 0:
2721
                    y_data = np.sum(self.pulsedmasterlogic().raw_data, axis=0)
2722
                else:
2723
                    y_data = self.pulsedmasterlogic().raw_data[laser_index - 1]
2724
            else:
2725
                y_data = self.pulsedmasterlogic().raw_data
2726
        else:
2727
            if laser_index == 0:
2728
                y_data = np.sum(self.pulsedmasterlogic().laser_data, axis=0)
2729
            else:
2730
                y_data = self.pulsedmasterlogic().laser_data[laser_index - 1]
2731
2732
        # Calculate the x-axis of the laser plot here
2733
        bin_width = self.pulsedmasterlogic().fast_counter_settings['bin_width']
2734
        x_data = np.arange(y_data.size, dtype=float) * bin_width
2735
2736
        # Plot data
2737
        self.lasertrace_image.setData(x=x_data, y=y_data)
2738
        return
2739
2740
2741