예제 #1
0
    def populate_comboboxes(self):
        """ Fill comboboxes in gui with awailable data (task in DAQTask object)

        :return:
        """
        canals = [task.decode() for task in DAQTask.get_daq_tasks()]
        self.statusbar.showMessage(str(canals))
        self.combobox_canal_horizontal.addItems(canals)
        self.combobox_canal_vertical.addItems(canals)
        self.combobox_canal_measure.addItems(canals)
예제 #2
0
    def _refresh_tasks_list(self, drop_popup=True):
        # Get tasks
        self.device_task.blockSignals(True)
        tasks_tmp = map(bytes.decode, dq.get_daq_tasks())
        tasks = list(tasks_tmp).copy()

        self.device_task.clear()
        self.device_task.addItem('- Choose task -')
        for item in tasks:
            self.device_task.addItem(item)

        self.device_task.addItem(qta.icon('fa.refresh', scale_factor=0.65, color=COLOR_PALETTE['primaryhex']), 'refresh  ')
        if drop_popup:
            self.device_task.showPopup()

        self.device_task.blockSignals(False)
예제 #3
0
    def _refresh_tasks_list(self, drop_popup=True):
        # Get tasks
        self.device_task.blockSignals(True)
        tasks_tmp = map(bytes.decode, dq.get_daq_tasks())
        tasks = list(tasks_tmp).copy()

        self.device_task.clear()
        self.device_task.addItem('- Choose task -')
        for item in tasks:
            self.device_task.addItem(item)

        self.device_task.addItem(
            qta.icon('fa.refresh',
                     scale_factor=0.65,
                     color=COLOR_PALETTE['primaryhex']), 'refresh  ')
        if drop_popup:
            self.device_task.showPopup()

        self.device_task.blockSignals(False)
