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

PulsedMeasurementGui.sequence_add_sel_clicked()   A

Complexity

Conditions 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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