예제 #4
0
    def channels_widget(self):
        """Setup device an channels."""
        channel_widget = QtWidgets.QWidget()

        font = QtGui.QFont()
        font.setPointSize(13)

        # Select excitation
        group = QtWidgets.QGroupBox('Excitation Type')
        group.setStyleSheet("QGroupBox {font-weight: bold;}")
        self.radio_impulse = QtWidgets.QRadioButton('Impulse')
        self.radio_impulse.setToolTip(tt.tooltips['impulse_excitation'])

        self.radio_impulse.toggled.connect(self.set_impulse_type)
        # self.settings['excitation_type'] = 'impulse' # TODO: It would be better if just set_impulse_type is called here.

        self.radio_random = QtWidgets.QRadioButton('Random')
        self.radio_random.setToolTip(tt.tooltips['random_excitation'])
        self.radio_random.toggled.connect(self.set_random_type)

        self.radio_oma = QtWidgets.QRadioButton('OMA')
        self.radio_oma.setToolTip(tt.tooltips['OMA_excitation'])
        self.radio_oma.toggled.connect(self.set_oma_type)
        # radio_random.setDisabled(True)
        radio_sweep = QtWidgets.QRadioButton('Sine Sweep')
        self.fields['excitation_type'] = 'impulse'
        # radio_sweep.setDisabled(True)

        group_layout = QtWidgets.QHBoxLayout()
        group_layout.addWidget(self.radio_impulse)
        group_layout.addWidget(self.radio_random)
        group_layout.addWidget(self.radio_oma)
        # group_layout.addWidget(radio_sweep)
        # group_layout.addStretch()

        group.setLayout(group_layout)

        # Get tasks
        # tasks_tmp = map(bytes.decode, dq.get_daq_tasks())
        # tasks = list(tasks_tmp).copy()
        self.device_task = QtWidgets.QComboBox()
        self.device_task.setToolTip(tt.tooltips['signal_selection'])
        self.device_task.setObjectName('small')
        task_status = QtWidgets.QLabel('')

        if (dp is None) or (dq is None):
            warning_label = QtWidgets.QPushButton(
                qta.icon('fa.warning', scale_factor=0.8, color='red'),
                'Install DAQmx, then restart OpenModal!')
            warning_label.setObjectName('linkbutton')
            warning_label.setStyleSheet(
                'font-size: x-small; color: red; text-decoration: none; width:375px;'
            )
            warning_label.setContentsMargins(0, 0, 0, 0)

            signal_hbox = QtWidgets.QHBoxLayout()
            signal_hbox.addStretch()
            signal_hbox.addWidget(warning_label)
            signal_hbox.addStretch()
        else:
            open_ni_max = QtWidgets.QPushButton('NIMax')
            open_ni_max.setToolTip(tt.tooltips['nimax'])
            open_ni_max.setObjectName('small')
            open_ni_max.clicked.connect(lambda: subprocess.Popen([
                r'{0}\National Instruments\MAX\NIMax.exe'.format(os.environ[
                    'ProgramFiles(x86)'])
            ]))

            # device_task.setFont(font)
            # select_task = True
            self._refresh_tasks_list(drop_popup=False)
            # self.device_task.addItem('- Choose task -')
            # for item in tasks:
            #     self.device_task.addItem(item)
            # self.fields['task_name'] = self.device_task.currentText().encode

            signal_hbox = QtWidgets.QHBoxLayout()
            # device_hbox.addWidget(label)
            signal_hbox.addWidget(self.device_task)
            signal_hbox.addStretch()
            signal_hbox.addWidget(open_ni_max)
            # signal_hbox.addStretch()
            # signal_hbox.addWidget(task_status)
            signal_hbox.addStretch()

        signal_vbox = QtWidgets.QVBoxLayout()

        # Signal setttings.
        signal_grid = QtWidgets.QGridLayout()

        # Window length.
        self.win_length = QtWidgets.QSpinBox()
        self.win_length.setToolTip(tt.tooltips['window_length'])
        self.win_length.setRange(1, MAX_WINDOW_LENGTH)
        self.win_length.setValue(DEFAULTS['samples_per_channel'])
        win_length_label = QtWidgets.QLabel('Window length')
        signal_grid.addWidget(win_length_label, 0, 0)
        signal_grid.addWidget(self.win_length, 0, 2)
        self.fields['samples_per_channel'] = self.win_length.value
        # signal_grid.addRow(self.tr('Window length'), win_length)

        # Zero padding.
        zero_padding = QtWidgets.QSpinBox()
        zero_padding.setToolTip(tt.tooltips['zero_padding'])
        zero_padding.setRange(0, MAX_WINDOW_LENGTH)
        zero_padding.setValue(DEFAULTS['zero_padding'])
        zero_padding_label = QtWidgets.QLabel('Zero padding')
        signal_grid.addWidget(zero_padding_label, 1, 0)
        signal_grid.addWidget(zero_padding, 1, 2)
        self.fields['zero_padding'] = zero_padding.value

        # Excitation window.
        self.exc_win = QtWidgets.QComboBox()
        self.exc_win.setToolTip(tt.tooltips['excitation_window'])
        for window in _WINDOWS:
            self.exc_win.addItem(window)
        self.exc_win.setCurrentIndex([
            i for i, window in enumerate(_WINDOWS)
            if window in DEFAULTS['exc_window']
        ][0])
        exc_win_label = QtWidgets.QLabel('Excitation window')
        exc_win_percent = QtWidgets.QDoubleSpinBox()
        exc_win_percent.setToolTip(tt.tooltips['excitation_window_percent'])
        exc_win_percent.setRange(0.01, 100)
        exc_win_percent.setValue(1)
        exc_win_percent_unit = QtWidgets.QLabel('%')
        signal_grid.addWidget(exc_win_label, 2, 0)
        signal_grid.addWidget(self.exc_win, 2, 2)
        signal_grid.addWidget(exc_win_percent, 2, 3)
        signal_grid.addWidget(exc_win_percent_unit, 2, 4)
        self.fields['exc_window'] = lambda: '{0}:{1:.4f}'.format(
            self.exc_win.currentText(),
            exc_win_percent.value() / 100)
        # self.fields['exc_window_percent'] = exc_win_percent
        # signal_grid.addRow(self.tr('Excitation window'), exc_win)

        # Response window.
        self.resp_win = QtWidgets.QComboBox()
        self.resp_win.setToolTip(tt.tooltips['response_window'])
        for window in _WINDOWS:
            self.resp_win.addItem(window)
        self.resp_win.setCurrentIndex([
            i for i, window in enumerate(_WINDOWS)
            if window in DEFAULTS['resp_window']
        ][0])
        resp_win_label = QtWidgets.QLabel('Response window')
        resp_win_percent = QtWidgets.QDoubleSpinBox()
        resp_win_percent.setToolTip(tt.tooltips['response_window_percent'])
        resp_win_percent.setRange(0.01, 100)
        resp_win_percent.setValue(1)
        resp_win_percent_unit = QtWidgets.QLabel('%')
        signal_grid.addWidget(resp_win_label, 3, 0)
        signal_grid.addWidget(self.resp_win, 3, 2)
        signal_grid.addWidget(resp_win_percent, 3, 3)
        signal_grid.addWidget(resp_win_percent_unit, 3, 4)
        self.fields['resp_window'] = lambda: '{0}:{1:.4f}'.format(
            self.resp_win.currentText(),
            resp_win_percent.value() / 100)
        # self.fields['resp_window_percent'] = resp_win_percent
        # signal_grid.addRow(self.tr('Response window'), resp_win)

        # Averaging.
        self.avg_type = QtWidgets.QComboBox()
        self.avg_type.setToolTip(tt.tooltips['averaging_type'])
        for weighting in _WGH_TYPES:
            self.avg_type.addItem(weighting)
        self.avg_type.setCurrentIndex([
            i for i, window in enumerate(_WGH_TYPES)
            if window in DEFAULTS['weighting']
        ][0])
        avg_type_label = QtWidgets.QLabel('Averaging')
        avg_sample_number = QtWidgets.QSpinBox()
        avg_sample_number.setToolTip(tt.tooltips['averaging_number'])
        avg_sample_number.setRange(2, 50)
        avg_sample_number.setValue(DEFAULTS['n_averages'])
        avg_sample_number_unit = QtWidgets.QLabel('samples')
        signal_grid.addWidget(avg_type_label, 4, 0)
        signal_grid.addWidget(self.avg_type, 4, 2)
        signal_grid.addWidget(avg_sample_number, 4, 3)
        signal_grid.addWidget(avg_sample_number_unit, 4, 4)
        self.fields['weighting'] = self.avg_type.currentText
        self.fields['n_averages'] = avg_sample_number.value

        # Save time history.
        save_time_history = QtWidgets.QCheckBox()
        save_time_history.setToolTip(tt.tooltips['save_time_history'])
        save_time_history_label = QtWidgets.QLabel('Save time-history')
        save_time_history.setChecked(DEFAULTS['save_time_history'])
        signal_grid.addWidget(save_time_history_label, 5, 0)
        signal_grid.addWidget(save_time_history, 5, 2)
        self.fields['save_time_history'] = save_time_history.isChecked

        # Trigger level
        self.trigger_level = QtWidgets.QDoubleSpinBox()
        self.trigger_level.setToolTip(tt.tooltips['trigger_level'])
        self.trigger_level.setRange(0.0001, 1000000)
        self.trigger_level.setValue(DEFAULTS['trigger_level'])
        trigger_level_label = QtWidgets.QLabel('Trigger level (excitation)')
        signal_grid.addWidget(trigger_level_label, 6, 0)
        signal_grid.addWidget(self.trigger_level, 6, 2)
        self.fields['trigger_level'] = self.trigger_level.value

        # Pre trigger samples.
        self.pre_trigger = QtWidgets.QSpinBox()
        self.pre_trigger.setToolTip(tt.tooltips['pre_trigger_samples'])
        self.pre_trigger.setRange(0, self.win_length.value())
        self.pre_trigger.setValue(DEFAULTS['pre_trigger_samples'])
        # self.win_length.valueChanged.connect(lambda: self.pre_trigger.setRange(0, self.win_length.value()))
        pre_trigger_label = QtWidgets.QLabel('Pre-trigger samples')
        pre_trigger_unit = QtWidgets.QLabel('S')
        signal_grid.addWidget(pre_trigger_label, 7, 0)
        signal_grid.addWidget(self.pre_trigger, 7, 2)
        signal_grid.addWidget(pre_trigger_unit, 7, 3)
        self.fields['pre_trigger_samples'] = self.pre_trigger.value

        # Check if task is already set and if it is, fill saved values.
        if 'task_name' in self.settings:
            self.win_length.setValue(self.settings['samples_per_channel'])
            self.exc_win.setCurrentIndex([
                i for i, win in enumerate(_WINDOWS)
                if win in self.settings['exc_window']
            ][0])
            exc_win_percent.setValue(
                float(self.settings['exc_window'].split(':')[1]) * 100)
            self.resp_win.setCurrentIndex([
                i for i, win in enumerate(_WINDOWS)
                if win in self.settings['resp_window']
            ][0])
            resp_win_percent.setValue(
                float(self.settings['resp_window'].split(':')[1]) * 100)
            self.avg_type.setCurrentIndex([
                i for i, avgt in enumerate(_WGH_TYPES)
                if avgt in self.settings['weighting']
            ][0])
            avg_sample_number.setValue(self.settings['n_averages'])
            self.trigger_level.setValue(self.settings['trigger_level'])
            self.pre_trigger.setValue(self.settings['pre_trigger_samples'])
            zero_padding.setValue(self.settings['zero_padding'])
            save_time_history.setChecked(self.settings['save_time_history'])

        if 'excitation_type' in self.settings:
            if self.settings['excitation_type'] == 'impulse':
                self.radio_impulse.setChecked(True)
            elif self.settings['excitation_type'] == 'random':
                self.radio_random.setChecked(True)
            elif self.settings['excitation_type'] == 'oma':
                self.radio_oma.setChecked(True)
        else:
            self.radio_impulse.setChecked(True)

        signal_grid.setColumnStretch(1, 5)
        signal_grid.setColumnStretch(4, 15)

        groupb_box = QtWidgets.QGroupBox()
        groupb_box.setTitle('Signal ')
        # groupb_box.setStyleSheet("QGroupBox {font-size: 16px;}")
        groupb_box.setStyleSheet("QGroupBox {font-weight: bold;}")

        signal_vbox.addLayout(signal_hbox)
        signal_vbox.addWidget(task_status)
        signal_vbox.addLayout(signal_grid)

        groupb_box.setLayout(signal_vbox)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(group)
        vbox.addWidget(groupb_box)

        table = QtWidgets.QTableWidget(3, 5)
        table.setShowGrid(False)

        horizontal_header = table.horizontalHeader()

        table.setHorizontalHeaderLabels(
            ['Name', 'Type', 'Units', 'Delay [ms]', ''])
        table.setVerticalHeaderLabels(
            ['Channel {0}'.format(i + 1) for i in range(3)])
        table.resizeColumnsToContents()
        header_view = table.horizontalHeader()
        header_view.setSectionResizeMode(0, header_view.Stretch)
        # cw = QtGui.QPushButton('Bu')
        # header_view.setCornerWidget(cw)
        table.setDisabled(True)

        excitation_warning = QtWidgets.QLabel('')

        def refresh_table(names):
            """Populate table with channels for the chosen task."""
            table.setEnabled(True)
            # self.channel_table.setEnabled(True)
            i = len(names)
            table.setRowCount(i)
            table.setVerticalHeaderLabels(
                ['Channel {0}'.format(i + 1) for i in range(i)])
            # self.channel_table.ch

            if not ('task_name' in self.settings):
                for key in DEFAULTS.keys():
                    self.settings[key] = DEFAULTS[key]
            elif not (self.device_task.currentText()
                      in self.settings['task_name'].decode()):
                for key in DEFAULTS.keys():
                    self.settings[key] = DEFAULTS[key]

            for i, name in enumerate(names):
                # First cell
                channel_name = QtWidgets.QTableWidgetItem(name)
                channel_name.setFlags(channel_name.flags()
                                      & ~QtCore.Qt.ItemIsEditable)
                table.setItem(i, 0, channel_name)

                # Type
                type = QtWidgets.QComboBox()
                type.addItem(self.tr('Response'))
                type.addItem(self.tr('Excitation'))
                # type.addItem(self.tr('Disabled'))
                if 'resp_channels' in self.settings and 'exc_channel' in self.settings:
                    if i in self.settings['resp_channels']:
                        type.setCurrentIndex(0)
                    elif i == self.settings['exc_channel']:
                        type.setCurrentIndex(1)

                # type.currentIndexChanged()
                table.setCellWidget(i, 1, type)

                # Units
                units = QtWidgets.QComboBox()
                if 'Excitation' in type.currentText():
                    # units.setEnabled(True)
                    if self.fields['excitation_type']() == 'oma':
                        units.addItems(_RESP_TYPES)
                    else:
                        units.addItems(_EXC_TYPES)
                elif 'Response' in type.currentText():
                    # units.setEnabled(True)
                    units.addItems(_RESP_TYPES)
                # elif 'Disabled' in type.currentText():
                #     units.setDisabled(True)
                # print(i, name)
                # print(self.settings['channel_types'])
                # print(self.fields['excitation_type']())
                if self.fields['excitation_type']() == 'oma':
                    try:
                        units.setCurrentIndex([
                            num for num, letter in enumerate(_RESP_TYPES)
                            if self.settings['channel_types'][i] in letter
                        ][0])
                    except:
                        units.setCurrentIndex(0)
                elif 'channel_types' in self.settings and 'Excitation' in type.currentText(
                ):
                    units.setCurrentIndex([
                        num for num, letter in enumerate(_EXC_TYPES)
                        if self.settings['channel_types'][i] in letter
                    ][0])
                elif 'channel_types' in self.settings and 'Response' in type.currentText(
                ):
                    try:
                        units.setCurrentIndex([
                            num for num, letter in enumerate(_RESP_TYPES)
                            if self.settings['channel_types'][i] in letter
                        ][0])
                    except:
                        units.setCurrentIndex(0)
                table.setCellWidget(i, 2, units)

                # Delay.
                delay = QtWidgets.QDoubleSpinBox()
                delay.setRange(-5000, 5000)
                delay.setDecimals(3)
                # print (self.settings['channel_delay'])
                if 'channel_delay' in self.settings:
                    delay.setValue(self.settings['channel_delay'][i] * 1000)
                table.setCellWidget(i, 3, delay)
            # Implement Excitation channel number checking. Also updating units field appropriately.
            def excitation_check(nr):

                for u in range(nr):
                    if 'Excitation' in table.cellWidget(u, 1).currentText():
                        # table.cellWidget(u, 2).setEnabled(True)
                        table.cellWidget(u, 2).clear()
                        table.cellWidget(u, 2).addItems(_EXC_TYPES)
                    elif 'Response' in table.cellWidget(u, 1).currentText():
                        # table.cellWidget(u, 2).setEnabled(True)
                        table.cellWidget(u, 2).clear()
                        table.cellWidget(u, 2).addItems(_RESP_TYPES)
                    # elif 'Disabled' in table.cellWidget(u, 1).currentText():
                    #     table.cellWidget(u, 2).setDisabled(True)

                excitation_channels = [
                    i for i in range(nr)
                    if 'Excitation' in table.cellWidget(i, 1).currentText()
                ]
                if len(excitation_channels) > 1:
                    excitation_warning.setText(
                        '''<span style="font-weight: bold; color: red;">There should be exactly one'''
                        ''' excitation channel!</span>''')
                    self.save.setDisabled(True)
                elif len(excitation_channels) < 1:
                    excitation_warning.setText(
                        '''<span style="font-weight: bold; color: red;">There should be exactly one'''
                        ''' excitation channel!</span>''')
                else:
                    excitation_warning.setText('')
                    self.save.setEnabled(True)

            nr = len(names)
            for i in range(nr):
                table.cellWidget(i, 1).currentIndexChanged.connect(
                    lambda: excitation_check(nr))

            table.resizeColumnsToContents()
            horizontal_header.setStretchLastSection(True)

        table.setAlternatingRowColors(True)

        table_title = QtWidgets.QLabel('Channels')
        table_title.setStyleSheet("QLabel {font-weight: bold;}")

        table_title_layout = QtWidgets.QHBoxLayout()
        table_title_layout.addWidget(table_title)
        table_title_layout.addWidget(excitation_warning)

        vbox.addLayout(table_title_layout)
        vbox.addWidget(table)

        # Preview window.
        preview_window = pg.GraphicsView()
        preview_window.setMinimumHeight(300)
        v_graphic_layout = QtWidgets.QVBoxLayout()
        h_button_layout = QtWidgets.QHBoxLayout()
        self.fig = pg.PlotWidget(name='Signal preview')
        self.fig.setLabel('bottom', 'time', units='s')
        self.fig.setLabel('left', 'amplitude')

        self.fig_plotitem = self.fig.getPlotItem()

        self.button_testrun = QtWidgets.QPushButton('Test Run')
        self.button_testrun.setToolTip(tt.tooltips['test_run'])
        self.button_testrun.setObjectName('small')
        self.button_testrun.setCheckable(True)
        self.button_testrun.setDisabled(True)

        def testrun_start_agent(pressed):
            if pressed:
                self.measure_test_run_data()
            else:
                self.stop_measurement_button_trigger()

        self.button_testrun.clicked[bool].connect(testrun_start_agent)

        self.button_fft = QtWidgets.QPushButton('PSD Toggle')
        self.button_fft.setToolTip(tt.tooltips['toggle_PSD'])
        self.button_fft.setObjectName('small')
        self.button_fft.setCheckable(True)
        self.button_fft.clicked[bool].connect(self.fft_toggle)

        h_button_layout.addStretch()
        h_button_layout.addWidget(self.button_testrun)
        h_button_layout.addWidget(self.button_fft)
        h_button_layout.addStretch()

        # splitter = QtGui.QSplitter(QtCore.Qt.Vertical)

        # v_graphic_layout.addWidget(splitter)

        v_graphic_layout.addLayout(h_button_layout)
        # splitter.addLayout(h_button_layout)
        # v_graphic_layout.addWidget(splitter)
        v_graphic_layout.addWidget(self.fig)
        # splitter.addWidget(self.fig)
        preview_window.setLayout(v_graphic_layout)
        # preview_window.setLayout(splitter)

        # vbox.addWidget(preview_window)

        channel_widget.setLayout(vbox)

        vbox.setContentsMargins(0, 0, 0, 0)

        def load_task(reset=False):
            if 'refresh  ' in self.device_task.currentText():
                self._refresh_tasks_list()
            else:
                try:
                    # TODO: Check for required buffer size and availible buffer.
                    # i = dq.DAQTask(self.device_task.currentText().encode())
                    i = dq.DAQTask(self.device_task.currentText().encode())

                    channel_list = list(map(bytes.decode, i.channel_list))

                    i.clear_task(wait_until_done=False)

                    # if i.sample_rate < 2000:
                    #     task_status.setText('<span style="color: orange;"><b>Sampling rate should be at least 2 kHz.</b></span>')
                    #     table.setDisabled(True)
                    #     self.save.setDisabled(True)
                    # else:

                    combos = [
                        QtWidgets.QComboBox() for channel in channel_list
                    ]
                    labels = [
                        QtWidgets.QLabel(channel) for channel in channel_list
                    ]

                    # task_status.setText("""<span style="color: green;">Sampling rate: <b>{0:.0f} S/s</b>, """
                    #                     """Samples to read: <b>{1:.0f} S</b><br />"""
                    #                     """Nr. of channels: <b>{2:.0f}</b></span>""".format(i.sample_rate,
                    #                                                                 i.samples_per_ch, len(channel_list)))

                    task_status.setText(
                        """<span style="color: green;">Sampling rate: <b>{0:.0f} S/s</b>, """
                        """Nr. of channels: <b>{1:.0f}</b></span>""".format(
                            i.sample_rate, len(channel_list)))

                    # Reset settings on task change except when opening up saved state.
                    if 'task_name' in self.settings:
                        if self.settings[
                                'task_name'] == self.device_task.currentText(
                                ).encode():
                            pass
                        else:
                            self.win_length.setValue(i.samples_per_ch)
                    else:
                        self.win_length.setValue(i.samples_per_ch)

                    self.channel_nr = len(channel_list)
                    refresh_table(channel_list)
                    self.save.setEnabled(True)
                    self.button_testrun.setEnabled(True)

                    # Run measurement thread.
                    # self.measure_test_run_process_start()

                    # table.setEnabled(True)

                except dq.DAQError:
                    task_status.setText(
                        '<span style="color: orange;"><b>Device malfunction.</b></span>'
                    )
                    table.setDisabled(True)
                    # table.setDisabled(True)
                    self.save.setDisabled(True)

        # Check if task is already set, then select it.
        self.device_task.currentIndexChanged.connect(load_task)
        self.measurement_type_change.connect(load_task)
        if 'task_name' in self.settings:
            tasks = map(bytes.decode, dq.get_daq_tasks())
            arglist = [
                n for n, task in enumerate(tasks)
                if self.settings['task_name'].decode() in task
            ]
            if len(arglist) > 0:
                self.device_task.setCurrentIndex(arglist[0] + 1)

        return table, channel_widget, preview_window
예제 #5
0
    def channels_widget(self):
        """Setup device an channels."""
        channel_widget = QtGui.QWidget()

        font = QtGui.QFont()
        font.setPointSize(13)

        # Select excitation
        group = QtGui.QGroupBox('Excitation Type')
        group.setStyleSheet("QGroupBox {font-weight: bold;}")
        self.radio_impulse = QtGui.QRadioButton('Impulse')
        self.radio_impulse.setToolTip(tt.tooltips['impulse_excitation'])

        self.radio_impulse.toggled.connect(self.set_impulse_type)
        # self.settings['excitation_type'] = 'impulse' # TODO: It would be better if just set_impulse_type is called here.

        self.radio_random = QtGui.QRadioButton('Random')
        self.radio_random.setToolTip(tt.tooltips['random_excitation'])
        self.radio_random.toggled.connect(self.set_random_type)

        self.radio_oma = QtGui.QRadioButton('OMA')
        self.radio_oma.setToolTip(tt.tooltips['OMA_excitation'])
        self.radio_oma.toggled.connect(self.set_oma_type)
        # radio_random.setDisabled(True)
        radio_sweep = QtGui.QRadioButton('Sine Sweep')
        self.fields['excitation_type'] = 'impulse'
        # radio_sweep.setDisabled(True)

        group_layout = QtGui.QHBoxLayout()
        group_layout.addWidget(self.radio_impulse)
        group_layout.addWidget(self.radio_random)
        group_layout.addWidget(self.radio_oma)
        # group_layout.addWidget(radio_sweep)
        # group_layout.addStretch()

        group.setLayout(group_layout)

        # Get tasks
        # tasks_tmp = map(bytes.decode, dq.get_daq_tasks())
        # tasks = list(tasks_tmp).copy()
        self.device_task = QtGui.QComboBox()
        self.device_task.setToolTip(tt.tooltips['signal_selection'])
        self.device_task.setObjectName('small')
        task_status = QtGui.QLabel('')

        if (dp is None) or (dq is None):
            warning_label = QtGui.QPushButton(qta.icon('fa.warning', scale_factor=0.8,
                                                       color='red'),
                                                      'Install DAQmx, then restart OpenModal!')
            warning_label.setObjectName('linkbutton')
            warning_label.setStyleSheet('font-size: x-small; color: red; text-decoration: none; width:375px;')
            warning_label.setContentsMargins(0, 0, 0, 0)

            signal_hbox = QtGui.QHBoxLayout()
            signal_hbox.addStretch()
            signal_hbox.addWidget(warning_label)
            signal_hbox.addStretch()
        else:
            open_ni_max = QtGui.QPushButton('NIMax')
            open_ni_max.setToolTip(tt.tooltips['nimax'])
            open_ni_max.setObjectName('small')
            open_ni_max.clicked.connect(lambda:
                                        subprocess.Popen([r'{0}\National Instruments\MAX\NIMax.exe'.format(
                                            os.environ['ProgramFiles(x86)'])]))


            # device_task.setFont(font)
            # select_task = True
            self._refresh_tasks_list(drop_popup=False)
            # self.device_task.addItem('- Choose task -')
            # for item in tasks:
            #     self.device_task.addItem(item)
            # self.fields['task_name'] = self.device_task.currentText().encode

            signal_hbox = QtGui.QHBoxLayout()
            # device_hbox.addWidget(label)
            signal_hbox.addWidget(self.device_task)
            signal_hbox.addStretch()
            signal_hbox.addWidget(open_ni_max)
            # signal_hbox.addStretch()
            # signal_hbox.addWidget(task_status)
            signal_hbox.addStretch()

        signal_vbox = QtGui.QVBoxLayout()


        # Signal setttings.
        signal_grid = QtGui.QGridLayout()

        # Window length.
        self.win_length = QtGui.QSpinBox()
        self.win_length.setToolTip(tt.tooltips['window_length'])
        self.win_length.setRange(1, MAX_WINDOW_LENGTH)
        self.win_length.setValue(DEFAULTS['samples_per_channel'])
        win_length_label = QtGui.QLabel('Window length')
        signal_grid.addWidget(win_length_label, 0, 0)
        signal_grid.addWidget(self.win_length, 0, 2)
        self.fields['samples_per_channel'] = self.win_length.value
        # signal_grid.addRow(self.tr('Window length'), win_length)

        # Zero padding.
        zero_padding = QtGui.QSpinBox()
        zero_padding.setToolTip(tt.tooltips['zero_padding'])
        zero_padding.setRange(0, MAX_WINDOW_LENGTH)
        zero_padding.setValue(DEFAULTS['zero_padding'])
        zero_padding_label = QtGui.QLabel('Zero padding')
        signal_grid.addWidget(zero_padding_label, 1, 0)
        signal_grid.addWidget(zero_padding, 1, 2)
        self.fields['zero_padding'] = zero_padding.value

        # Excitation window.
        self.exc_win = QtGui.QComboBox()
        self.exc_win.setToolTip(tt.tooltips['excitation_window'])
        for window in _WINDOWS:
            self.exc_win.addItem(window)
        self.exc_win.setCurrentIndex([i for i, window in enumerate(_WINDOWS) if window in DEFAULTS['exc_window']][0])
        exc_win_label = QtGui.QLabel('Excitation window')
        exc_win_percent = QtGui.QDoubleSpinBox()
        exc_win_percent.setToolTip(tt.tooltips['excitation_window_percent'])
        exc_win_percent.setRange(0.01, 100)
        exc_win_percent.setValue(1)
        exc_win_percent_unit = QtGui.QLabel('%')
        signal_grid.addWidget(exc_win_label, 2, 0)
        signal_grid.addWidget(self.exc_win, 2, 2)
        signal_grid.addWidget(exc_win_percent, 2, 3)
        signal_grid.addWidget(exc_win_percent_unit, 2, 4)
        self.fields['exc_window'] = lambda: '{0}:{1:.4f}'.format(self.exc_win.currentText(), exc_win_percent.value()/100)
        # self.fields['exc_window_percent'] = exc_win_percent
        # signal_grid.addRow(self.tr('Excitation window'), exc_win)

        # Response window.
        self.resp_win = QtGui.QComboBox()
        self.resp_win.setToolTip(tt.tooltips['response_window'])
        for window in _WINDOWS:
            self.resp_win.addItem(window)
        self.resp_win.setCurrentIndex([i for i, window in enumerate(_WINDOWS) if window in DEFAULTS['resp_window']][0])
        resp_win_label = QtGui.QLabel('Response window')
        resp_win_percent = QtGui.QDoubleSpinBox()
        resp_win_percent.setToolTip(tt.tooltips['response_window_percent'])
        resp_win_percent.setRange(0.01, 100)
        resp_win_percent.setValue(1)
        resp_win_percent_unit = QtGui.QLabel('%')
        signal_grid.addWidget(resp_win_label, 3, 0)
        signal_grid.addWidget(self.resp_win, 3, 2)
        signal_grid.addWidget(resp_win_percent, 3, 3)
        signal_grid.addWidget(resp_win_percent_unit, 3, 4)
        self.fields['resp_window'] = lambda: '{0}:{1:.4f}'.format(self.resp_win.currentText(), resp_win_percent.value()/100)
        # self.fields['resp_window_percent'] = resp_win_percent
        # signal_grid.addRow(self.tr('Response window'), resp_win)

        # Averaging.
        self.avg_type = QtGui.QComboBox()
        self.avg_type.setToolTip(tt.tooltips['averaging_type'])
        for weighting in _WGH_TYPES:
            self.avg_type.addItem(weighting)
        self.avg_type.setCurrentIndex([i for i, window in enumerate(_WGH_TYPES) if window in DEFAULTS['weighting']][0])
        avg_type_label = QtGui.QLabel('Averaging')
        avg_sample_number = QtGui.QSpinBox()
        avg_sample_number.setToolTip(tt.tooltips['averaging_number'])
        avg_sample_number.setRange(2, 50)
        avg_sample_number.setValue(DEFAULTS['n_averages'])
        avg_sample_number_unit = QtGui.QLabel('samples')
        signal_grid.addWidget(avg_type_label, 4, 0)
        signal_grid.addWidget(self.avg_type, 4, 2)
        signal_grid.addWidget(avg_sample_number, 4, 3)
        signal_grid.addWidget(avg_sample_number_unit, 4, 4)
        self.fields['weighting'] = self.avg_type.currentText
        self.fields['n_averages'] = avg_sample_number.value

        # Save time history.
        save_time_history = QtGui.QCheckBox()
        save_time_history.setToolTip(tt.tooltips['save_time_history'])
        save_time_history_label = QtGui.QLabel('Save time-history')
        save_time_history.setChecked(DEFAULTS['save_time_history'])
        signal_grid.addWidget(save_time_history_label, 5, 0)
        signal_grid.addWidget(save_time_history, 5, 2)
        self.fields['save_time_history'] = save_time_history.isChecked

        # Trigger level
        self.trigger_level = QtGui.QDoubleSpinBox()
        self.trigger_level.setToolTip(tt.tooltips['trigger_level'])
        self.trigger_level.setRange(0.0001, 1000000)
        self.trigger_level.setValue(DEFAULTS['trigger_level'])
        trigger_level_label = QtGui.QLabel('Trigger level (excitation)')
        signal_grid.addWidget(trigger_level_label, 6, 0)
        signal_grid.addWidget(self.trigger_level, 6, 2)
        self.fields['trigger_level'] = self.trigger_level.value

        # Pre trigger samples.
        self.pre_trigger = QtGui.QSpinBox()
        self.pre_trigger.setToolTip(tt.tooltips['pre_trigger_samples'])
        self.pre_trigger.setRange(0, self.win_length.value())
        self.pre_trigger.setValue(DEFAULTS['pre_trigger_samples'])
        # self.win_length.valueChanged.connect(lambda: self.pre_trigger.setRange(0, self.win_length.value()))
        pre_trigger_label = QtGui.QLabel('Pre-trigger samples')
        pre_trigger_unit = QtGui.QLabel('S')
        signal_grid.addWidget(pre_trigger_label, 7, 0)
        signal_grid.addWidget(self.pre_trigger, 7, 2)
        signal_grid.addWidget(pre_trigger_unit, 7, 3)
        self.fields['pre_trigger_samples'] = self.pre_trigger.value

        # Check if task is already set and if it is, fill saved values.
        if 'task_name' in self.settings:
            self.win_length.setValue(self.settings['samples_per_channel'])
            self.exc_win.setCurrentIndex([i for i, win in enumerate(_WINDOWS) if win in self.settings['exc_window']][0])
            exc_win_percent.setValue(float(self.settings['exc_window'].split(':')[1])*100)
            self.resp_win.setCurrentIndex([i for i, win in enumerate(_WINDOWS) if win in self.settings['resp_window']][0])
            resp_win_percent.setValue(float(self.settings['resp_window'].split(':')[1])*100)
            self.avg_type.setCurrentIndex([i for i, avgt in enumerate(_WGH_TYPES) if avgt in self.settings['weighting']][0])
            avg_sample_number.setValue(self.settings['n_averages'])
            self.trigger_level.setValue(self.settings['trigger_level'])
            self.pre_trigger.setValue(self.settings['pre_trigger_samples'])
            zero_padding.setValue(self.settings['zero_padding'])
            save_time_history.setChecked(self.settings['save_time_history'])


        if 'excitation_type' in self.settings:
            if self.settings['excitation_type'] == 'impulse':
                self.radio_impulse.setChecked(True)
            elif self.settings['excitation_type'] == 'random':
                self.radio_random.setChecked(True)
            elif self.settings['excitation_type'] == 'oma':
                self.radio_oma.setChecked(True)
        else:
            self.radio_impulse.setChecked(True)

        signal_grid.setColumnStretch(1, 5)
        signal_grid.setColumnStretch(4, 15)

        groupb_box = QtGui.QGroupBox()
        groupb_box.setTitle('Signal ')
        # groupb_box.setStyleSheet("QGroupBox {font-size: 16px;}")
        groupb_box.setStyleSheet("QGroupBox {font-weight: bold;}")

        signal_vbox.addLayout(signal_hbox)
        signal_vbox.addWidget(task_status)
        signal_vbox.addLayout(signal_grid)

        groupb_box.setLayout(signal_vbox)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(group)
        vbox.addWidget(groupb_box)

        table = QtGui.QTableWidget(3, 5)
        table.setShowGrid(False)

        horizontal_header = table.horizontalHeader()

        table.setHorizontalHeaderLabels(['Name', 'Type', 'Units', 'Delay [ms]', ''])
        table.setVerticalHeaderLabels(['Channel {0}'.format(i+1) for i in range(3)])
        table.resizeColumnsToContents()
        header_view = table.horizontalHeader()
        header_view.setResizeMode(0, header_view.Stretch)
        # cw = QtGui.QPushButton('Bu')
        # header_view.setCornerWidget(cw)
        table.setDisabled(True)

        excitation_warning = QtGui.QLabel('')

        def refresh_table(names):
            """Populate table with channels for the chosen task."""
            table.setEnabled(True)
            # self.channel_table.setEnabled(True)
            i = len(names)
            table.setRowCount(i)
            table.setVerticalHeaderLabels(['Channel {0}'.format(i+1) for i in range(i)])
            # self.channel_table.ch

            if not ('task_name' in self.settings):
                for key in DEFAULTS.keys():
                    self.settings[key] = DEFAULTS[key]
            elif not(self.device_task.currentText() in self.settings['task_name'].decode()):
                for key in DEFAULTS.keys():
                    self.settings[key] = DEFAULTS[key]

            for i, name in enumerate(names):
                # First cell
                channel_name = QtGui.QTableWidgetItem(name)
                channel_name.setFlags(channel_name.flags() & ~QtCore.Qt.ItemIsEditable)
                table.setItem(i, 0, channel_name)

                # Type
                type = QtGui.QComboBox()
                type.addItem(self.tr('Response'))
                type.addItem(self.tr('Excitation'))
                # type.addItem(self.tr('Disabled'))
                if 'resp_channels' in self.settings and 'exc_channel' in self.settings:
                    if i in self.settings['resp_channels']:
                        type.setCurrentIndex(0)
                    elif i == self.settings['exc_channel']:
                        type.setCurrentIndex(1)

                # type.currentIndexChanged()
                table.setCellWidget(i, 1, type)

                # Units
                units = QtGui.QComboBox()
                if 'Excitation' in type.currentText():
                    # units.setEnabled(True)
                    if self.fields['excitation_type']() == 'oma':
                        units.addItems(_RESP_TYPES)
                    else:
                        units.addItems(_EXC_TYPES)
                elif 'Response' in type.currentText():
                    # units.setEnabled(True)
                    units.addItems(_RESP_TYPES)
                # elif 'Disabled' in type.currentText():
                #     units.setDisabled(True)
                # print(i, name)
                # print(self.settings['channel_types'])
                # print(self.fields['excitation_type']())
                if self.fields['excitation_type']() == 'oma':
                    try:
                        units.setCurrentIndex([num for num, letter in enumerate(_RESP_TYPES) if
                        self.settings['channel_types'][i] in letter][0])
                    except:
                        units.setCurrentIndex(0)
                elif 'channel_types' in self.settings and 'Excitation' in type.currentText():
                    units.setCurrentIndex([num for num, letter in enumerate(_EXC_TYPES) if
                    self.settings['channel_types'][i] in letter][0])
                elif 'channel_types' in self.settings and 'Response' in type.currentText():
                    try:
                        units.setCurrentIndex([num for num, letter in enumerate(_RESP_TYPES) if
                        self.settings['channel_types'][i] in letter][0])
                    except:
                        units.setCurrentIndex(0)
                table.setCellWidget(i, 2, units)

                # Delay.
                delay = QtGui.QDoubleSpinBox()
                delay.setRange(-5000, 5000)
                delay.setDecimals(3)
                # print (self.settings['channel_delay'])
                if 'channel_delay' in self.settings:
                    delay.setValue(self.settings['channel_delay'][i]*1000)
                table.setCellWidget(i, 3, delay)
            # Implement Excitation channel number checking. Also updating units field appropriately.
            def excitation_check(nr):

                for u in range(nr):
                    if 'Excitation' in table.cellWidget(u, 1).currentText():
                        # table.cellWidget(u, 2).setEnabled(True)
                        table.cellWidget(u, 2).clear()
                        table.cellWidget(u, 2).addItems(_EXC_TYPES)
                    elif 'Response' in table.cellWidget(u, 1).currentText():
                        # table.cellWidget(u, 2).setEnabled(True)
                        table.cellWidget(u, 2).clear()
                        table.cellWidget(u, 2).addItems(_RESP_TYPES)
                    # elif 'Disabled' in table.cellWidget(u, 1).currentText():
                    #     table.cellWidget(u, 2).setDisabled(True)


                excitation_channels = [i for i in range(nr) if 'Excitation' in table.cellWidget(i, 1).currentText()]
                if len(excitation_channels) > 1:
                    excitation_warning.setText('''<span style="font-weight: bold; color: red;">There should be exactly one'''
                                               ''' excitation channel!</span>''')
                    self.save.setDisabled(True)
                elif len(excitation_channels) < 1:
                    excitation_warning.setText('''<span style="font-weight: bold; color: red;">There should be exactly one'''
                                               ''' excitation channel!</span>''')
                else:
                    excitation_warning.setText('')
                    self.save.setEnabled(True)

            nr = len(names)
            for i in range(nr):
                table.cellWidget(i, 1).currentIndexChanged.connect(lambda: excitation_check(nr))


            table.resizeColumnsToContents()
            horizontal_header.setStretchLastSection(True)

        table.setAlternatingRowColors(True)





        table_title = QtGui.QLabel('Channels')
        table_title.setStyleSheet("QLabel {font-weight: bold;}")

        table_title_layout = QtGui.QHBoxLayout()
        table_title_layout.addWidget(table_title)
        table_title_layout.addWidget(excitation_warning)

        vbox.addLayout(table_title_layout)
        vbox.addWidget(table)

        # Preview window.
        preview_window = pg.GraphicsView()
        preview_window.setMinimumHeight(300)
        v_graphic_layout = QtGui.QVBoxLayout()
        h_button_layout = QtGui.QHBoxLayout()
        self.fig = pg.PlotWidget(name='Signal preview')
        self.fig.setLabel('bottom', 'time', units='s')
        self.fig.setLabel('left', 'amplitude')

        self.fig_plotitem = self.fig.getPlotItem()

        self.button_testrun = QtGui.QPushButton('Test Run')
        self.button_testrun.setToolTip(tt.tooltips['test_run'])
        self.button_testrun.setObjectName('small')
        self.button_testrun.setCheckable(True)
        self.button_testrun.setDisabled(True)
        def testrun_start_agent(pressed):
            if pressed:
                self.measure_test_run_data()
            else:
                self.stop_measurement_button_trigger()
        self.button_testrun.clicked[bool].connect(testrun_start_agent)

        self.button_fft = QtGui.QPushButton('PSD Toggle')
        self.button_fft.setToolTip(tt.tooltips['toggle_PSD'])
        self.button_fft.setObjectName('small')
        self.button_fft.setCheckable(True)
        self.button_fft.clicked[bool].connect(self.fft_toggle)

        h_button_layout.addStretch()
        h_button_layout.addWidget(self.button_testrun)
        h_button_layout.addWidget(self.button_fft)
        h_button_layout.addStretch()

        # splitter = QtGui.QSplitter(QtCore.Qt.Vertical)

        # v_graphic_layout.addWidget(splitter)

        v_graphic_layout.addLayout(h_button_layout)
        # splitter.addLayout(h_button_layout)
        # v_graphic_layout.addWidget(splitter)
        v_graphic_layout.addWidget(self.fig)
        # splitter.addWidget(self.fig)
        preview_window.setLayout(v_graphic_layout)
        # preview_window.setLayout(splitter)

        # vbox.addWidget(preview_window)

        channel_widget.setLayout(vbox)

        vbox.setContentsMargins(0, 0, 0, 0)

        def load_task(reset=False):
            if 'refresh  ' in self.device_task.currentText():
                self._refresh_tasks_list()
            else:
                try:
                    # TODO: Check for required buffer size and availible buffer.
                # i = dq.DAQTask(self.device_task.currentText().encode())
                    i = dq.DAQTask(self.device_task.currentText().encode())

                    channel_list = list(map(bytes.decode, i.channel_list))

                    i.clear_task(wait_until_done=False)

                    # if i.sample_rate < 2000:
                    #     task_status.setText('<span style="color: orange;"><b>Sampling rate should be at least 2 kHz.</b></span>')
                    #     table.setDisabled(True)
                    #     self.save.setDisabled(True)
                    # else:

                    combos = [QtGui.QComboBox() for channel in channel_list]
                    labels = [QtGui.QLabel(channel) for channel in channel_list]

                    # task_status.setText("""<span style="color: green;">Sampling rate: <b>{0:.0f} S/s</b>, """
                    #                     """Samples to read: <b>{1:.0f} S</b><br />"""
                    #                     """Nr. of channels: <b>{2:.0f}</b></span>""".format(i.sample_rate,
                    #                                                                 i.samples_per_ch, len(channel_list)))

                    task_status.setText("""<span style="color: green;">Sampling rate: <b>{0:.0f} S/s</b>, """
                                        """Nr. of channels: <b>{1:.0f}</b></span>""".format(i.sample_rate,
                                                                                    len(channel_list)))


                    # Reset settings on task change except when opening up saved state.
                    if 'task_name' in self.settings:
                        if self.settings['task_name'] == self.device_task.currentText().encode():
                            pass
                        else:
                            self.win_length.setValue(i.samples_per_ch)
                    else:
                        self.win_length.setValue(i.samples_per_ch)

                    self.channel_nr = len(channel_list)
                    refresh_table(channel_list)
                    self.save.setEnabled(True)
                    self.button_testrun.setEnabled(True)

                    # Run measurement thread.
                    # self.measure_test_run_process_start()

                    # table.setEnabled(True)

                except dq.DAQError:
                    task_status.setText('<span style="color: orange;"><b>Device malfunction.</b></span>')
                    table.setDisabled(True)
                    # table.setDisabled(True)
                    self.save.setDisabled(True)

        # Check if task is already set, then select it.
        self.device_task.currentIndexChanged.connect(load_task)
        self.measurement_type_change.connect(load_task)
        if 'task_name' in self.settings:
            tasks = map(bytes.decode, dq.get_daq_tasks())
            arglist = [n for n, task in enumerate(tasks) if self.settings['task_name'].decode() in task]
            if len(arglist) > 0:
                self.device_task.setCurrentIndex(arglist[0]+1)

        return table, channel_widget, preview_window