Пример #1
0
    def run(self, num_experiments=100, num_steps=50000):

        progress_bar = tqdm(total=len(self.agents) * num_experiments)
        for named_bandit, agent in zip(self.named_bandits, self.agents):
            regret = []
            avg_regret = []
            for j in range(num_experiments):
                exp = Experiment(named_bandit.bandit, agent)
                exp.run(num_steps)
                regret.append(exp.regrets_alternative)
                avg_regret.append(exp.avg_regrets_alternative)
                progress_bar.update(1)

            dir = f'data/bandit_{named_bandit.name}/regret'
            if not os.path.exists(dir):
                os.makedirs(dir)
            with open(f'{dir}/{str(agent(named_bandit.bandit))}.pickle',
                      'wb') as fp:
                pickle.dump(regret, fp)

            dir = f'data/bandit_{named_bandit.name}/avg_regret'
            if not os.path.exists(dir):
                os.makedirs(dir)

            with open(f'{dir}/{str(agent(named_bandit.bandit))}.pickle',
                      'wb') as fp:
                pickle.dump(avg_regret, fp)
Пример #2
0
def exp_no_wikipage_or_subentries(expprops):
    confighandler = ExpConfigHandler(pathscheme='test1')
    experiment = Experiment(confighandler=confighandler,
                            props=expprops,
                            autoattachwikipage=False,
                            doparseLocaldirSubentries=False)
    return experiment
Пример #3
0
def experiment_with_ch(fakeconfighandler):
    ch = fakeconfighandler
    subdir = ch.getAbsExpPath('local_exp_subDir')
    foldername = 'RS001 Pytest test experiment'
    localdir = os.path.join(subdir, foldername)
    if not os.path.isdir(localdir):
        logger.info("Creating dir (os.makedirs): %s", localdir)
        os.makedirs(localdir)
    e = Experiment(confighandler=ch, localdir=localdir)
    return e
Пример #4
0
 def add_experiment(self, info, user_id):
     try:
         experiment = Experiment()
         experiment.name = info.get('name')
         experiment.start_time = time2datetime(info.get('start_time'))
         experiment.end_time = time2datetime(info.get('end_time'))
         if experiment.start_time > experiment.end_time:
             raise Exception(u"开始时间不能大于结束时间")
         experiment.remark = info.get('remark')
         experiment.lab_no = info.get('lab_no')
         experiment.teacher_id = user_id
         experiment.status = Experiment.Status.PROCESS
         db.session.add(experiment)
         db.session.commit()
     except Exception as e:
         db.session.rollback()
         raise Exception(e)
Пример #5
0
import threading
from time import sleep

from model.experiment import Experiment


experiment = Experiment()
experiment.load_config('experiment.yml')
experiment.initialize()
t = threading.Thread(target=experiment.start_scan)
t.start()
while t.is_alive():
    print(experiment.i)
    sleep(1)
    experiment.keep_running = False


experiment.save_data()
def get_experiment_by_id(exp_id):
    doc = es.get_document_by_id(e_idx, exp_id)
    if doc:
        return Experiment.from_es_data(doc['_source'])

    return None
Пример #7
0
 def on_comboBox_dev_list_activated(self):
     device_name = self.ui.comboBox_dev_list.currentText()
     self.print_qt(f'Device selected: {device_name}')
     streaming_device_model = self.devices_name_to_model[device_name]
     self.e = Experiment(streaming_device_model(device_name))
     self.configure_gui()
Пример #8
0
class TwingoExec:

    def __init__(self):
        #self.mutex = QtCore.QMutex()

        app = QtWidgets.QApplication(sys.argv)
        apply_dark_theme(app)

        MainWindow = QtWidgets.QMainWindow()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(MainWindow)

        self.SETTINGS_TAB_INDEX = 0
        self.CONTINUOUS_MEAS_TAB_INDEX = 1
        self.CM_TIMESERIES_TAB_INDEX = 0
        self.CM_SPECTRUM_TAB_INDEX = 1
        self.CM_PHASE_TAB_INDEX = 2

        self.FINITE_MEAS_TAB_INDEX = 2
        self.FM_TIMESERIES_TAB_INDEX = 0
        self.FM_SPECTRUM_TAB_INDEX = 1
        self.FM_SPECTROGRAM_TAB_INDEX = 2

        self.ui.tabWidget_main.setCurrentIndex(self.SETTINGS_TAB_INDEX)
        self.ui.tabWidget_fm.setCurrentIndex(self.FM_TIMESERIES_TAB_INDEX)
        self.ui.tabWidget_cm.setCurrentIndex(self.CM_TIMESERIES_TAB_INDEX)

        self.ui.tabWidget_main.setTabEnabled(self.FINITE_MEAS_TAB_INDEX, False)
        self.ui.tabWidget_main.setTabEnabled(self.CONTINUOUS_MEAS_TAB_INDEX, False)

        if config.NR_OF_CHANNELS_TO_PLOT < 2:
            self.ui.tabWidget_cm.setTabEnabled(self.CM_PHASE_TAB_INDEX, False)

        # plot widgets:
        self.cm_tm_plot_widget = None
        self.cm_sp_plot_widget = None
        self.cm_ph_plot_widget = None
        self.fm_tm_plot_widget = None
        self.fm_sp_plot_widget = None
        self.fm_spg_widget = None
        self.graphics_plot = None
        self.img = None
        self.hist = None

        # plot hold functionality
        self.fm_tm_plot_data_items = []
        self.fm_sp_plot_data_items = []

        self.fm_tm_plot_hold_data_items = []
        self.fm_sp_plot_hold_data_items = []

        self.cm_tm_plot_data_items = []
        self.cm_sp_plot_data_items = []
        self.cm_ph_plot_data_item = None
        self.cm_ph_plot_box_data_item = []

        self.cm_sp_plot_hold_data_items = []
        self.cm_tm_plot_hold_data_items = []
        self.cm_ph_plot_hold_data_items = []

        self.pen_case = \
            [pg.mkPen(color=chan_index + config.PLOT_COLOR_MODIFIER_INT) for chan_index in
             range(config.NR_OF_CHANNELS_TO_PLOT)]

        self.hold_pen_case = \
            [pg.mkPen(color=chan_index + config.PLOT_COLOR_MODIFIER_INT, style=QtCore.Qt.DotLine) for chan_index in
             range(config.NR_OF_CHANNELS_TO_PLOT)]

        self.place_fm_tm_graph()
        self.place_fm_sp_graph()
        self.place_fm_spg_graphics()
        self.place_cm_tm_graph()
        self.place_cm_sp_graph()
        self.place_cm_ph_graph()
        self.connect_gui_signals()

        # paint the background of hold items with the same color as pen assigned to hold plots:
        hold_checkbox_style_sheet_strings = \
            [f'color: rgb(0, 0, 0); background-color:rgb{self.pen_case[chan_index].color().getRgb()}' for
             chan_index in range(config.NR_OF_CHANNELS_TO_PLOT)]

        try:
            self.ui.checkBox_fm_tm_hold_a.setStyleSheet(hold_checkbox_style_sheet_strings[0])
            self.ui.checkBox_fm_sp_hold_a.setStyleSheet(hold_checkbox_style_sheet_strings[0])
            self.ui.checkBox_cm_tm_hold_a.setStyleSheet(hold_checkbox_style_sheet_strings[0])
            self.ui.checkBox_cm_sp_hold_a.setStyleSheet(hold_checkbox_style_sheet_strings[0])
            self.ui.checkBox_fm_tm_hold_b.setStyleSheet(hold_checkbox_style_sheet_strings[1])
            self.ui.checkBox_fm_sp_hold_b.setStyleSheet(hold_checkbox_style_sheet_strings[1])
            self.ui.checkBox_cm_tm_hold_b.setStyleSheet(hold_checkbox_style_sheet_strings[1])
            self.ui.checkBox_cm_sp_hold_b.setStyleSheet(hold_checkbox_style_sheet_strings[1])
        except IndexError as exc:
            print(exc)

        self.buffer_indicator_timer = QtCore.QTimer()
        self.buffer_indicator_timer.timeout.connect(self.update_output_buffer_indicator)

        # self.timeseries_timer = QtCore.QTimer()
        # self.timeseries_timer.timeout.connect(self.update_cm_timeseries_plot)

        self.devices_name_to_model = None
        self.e = None

        MainWindow.show()
        sys.exit(app.exec_())

    def connect_gui_signals(self):
        self.ui.tabWidget_main.currentChanged.connect(self.on_tabWidget_main_changed)

        # settings tab:
        self.ui.pushButton_detectDAQ.clicked.connect(self.on_pushButton_detectDAQ_clicked)
        self.ui.comboBox_dev_list.activated.connect(self.on_comboBox_dev_list_activated)
        self.ui.comboBox_ai_a.activated.connect(self.on_comboBox_ai_ab_activated)
        self.ui.comboBox_ai_b.activated.connect(self.on_comboBox_ai_ab_activated)
        self.ui.comboBox_ao_a.activated.connect(self.on_comboBox_ao_ab_activated)
        self.ui.comboBox_ao_b.activated.connect(self.on_comboBox_ao_ab_activated)
        self.ui.comboBox_ai_terminal_cfg.activated.connect(self.on_comboBox_ai_terminal_cfg_activated)
        self.ui.comboBox_ai_max.activated.connect(self.on_comboBox_ai_min_max_activated)
        self.ui.comboBox_ai_min.activated.connect(self.on_comboBox_ai_min_max_activated)
        self.ui.comboBox_ao_max.activated.connect(self.on_comboBox_ao_min_max_activated)
        self.ui.comboBox_ao_min.activated.connect(self.on_comboBox_ao_min_max_activated)
        self.ui.comboBox_ai_fs.activated.connect(self.on_comboBox_ai_fs_activated)
        self.ui.comboBox_ao_fs.activated.connect(self.on_comboBox_ao_fs_activated)
        self.ui.comboBox_ao_max.activated.connect(self.on_comboBox_ao_max_activated)

        # common widgets
        self.ui.comboBox_sig_len.activated.connect(self.on_comboBox_sig_len_activated)
        self.ui.comboBox_out_sig_type.activated.connect(self.on_comboBox_out_sig_activated)
        self.ui.lineEdit_min_f.editingFinished.connect(self.on_lineEdit_min_f_editingFinished)
        self.ui.lineEdit_max_f.editingFinished.connect(self.on_lineEdit_max_f_editingFinished)
        self.ui.pushButton_start.clicked.connect(self.on_pushButton_start_clicked)
        self.ui.pushButton_stop.clicked.connect(self.on_pushButton_stop_clicked)

        # finite measurement widgets
        self.ui.tabWidget_fm.currentChanged.connect(self.update_current_fm_plot)
        # timeseries
        self.ui.checkBox_fm_tm_hold_a.toggled.connect(self.hold_fm_tm_plot_a)
        self.ui.checkBox_fm_tm_hold_b.toggled.connect(self.hold_fm_tm_plot_b)
        # spectrum
        self.ui.comboBox_fm_window_size.activated.connect(self.on_comboBox_fm_window_size_activated)
        self.ui.comboBox_fm_window_type.activated.connect(self.on_comboBox_fm_window_type_activated)
        self.ui.checkBox_fm_sp_hold_a.toggled.connect(self.on_checkBox_fm_sp_hold_a_toggled)
        self.ui.checkBox_fm_sp_hold_b.toggled.connect(self.on_checkBox_fm_sp_hold_b_toggled)
        # spectrogram
        self.ui.checkBox_fm_spg_log_amp.toggled.connect(self.update_fm_spg)
        self.ui.comboBox_fm_spg_window_size.activated.connect(self.on_comboBox_fm_spg_window_size_activated)
        self.ui.comboBox_fm_spg_chan.activated.connect(self.on_comboBox_fm_spg_chan_activated)
        self.ui.comboBox_fm_spg_window_type.activated.connect(self.on_comboBox_fm_spg_window_type_activated)

        # continuous measurement widgets
        self.ui.tabWidget_cm.currentChanged.connect(self.on_tabWidget_cm_changed)
        # timeseries
        self.ui.checkBox_cm_tm_hold_a.toggled.connect(self.on_checkBox_cm_tm_hold_a_toggled)
        self.ui.checkBox_cm_tm_hold_b.toggled.connect(self.on_checkBox_cm_tm_hold_b_toggled)
        # spectrum
        self.ui.comboBox_cm_window_type.activated.connect(self.on_comboBox_cm_window_type_activated)
        self.ui.comboBox_cm_window_size.activated.connect(self.on_comboBox_cm_window_size_activated)
        self.ui.checkBox_cm_sp_hold_a.toggled.connect(self.on_checkBox_cm_sp_hold_a_toggled)
        self.ui.checkBox_cm_sp_hold_b.toggled.connect(self.on_checkBox_cm_sp_hold_b_toggled)
        # phase
        self.ui.comboBox_cm_ph_window_size.activated.connect(self.on_comboBox_cm_ph_window_size_activated)
        self.ui.checkBox_cm_ph_hold_1.toggled.connect(self.on_checkBox_cm_ph_hold_1_toggled)
        self.ui.checkBox_cm_ph_hold_2.toggled.connect(self.on_checkBox_cm_ph_hold_2_toggled)

        # common
        self.ui.dial_cm_vfine_freq.valueChanged.connect(self.on_dial_value_changed)
        self.ui.dial_cm_fine_freq.valueChanged.connect(self.on_dial_value_changed)
        self.ui.dial_cm_coarse_freq.valueChanged.connect(self.on_dial_value_changed)

    def get_dials_value(self):
        return self.ui.dial_cm_vfine_freq.value() + \
               self.ui.dial_cm_fine_freq.value() + \
               self.ui.dial_cm_coarse_freq.value()

    def on_comboBox_sig_len_activated(self):
        self.e.streaming_device.set_mode_to_finite(float(self.ui.comboBox_sig_len.currentText()))

    def on_dial_value_changed(self):
        new_value = self.get_dials_value()
        self.e.streaming_device.function_gen.set_frequency(new_value)
        self.ui.lineEdit_max_f.setText(str(new_value))
        self.ui.lcdNumber.display(new_value)

    def on_comboBox_fm_window_type_activated(self):
        self.e.set_fm_sp_window(win_type=self.ui.comboBox_fm_window_type.currentText())
        self.update_current_fm_plot()

    def on_comboBox_fm_window_size_activated(self):
        self.e.set_fm_sp_window(win_size=int(self.ui.comboBox_fm_window_size.currentText()))
        self.update_current_fm_plot()

    def on_comboBox_cm_window_type_activated(self):
        self.e.set_cm_sp_window(win_type=self.ui.comboBox_cm_window_type.currentText())

    def on_comboBox_cm_window_size_activated(self):
        self.e.set_cm_sp_window(win_size=int(self.ui.comboBox_cm_window_size.currentText())) #TODO RENAME THIS METHOD TO SET_CM_WINDOW

    def on_comboBox_cm_ph_window_size_activated(self):
        self.e.set_cm_ph_window(win_size=int(self.ui.comboBox_cm_ph_window_size.currentText()))

    def on_comboBox_fm_spg_chan_activated(self):
        self.e.set_fm_spg_chan(self.ui.comboBox_fm_spg_chan.currentIndex())
        self.update_fm_spg()

    def on_comboBox_fm_spg_window_type_activated(self):
        self.e.set_fm_spg_window(win_type=self.ui.comboBox_fm_spg_window_type.currentText())
        self.update_fm_spg()

    def on_comboBox_fm_spg_window_size_activated(self):
        self.e.set_fm_spg_window(win_size=int(self.ui.comboBox_fm_spg_window_size.currentText()))
        self.update_fm_spg()

    def on_comboBox_ai_ab_activated(self):
        # TODO some callbacks are coded in the uic generated file already and they can theoretically create race
        #  condition with the checks below. Its probably a good idea to remove the callbacks from Designer and hard
        #  code them here by creating separate, dedicated  "on_comboBox_index_changed" callbacks for each  that
        #  contain both functionalities without allowing race.
        self.e.streaming_device.ai_a_name = self.ui.comboBox_ai_a.currentText()
        self.e.streaming_device.ai_b_name = self.ui.comboBox_ai_b.currentText()
        self.print_qt(f'Input channels : A:{self.e.streaming_device.ai_a_name} B:{self.e.streaming_device.ai_b_name}')

    def on_comboBox_ao_ab_activated(self):
        self.e.streaming_device.ao_a_name = self.ui.comboBox_ao_a.currentText()
        self.e.streaming_device.ao_b_name = self.ui.comboBox_ao_b.currentText()
        self.print_qt(f'Output channels : A:{self.e.streaming_device.ao_a_name} B:{self.e.streaming_device.ao_b_name}')

    def on_comboBox_ai_min_max_activated(self):
        self.e.streaming_device.ai_min_val = float(self.ui.comboBox_ai_min.currentText())
        self.e.streaming_device.ai_max_val = float(self.ui.comboBox_ai_max.currentText())
        self.print_qt(f'Input voltage limit min:{self.e.streaming_device.ai_min_val}V,'
                      f' max:{self.e.streaming_device.ai_max_val}V')
        self.set_plot_limits()

    def on_comboBox_ao_min_max_activated(self):
        self.e.streaming_device.ao_min_val = float(self.ui.comboBox_ao_min.currentText())
        self.e.streaming_device.ao_max_val = float(self.ui.comboBox_ao_max.currentText())
        self.print_qt(f'Output voltage limit min:{self.e.streaming_device.ao_min_val}V,'
                      f' max:{self.e.streaming_device.ao_max_val}V')

    def on_comboBox_ai_terminal_cfg_activated(self):
        self.e.streaming_device.ai_terminal_config = self.ui.comboBox_ai_terminal_cfg.currentText()
        self.print_qt(f'Ai terminal config: {self.e.streaming_device.ai_terminal_config}')

    def print_qt(self, message, suppress_console=True):
        if suppress_console is False:
            print(message)
        self.ui.statusbar.showMessage(message.__str__(), config.STATUS_BAR_MESSAGE_TIME_MS)

    def check_fm_data_present(self):
        if self.e.fm_result_y is None:
            raise NoInputData('No finite input data is available. Press START to run a measurement.')

    # TODO this is a lot pattern repetition. Perhaps some design pattern (prototype?) can be used to def any number
    #  of hold callbacks with equivalent functionality?
    def on_checkBox_cm_tm_hold_a_toggled(self):
        try:
            if self.ui.checkBox_cm_tm_hold_a.isChecked():
                self.cm_tm_plot_hold_data_items[0].setData(self.cm_tm_plot_data_items[0].xData,
                                                           self.cm_tm_plot_data_items[0].yData)
            else:
                self.cm_tm_plot_hold_data_items[0].clear()
        except Exception as exc:
            self.print_qt(exc)

    def on_checkBox_cm_tm_hold_b_toggled(self):
        try:
            if self.ui.checkBox_cm_tm_hold_b.isChecked():
                self.cm_tm_plot_hold_data_items[1].setData(self.cm_tm_plot_data_items[1].xData,
                                                           self.cm_tm_plot_data_items[1].yData)
            else:
                self.cm_tm_plot_hold_data_items[1].clear()
        except Exception as exc:
            self.print_qt(exc)

    def on_checkBox_cm_sp_hold_a_toggled(self):
        try:
            if self.ui.checkBox_cm_sp_hold_a.isChecked():
                self.cm_sp_plot_hold_data_items[0].setData(self.cm_sp_plot_data_items[0].xData,
                                                           self.cm_sp_plot_data_items[0].yData)
            else:
                self.cm_sp_plot_hold_data_items[0].clear()
        except Exception as exc:
            self.print_qt(exc)

    def on_checkBox_cm_sp_hold_b_toggled(self):
        try:
            if self.ui.checkBox_cm_sp_hold_b.isChecked():
                self.cm_sp_plot_hold_data_items[1].setData(self.cm_sp_plot_data_items[1].xData,
                                                           self.cm_sp_plot_data_items[1].yData)
            else:
                self.cm_sp_plot_hold_data_items[1].clear()
        except Exception as exc:
            self.print_qt(exc)


    def on_checkBox_cm_ph_hold_1_toggled(self):
        try:
            if self.ui.checkBox_cm_ph_hold_1.isChecked():
                self.cm_ph_plot_hold_data_items[0].setData(self.cm_ph_plot_data_item.xData,
                                                           self.cm_ph_plot_data_item.yData)
            else:
                self.cm_ph_plot_hold_data_items[0].clear()
        except Exception as exc:
            self.print_qt(exc)

    def on_checkBox_cm_ph_hold_2_toggled(self):
        try:
            if self.ui.checkBox_cm_ph_hold_2.isChecked():
                self.cm_ph_plot_hold_data_items[1].setData(self.cm_ph_plot_data_item.xData,
                                                           self.cm_ph_plot_data_item.yData)
            else:
                self.cm_ph_plot_hold_data_items[1].clear()
        except Exception as exc:
            self.print_qt(exc)

    def hold_fm_tm_plot_a(self):  # TODO THIS SHOULD PROBABLY BE RENAMED
        try:
            if self.ui.checkBox_fm_tm_hold_a.isChecked():
                self.fm_tm_plot_hold_data_items[0].setData(self.fm_tm_plot_data_items[0].xData,
                                                           self.fm_tm_plot_data_items[0].yData)
            else:
                self.fm_tm_plot_hold_data_items[0].clear()
        except Exception as exc:
            self.print_qt(exc)

    def hold_fm_tm_plot_b(self):
        try:
            if self.ui.checkBox_fm_tm_hold_b.isChecked():
                self.fm_tm_plot_hold_data_items[1].setData(self.fm_tm_plot_data_items[1].xData,
                                                           self.fm_tm_plot_data_items[1].yData)
            else:
                self.fm_tm_plot_hold_data_items[1].clear()
        except Exception as exc:
            self.print_qt(exc)

    def on_checkBox_fm_sp_hold_a_toggled(self):
        try:
            if self.ui.checkBox_fm_sp_hold_a.isChecked():
                self.fm_sp_plot_hold_data_items[0].setData(self.fm_sp_plot_data_items[0].xData,
                                                           self.fm_sp_plot_data_items[0].yData)
            else:
                self.fm_sp_plot_hold_data_items[0].clear()
        except Exception as exc:
            self.print_qt(exc)

    def on_checkBox_fm_sp_hold_b_toggled(self):
        try:
            if self.ui.checkBox_fm_sp_hold_b.isChecked():
                self.fm_sp_plot_hold_data_items[1].setData(self.fm_sp_plot_data_items[1].xData,
                                                           self.fm_sp_plot_data_items[1].yData)
            else:
                self.fm_sp_plot_hold_data_items[1].clear()
        except Exception as exc:
            self.print_qt(exc)

    def check_set_line_edit_number(self, line_edit_caller, casting_class, limits=None, num_on_exc=None):
        """
        Checks, and, if necessary, corrects user QLineEdit.text() entry.

        :param line_edit_caller: QLineEdit object we wish to check/correct .text() of.
        :param casting_class: One of the numeric built-in classes (int, float ...)
        that will be used to test if text can be casted to a specific numeric type.
        :param limits: (tuple) (min, max) limits for user input. If exceeded user input will be clipped
        to either limit respectively.
        :param num_on_exc: Value which will overwrite user input in case it can not be
        casted to a specified numeric type.
        :return: numeric value corresponding to accepted/corrected QlineEdit.text().
        """
        # override the number to return on exception in case its supplied out of the limits required.
        # It can happen if the previous value is used equal to the value in lineEdit from before callback while
        # meantime a property determining the limits was changed (e.g. fs was reduced so max allowed freq is now
        # less than what is entered into freq0 field). In this case defaulting to the previous value on
        # exception is not ok. Therefore num_on_exc has got to be fixed to the closest limit...
        if limits is not None:
            num_on_exc = limit(num_on_exc, limits)

        try:
            num = casting_class(line_edit_caller.text())

            if limits is not None:  # TODO ...but it leads to code repetition which makes me wanna cry
                num_within_limit = limit(num, limits)
                if num_within_limit != num:
                    raise LimitExceeded(f'Value {num} exceeded limits: {limits[0]}-{limits[1]}.')

        except ValueError as err:
            print(err)
            self.print_qt(f'Input must be numeric {casting_class}.')
            line_edit_caller.setText(str(num_on_exc))
            return num_on_exc

        except LimitExceeded as err:
            self.print_qt(err)
            line_edit_caller.setText(str(num_within_limit))
            return num_within_limit

        return num

    def on_comboBox_ao_fs_activated(self):
        self.e.streaming_device.set_ao_fs(float(self.ui.comboBox_ao_fs.currentText()))
        self.print_qt(f'Output sampling rate changed: {self.e.streaming_device.ao_fs}Hz.')
        # recalculate new max for coarse dial and realign all dials
        new_max_dial_rng = self.e.streaming_device.ao_fs // 2 - self.ui.dial_cm_fine_freq.maximum() - self.ui.dial_cm_vfine_freq.maximum()
        new_max_dial_rng = limit(new_max_dial_rng, (0, config.MAX_COARSE_FREQ_DIAL_LIMIT))
        self.ui.dial_cm_coarse_freq.setRange(0, new_max_dial_rng)
        self.align_dials_position()

    def on_comboBox_ai_fs_activated(self):
        self.e.streaming_device.set_ai_fs(float(self.ui.comboBox_ai_fs.currentText()))
        self.print_qt(f'Input sampling rate changed: {self.e.streaming_device.ai_fs}Hz.')
        self.e.set_cm_freq_base()

    def on_lineEdit_min_f_editingFinished(self):
        prev_value = self.e.streaming_device.function_gen.freq0
        min_value = config.MIN_OUTPUT_FREQUENCY_ALLOWED
        max_value = self.e.streaming_device.ao_fs / 2
        new_value = self.check_set_line_edit_number(self.ui.lineEdit_min_f, float,
                                                    limits=(min_value, max_value),
                                                    num_on_exc=prev_value)
        if new_value == prev_value:
            return
        self.e.streaming_device.function_gen.set_start_frequency(new_value)
        self.print_qt(f'Start frequency changed: {self.e.streaming_device.function_gen.freq0}Hz.')

    def on_lineEdit_max_f_editingFinished(self):
        prev_value = self.e.streaming_device.function_gen.freq1
        min_value = config.MIN_OUTPUT_FREQUENCY_ALLOWED
        max_value = self.e.streaming_device.ao_fs / 2
        new_value = self.check_set_line_edit_number(self.ui.lineEdit_max_f, float,
                                                    limits=(min_value, max_value),
                                                    num_on_exc=prev_value)
        if new_value == prev_value:
            return
        self.e.streaming_device.function_gen.set_frequency(new_value)
        self.print_qt(f'Set/End frequency changed: {self.e.streaming_device.function_gen.freq1}Hz.')
        self.ui.lcdNumber.display(new_value)
        # ensure dials are in consistent position with the current set freq. and allow exploration in its vicinity
        self.align_dials_position()

    def align_dials_position(self):
        new_value = self.e.streaming_device.function_gen.freq1
        self.ui.dial_cm_vfine_freq.blockSignals(True)
        self.ui.dial_cm_fine_freq.blockSignals(True)
        self.ui.dial_cm_coarse_freq.blockSignals(True)
        if new_value <= self.ui.dial_cm_vfine_freq.maximum() // 2:
            self.ui.dial_cm_vfine_freq.setValue(new_value)
            self.ui.dial_cm_fine_freq.setValue(0)
            self.ui.dial_cm_coarse_freq.setValue(0)
        elif new_value <= self.ui.dial_cm_fine_freq.maximum() // 2:
            self.ui.dial_cm_vfine_freq.setValue(self.ui.dial_cm_vfine_freq.maximum() // 2)
            self.ui.dial_cm_fine_freq.setValue(new_value - self.ui.dial_cm_vfine_freq.value())
            self.ui.dial_cm_coarse_freq.setValue(0)
        elif new_value <= self.ui.dial_cm_coarse_freq.maximum():
            self.ui.dial_cm_vfine_freq.setValue(self.ui.dial_cm_vfine_freq.maximum() // 2)
            self.ui.dial_cm_fine_freq.setValue(self.ui.dial_cm_fine_freq.maximum() // 2)
            self.ui.dial_cm_coarse_freq.setValue(new_value - self.ui.dial_cm_vfine_freq.value()
                                                 - self.ui.dial_cm_fine_freq.value())
        elif new_value > self.ui.dial_cm_coarse_freq.maximum():
            self.ui.dial_cm_vfine_freq.setValue(self.ui.dial_cm_vfine_freq.maximum() // 2)
            self.ui.dial_cm_fine_freq.setValue(self.ui.dial_cm_fine_freq.maximum() // 2)
            self.ui.dial_cm_coarse_freq.setValue(self.ui.dial_cm_coarse_freq.maximum())

        self.ui.dial_cm_vfine_freq.blockSignals(False)
        self.ui.dial_cm_fine_freq.blockSignals(False)
        self.ui.dial_cm_coarse_freq.blockSignals(False)

    def on_comboBox_ao_max_activated(self):
        self.e.streaming_device.function_gen.set_amplitude(float(self.ui.comboBox_ao_max.currentText()))
        print(f'Output signal amplitude changed to {self.e.streaming_device.function_gen.amplitude}V.')

    def on_comboBox_out_sig_activated(self):
        self.e.streaming_device.function_gen.set_function(self.ui.comboBox_out_sig_type.currentText())
        #print(f'Output signal function changed to {self.e.streaming_device.function_gen.current_function'})

    def on_tabWidget_main_changed(self):
        if self.ui.tabWidget_main.currentIndex() == self.FINITE_MEAS_TAB_INDEX:
            self.e.streaming_device.set_mode_to_finite(float(self.ui.comboBox_sig_len.currentText()))
            self.ui.comboBox_sig_len.setEnabled(True)
        elif self.ui.tabWidget_main.currentIndex() == self.CONTINUOUS_MEAS_TAB_INDEX:
            self.e.streaming_device.set_mode_to_continuous()
            self.ui.comboBox_sig_len.setEnabled(False)
        elif self.ui.tabWidget_main.currentIndex() == self.SETTINGS_TAB_INDEX:
            pass
        else:
            # reminder for future expansion of tabs
            self.print_qt('WARNING: This tab does not define a specific streaming device mode')

    def update_current_fm_plot(self):
        try:
            if self.ui.tabWidget_fm.currentIndex() == self.FM_TIMESERIES_TAB_INDEX:
                self.update_fm_tm_plot()
            elif self.ui.tabWidget_fm.currentIndex() == self.FM_SPECTRUM_TAB_INDEX:
                self.update_fm_sp_plot()
            elif self.ui.tabWidget_fm.currentIndex() == self.FM_SPECTROGRAM_TAB_INDEX:
                self.update_fm_spg()
            else:
                pass
        except NoInputData as exc:
            self.print_qt(exc)

    def on_pushButton_detectDAQ_clicked(self):
        self.devices_name_to_model = io_streaming_device_discovery()
        self.ui.comboBox_dev_list.clear()
        for name in self.devices_name_to_model:
            self.ui.comboBox_dev_list.addItem(name)

        self.ui.comboBox_dev_list.showPopup()

        if self.ui.comboBox_dev_list.count() == 1:  # if only one device found use it by default
            self.on_comboBox_dev_list_activated()

        if self.ui.comboBox_dev_list.count() == 0:
            self.print_qt("No DAQ devices found and/or supporting packages (pyaudio / nidaqmx) are not installed.",
                          suppress_console=False)

    def on_comboBox_dev_list_activated(self):
        device_name = self.ui.comboBox_dev_list.currentText()
        self.print_qt(f'Device selected: {device_name}')
        streaming_device_model = self.devices_name_to_model[device_name]
        self.e = Experiment(streaming_device_model(device_name))
        self.configure_gui()

    def set_plot_limits(self):

        x_min = self.e.streaming_device.ai_min_val
        x_max = self.e.streaming_device.ai_max_val
        y_min = self.e.streaming_device.ai_min_val
        y_max = self.e.streaming_device.ai_max_val

        plot_items = [self.fm_tm_plot_widget.getPlotItem(),
                      self.cm_tm_plot_widget.getPlotItem()]

        for plot_item in plot_items:
            plot_item.vb.setLimits(yMin=y_min*1.1, yMax=y_max*1.1)
            plot_item.setRange(yRange=(y_min*1.1, y_max*1.1), disableAutoRange=True)

        phase_box_x = np.array([x_min, x_max, x_max, x_min, x_min])*config.PHASE_PLOT_OPTIMAL_WIDTH
        phase_box_y = np.array([y_min, y_min, y_max, y_max, y_min])
        self.cm_ph_plot_box_data_item.setData(phase_box_x, phase_box_y)

        cm_ph_plot_item = self.cm_ph_plot_widget.getPlotItem()
        cm_ph_plot_item.vb.setLimits(xMin=x_min*1.1, xMax=x_max*1.1, yMin=y_min*1.1, yMax=y_max*1.1)
        cm_ph_plot_item.setRange(xRange=(x_min*1.1, x_max*1.1), yRange=(y_min*1.1, y_max*1.1), disableAutoRange=True)

        cm_ph_text_m = pg.TextItem(text='M', anchor=(0.5, 0.5))#, color=(256, 256, 256))
        cm_ph_text_a = pg.TextItem(text='A', anchor=(0.5, 0.5))
        cm_ph_text_b = pg.TextItem(text='B', anchor=(0.5, 0.5))

        cm_ph_text_m.setPos(0, y_max*0.9)
        cm_ph_text_a.setPos(-x_max*0.5, y_max*0.5)
        cm_ph_text_b.setPos(x_max*0.5, y_max*0.5)

        cm_ph_plot_item.addItem(cm_ph_text_m)
        cm_ph_plot_item.addItem(cm_ph_text_a)
        cm_ph_plot_item.addItem(cm_ph_text_b)

        #  TODO add limits for the spectral graphs and disable auto range

    def configure_gui(self):
        self.set_settings_page()
        self.ui.lineEdit_min_f.setText(str(self.e.streaming_device.function_gen.freq0))
        self.ui.lineEdit_max_f.setText(str(self.e.streaming_device.function_gen.freq1))

        self.ui.comboBox_out_sig_type.setCurrentText(self.e.streaming_device.function_gen.current_function)
        self.ui.comboBox_sig_len.setCurrentText(str(self.e.streaming_device.finite_frame_len_sec))

        self.ui.comboBox_cm_window_type.setCurrentText(self.e.cm_sp_window_type) #  TODO Rename to cm_sp
        self.ui.comboBox_cm_window_size.setCurrentText(str(self.e.cm_sp_window_size)) #  TODO Rename to cm_sp

        self.ui.comboBox_cm_ph_window_size.setCurrentText(str(self.e.cm_ph_window_size))

        self.ui.comboBox_fm_window_type.setCurrentText(self.e.fm_sp_window_type)
        self.ui.comboBox_fm_window_size.setCurrentText(str(self.e.fm_sp_window_size))

        self.ui.comboBox_fm_spg_window_type.setCurrentText(self.e.fm_spg_window_type)
        self.ui.comboBox_fm_spg_window_type.setCurrentText(str(self.e.fm_spg_window_size))
        self.ui.comboBox_fm_spg_chan.setCurrentText(str(self.e.fm_spg_chan))

        self.align_dials_position()
        self.set_plot_limits()
        self.e.streaming_device.input_frame_ready_signal.connect(self.update_cm_tm_plot)

        self.ui.pushButton_start.setEnabled(True)
        self.ui.tabWidget_main.setTabEnabled(self.FINITE_MEAS_TAB_INDEX, True)
        self.ui.tabWidget_main.setTabEnabled(self.CONTINUOUS_MEAS_TAB_INDEX, True)

    def set_settings_page(self):
        self.set_comboBoxes_ai()
        self.set_comboBoxes_ao()
        self.set_comboBoxes_ai_range()
        self.set_comboBoxes_ao_range()
        self.set_comboBox_ai_config()
        self.set_comboBox_ai_fs()
        self.set_comboBox_ao_fs()
        self.set_comboBoxes_win_size()

    def set_comboBox_ai_fs(self):
        self.ui.comboBox_ai_fs.clear()
        self.ui.comboBox_ai_fs.addItems([str(item) for item in self.e.streaming_device.limits.supported_input_rates])

    def set_comboBox_ao_fs(self):
        self.ui.comboBox_ao_fs.clear()
        self.ui.comboBox_ao_fs.addItems([str(item) for item in self.e.streaming_device.limits.supported_output_rates])

    def set_comboBoxes_win_size(self):
        self.ui.comboBox_cm_window_size.clear()  # TODO RENAME to cm_sp
        self.ui.comboBox_cm_ph_window_size.clear()
        self.ui.comboBox_fm_window_size.clear()
        self.ui.comboBox_fm_spg_window_size.clear()
        list_of_win_sizes = [str(item) for item in self.e.streaming_device.limits.supported_monitor_frame_lengths]
        self.ui.comboBox_cm_window_size.addItems(list_of_win_sizes)  # TODO RENAME to cm_sp
        self.ui.comboBox_cm_ph_window_size.addItems(list_of_win_sizes)
        self.ui.comboBox_fm_window_size.addItems(list_of_win_sizes)
        self.ui.comboBox_fm_spg_window_size.addItems(list_of_win_sizes)

    def set_comboBoxes_ai(self):
        self.ui.comboBox_ai_a.clear()
        self.ui.comboBox_ai_b.clear()

        counter = 0
        for channel in self.e.streaming_device.limits.ai_physical_chans:
            if counter % 2 == 0:
                self.ui.comboBox_ai_a.addItem(channel)
            else:
                self.ui.comboBox_ai_b.addItem(channel)
            counter += 1

    def set_comboBoxes_ao(self):
        self.ui.comboBox_ao_a.clear()
        self.ui.comboBox_ao_b.clear()

        counter = 0
        for channel in self.e.streaming_device.limits.ao_physical_chans:
            if counter % 2 == 0:
                self.ui.comboBox_ao_a.addItem(channel)
            else:
                self.ui.comboBox_ao_b.addItem(channel)
            counter += 1

    def set_comboBoxes_ai_range(self):
        self.ui.comboBox_ai_max.clear()
        self.ui.comboBox_ai_min.clear()

        counter = 0
        # count backwards since ranges are listed in increasing order in the DAQ object
        # while we want to default to the largest input range that is the safest bet.
        for voltage in self.e.streaming_device.limits.ai_voltage_rngs:
            if counter % 2 != 1:
                self.ui.comboBox_ai_max.addItem(str(voltage))
            else:
                self.ui.comboBox_ai_min.addItem(str(voltage))
            counter += 1

    def set_comboBoxes_ao_range(self):
        self.ui.comboBox_ao_max.clear()
        self.ui.comboBox_ao_min.clear()

        counter = 0
        for voltage in self.e.streaming_device.limits.ao_voltage_rngs:
            if counter % 2 != 1:
                self.ui.comboBox_ao_max.addItem(str(voltage))
            else:
                self.ui.comboBox_ao_min.addItem(str(voltage))
            counter += 1

    def set_comboBox_ai_config(self):
        self.ui.comboBox_ai_terminal_cfg.clear()
        for item in self.e.streaming_device.limits.terminal_configs:
            self.ui.comboBox_ai_terminal_cfg.addItem(item)
            # its possible to use the comboBox string entries later as keywords to the enumerated type that
            # corresponds to them. i.e. nidaqmx.constants.TerminalConfiguration['RSE'] returns the enum same as
            # nidaqmx.constants.TerminalConfiguration.RSE. More documentation here:
            # https://docs.python.org/3/library/enum.html

    def on_pushButton_start_clicked(self):
        if self.ui.tabWidget_main.currentIndex() == self.FINITE_MEAS_TAB_INDEX:

            if self.ui.comboBox_out_sig_type.currentText() != 'ess':
                self.print_qt('>>> Finite measurement running...')
                self.e.start_fm_experiment()
            elif self.ui.comboBox_out_sig_type.currentText() == 'ess':
                self.print_qt('>>> Finite ESS measurement running...')
                self.e.start_fm_ess_experiment()
            self.update_current_fm_plot()

        elif self.ui.tabWidget_main.currentIndex() == self.CONTINUOUS_MEAS_TAB_INDEX:

            self.ui.pushButton_start.setEnabled(False)
            self.ui.tabWidget_main.setTabEnabled(self.SETTINGS_TAB_INDEX, False)
            self.ui.tabWidget_main.setTabEnabled(self.FINITE_MEAS_TAB_INDEX, False)
            self.e.streaming_device.io_start()
            self.print_qt('>>> Continuous measurement started.')
            self.ui.pushButton_stop.setEnabled(True)
            self.buffer_indicator_timer.start(config.IO_BUFFER_INDICATOR_REFRESH_MSEC)
            self.on_tabWidget_cm_changed()
        else:
            self.print_qt('Move to one of the measurement tabs to run a measurement.')

    def on_pushButton_stop_clicked(self):
        self.buffer_indicator_timer.stop()
        # self.timeseries_timer.stop()
        self.e.streaming_device.io_stop()
        self.ui.pushButton_stop.setEnabled(False)
        self.ui.pushButton_start.setEnabled(True)
        self.ui.tabWidget_main.setTabEnabled(self.SETTINGS_TAB_INDEX, True)
        self.ui.tabWidget_main.setTabEnabled(self.FINITE_MEAS_TAB_INDEX, True)
        self.print_qt('>>> Continuous measurement stopped.')

    def on_tabWidget_cm_changed(self): # TODO rename to on_tabWidget_cm_changed
        if self.e.streaming_device.cm_measurement_is_running:# TODO why is this needed?
            self.disconnect_all_drawing()
            if self.ui.tabWidget_cm.currentIndex() == self.CM_TIMESERIES_TAB_INDEX:
                self.e.streaming_device.input_frame_ready_signal.connect(self.update_cm_tm_plot)
            elif self.ui.tabWidget_cm.currentIndex() == self.CM_SPECTRUM_TAB_INDEX:
                self.e.streaming_device.set_monitor(self.e.cm_sp_window_size)
                self.e.streaming_device.monitor_ready_signal.connect(self.update_cm_sp_plot)
            elif self.ui.tabWidget_cm.currentIndex() == self.CM_PHASE_TAB_INDEX:
                self.e.streaming_device.set_monitor(self.e.cm_ph_window_size)
                self.e.streaming_device.monitor_ready_signal.connect(self.update_cm_ph_plot)
            else:
                # reminder for future expansion of tabs
                self.print_qt('WARNING: This tab does not define a specific streaming device configuration')

    def disconnect_all_drawing(self): #TODO FIND A BETTER WAY TO DO THIS BY LEARNING WHICH SIGNAL IS ACTUALLY ASSIGNED TO A GIVEN SLOT
        all_input_frame_draw_methods = [self.update_cm_tm_plot]
        all_monitor_draw_methods = [self.update_cm_sp_plot, self.update_cm_ph_plot]

        for method in all_input_frame_draw_methods:
            try:
                self.e.streaming_device.input_frame_ready_signal.disconnect(method)
            except TypeError: # This is thrown when we try to disconnect a method that isn't connected
                pass

        for method in all_monitor_draw_methods:
            try:
                self.e.streaming_device.monitor_ready_signal.disconnect(method)
            except TypeError:
                pass

    def place_fm_tm_graph(self):
        self.fm_tm_plot_widget = pg.PlotWidget(name='Timeseries')
        self.ui.tm_verticalLayout.addWidget(self.fm_tm_plot_widget)
        fm_tm_plot_item = self.fm_tm_plot_widget.getPlotItem()
        fm_tm_plot_item.showGrid(True, True, alpha=1)
        fm_tm_plot_item.setLabel('left', 'Lvl', units='<b>V</b>')
        #fm_tm_plot_item.setLabel('bottom', 'time', units='s')

        for chan_index in range(config.NR_OF_CHANNELS_TO_PLOT):
            this_plot_data_item = fm_tm_plot_item.plot(pen=self.pen_case[chan_index])
            self.fm_tm_plot_data_items.append(this_plot_data_item)
            this_plot_data_item = fm_tm_plot_item.plot(pen=self.hold_pen_case[chan_index])
            self.fm_tm_plot_hold_data_items.append(this_plot_data_item)

        self.fm_tm_plot_widget.show()
        # fm_tm_plot_item.vb.setLimits(yMin=self.streaming_device.ai_min_val, yMax=self.streaming_device.ai_max_val)

    def place_fm_sp_graph(self):
        self.fm_sp_plot_widget = pg.PlotWidget(name='Spectral Analysis')
        self.ui.sp_verticalLayout.addWidget(self.fm_sp_plot_widget)
        fm_sp_plot_item = self.fm_sp_plot_widget.getPlotItem()
        fm_sp_plot_item.setLogMode(True, False)
        fm_sp_plot_item.showGrid(True, True, alpha=1)
        fm_sp_plot_item.vb.setLimits(yMin=config.FM_SP_GRAPH_MIN_dB_LIMIT, yMax=config.FM_SP_GRAPH_MAX_dB_LIMIT)
        fm_sp_plot_item.setRange(yRange=(config.FM_SP_GRAPH_MIN_dB_LIMIT, config.FM_SP_GRAPH_MAX_dB_LIMIT),
                                 disableAutoRange=True)
        fm_sp_plot_item.setLabel('left', 'Lvl', units='<b>dBFS</b>')

        for chan_index in range(config.NR_OF_CHANNELS_TO_PLOT):
            this_plot_data_item = fm_sp_plot_item.plot(pen=self.pen_case[chan_index])
            self.fm_sp_plot_data_items.append(this_plot_data_item)
            this_plot_data_item = fm_sp_plot_item.plot(pen=self.hold_pen_case[chan_index])
            self.fm_sp_plot_hold_data_items.append(this_plot_data_item)

        self.fm_sp_plot_widget.show()

    def place_fm_spg_graphics(self):
        self.fm_spg_widget = pg.GraphicsLayoutWidget()
        self.ui.spg_verticalLayout.addWidget(self.fm_spg_widget)

        # view = self.ui.graphics_widget.addViewBox()
        self.graphics_plot = self.fm_spg_widget.addPlot()  # will generate the view and axes automatically
        # Add labels to the axis
        # self.graphics_plot.setLabel('bottom', 'Time', units='s') # this way lots of space is wasted
        # If you include the units, Pyqtgraph automatically scales the axis and adjusts the SI prefix (in this case kHz)
        self.graphics_plot.setLabel('left', "Frequency", units='<b>Hz</b>')

        self.img = pg.ImageItem(border='w')
        self.graphics_plot.addItem(self.img)

        # self.ui.graphics_plot.setLogMode(True, False)

        self.hist = pg.HistogramLUTItem()
        self.hist.setImageItem(self.img)
        self.fm_spg_widget.addItem(self.hist)

        self.hist.gradient.restoreState(config.default_spg_hist_gradient)

    def place_cm_tm_graph(self):
        self.cm_tm_plot_widget = pg.PlotWidget(name='Continuous Timeseries')
        self.ui.cm_tm_verticalLayout.addWidget(self.cm_tm_plot_widget)
        cm_tm_plot_item = self.cm_tm_plot_widget.getPlotItem()
        # cm_tm_plot_item.vb.disableAutoRange()
        # cm_tm_plot_item.vb.setLimits(ymin=self.streaming_device.ai_min_val,ymax=self.streaming_device.ai_max_val)
        cm_tm_plot_item.showGrid(True, True, alpha=1)
        cm_tm_plot_item.setLabel('left', 'Lvl', units='<b>V</b>')

        for chan_index in range(config.NR_OF_CHANNELS_TO_PLOT):
            this_plot_data_item = cm_tm_plot_item.plot(pen=self.pen_case[chan_index])
            self.cm_tm_plot_data_items.append(this_plot_data_item)
            this_plot_data_item = cm_tm_plot_item.plot(pen=self.hold_pen_case[chan_index])
            self.cm_tm_plot_hold_data_items.append(this_plot_data_item)

    def place_cm_sp_graph(self):
        self.cm_sp_plot_widget = pg.PlotWidget(name='Continuous Spectral Analysis')
        self.ui.cm_sp_verticalLayout.addWidget(self.cm_sp_plot_widget)
        cm_sp_plot_item = self.cm_sp_plot_widget.getPlotItem()

        # cm_sp_plot_item.disableAutoRange()
        cm_sp_plot_item.setLogMode(True, False)
        cm_sp_plot_item.showGrid(True, True, alpha=1)
        cm_sp_plot_item.setLabel('left', 'Lvl', units='<b>dBFS</b>')

        for chan_index in range(config.NR_OF_CHANNELS_TO_PLOT):
            this_plot_data_item = cm_sp_plot_item.plot(pen=self.pen_case[chan_index])
            self.cm_sp_plot_data_items.append(this_plot_data_item)
            this_plot_data_item = cm_sp_plot_item.plot(pen=self.hold_pen_case[chan_index])
            self.cm_sp_plot_hold_data_items.append(this_plot_data_item)

        x_min = np.log10(config.MIN_OUTPUT_FREQUENCY_ALLOWED)
        x_max = np.log10(config.MAX_COARSE_FREQ_DIAL_LIMIT)
        y_min = config.CM_SP_GRAPH_MIN_dB_LIMIT
        y_max = config.CM_SP_GRAPH_MAX_dB_LIMIT

        cm_sp_plot_item.vb.setLimits(xMin=x_min, xMax=x_max,
                                     yMin=y_min, yMax=y_max)

        cm_sp_plot_item.setRange(xRange=(x_min, x_max),
                                 yRange=(y_min, y_max),
                                 disableAutoRange=True)

    def place_cm_ph_graph(self):
        self.cm_ph_plot_widget = pg.PlotWidget(name='Phase Scope')
        self.ui.cm_ph_horizontalLayout.addWidget(self.cm_ph_plot_widget)
        cm_ph_plot_item = self.cm_ph_plot_widget.getPlotItem()
        cm_ph_plot_item.showGrid(True, True, alpha=1)
        #cm_ph_plot_item.setLabel('left', 'Lvl', units='<b>V</b>')

        self.cm_ph_plot_data_item = cm_ph_plot_item.plot(pen=config.PHASE_PLOT_COLOR_MODIFIER)
        plot_hold_data_item1 = cm_ph_plot_item.plot(pen=config.PHASE_PLOT_HOLD_COLOR_MODIFIER)
        self.cm_ph_plot_hold_data_items.append(plot_hold_data_item1)
        plot_hold_data_item2 = cm_ph_plot_item.plot(pen=config.PHASE_PLOT_HOLD_COLOR_MODIFIER+1)
        self.cm_ph_plot_hold_data_items.append(plot_hold_data_item2)
        self.cm_ph_plot_box_data_item = cm_ph_plot_item.plot(pen=config.PHASE_PLOT_LIMIT_COLOR_MODIFIER)

        #TODO GENERATE THE ROTATION MATRIX FOR 45*


    def update_output_buffer_indicator(self):
        ai_buffer_level = self.e.streaming_device.get_ai_buffer_level_prc()
        ao_buffer_level = self.e.streaming_device.get_ao_buffer_level_prc()

        self.ui.buffer_indicator_label.setText(f'ai:{ai_buffer_level}/ao:{ao_buffer_level}')

    def update_cm_tm_plot(self):
        self.e.streaming_device.read_lock.acquire()  # TODO this probably isn't working
        input_frame = self.e.streaming_device.input_frame
        input_frame_timebase = self.e.streaming_device.input_time_base
        self.e.streaming_device.read_lock.release()

        for chan in range(config.NR_OF_CHANNELS_TO_PLOT):
            self.cm_tm_plot_data_items[chan].setData(input_frame_timebase[chan], input_frame[chan])

    def update_cm_sp_plot(self):
        for chan in range(config.NR_OF_CHANNELS_TO_PLOT):
            # plot except for DC component to prevent warning with X logscale
            self.cm_sp_plot_data_items[chan].setData(self.e.cm_freq_base[1:], self.e.calculate_cm_fft()[chan][1:])

    def update_cm_ph_plot(self):
        phase_frame = self.e.calculate_cm_phase()
        self.cm_ph_plot_data_item.setData(phase_frame)

    def update_fm_tm_plot(self):
        self.check_fm_data_present()
        self.print_qt('>>> Drawing...')

        for chan in range(config.NR_OF_CHANNELS_TO_PLOT):
            self.fm_tm_plot_data_items[chan].setData(self.e.fm_result_x, self.e.fm_result_y[chan])

    def update_fm_sp_plot(self):
        self.check_fm_data_present()
        self.print_qt('>>> Calculating...')

        try:
            if self.e.streaming_device.function_gen.current_function != 'ess':
                fm_freq_base, fm_fft_segment_time, fm_db_fft = self.e.calculate_fm_fft()
            else:
                impulse_response = self.e.calculate_ir_from_fm_ess()
                fm_freq_base, fm_fft_segment_time, fm_db_fft = self.e.calculate_fm_fft(impulse_response)
        except ValueError as err:
            self.print_qt(err)
            return

        self.print_qt(f'{len(fm_fft_segment_time)} FFT segments average.')

        for chan in range(config.NR_OF_CHANNELS_TO_PLOT):
            self.fm_sp_plot_data_items[chan].setData(fm_freq_base[1:], fm_db_fft[chan][1:])

    def update_fm_spg(self):
        self.check_fm_data_present()
        self.print_qt('>>> Calculating...')

        try:
            f, t, spg = self.e.calculate_fm_spectrogram()
            # axis 1 is the time axis
        except ValueError as err:
            self.print_qt(err)
            return
        except MemoryError as err:
            print(err)
            self.print_qt('>> EXCEPTION << : Out of memory. Try analyzing less data.')
            return

        # convert amplitudes to log scale if required:
        if self.ui.checkBox_fm_spg_log_amp.isChecked():
            spg = np.log10(spg)

        # limit the frequency range of the analysis
        spg = spg[:][:int(np.size(spg, axis=0) * config.SPG_FREQUENCY_LIMIT / (
                self.e.streaming_device.ai_fs / 2))]

        # Clip the freq axis accordingly
        f = f[:int(np.size(spg, axis=0))]

        self.hist.setLevels(np.min(spg), np.max(spg))

        self.img.resetTransform()  # Ensures that the previous transformation does not interfere with the current one
        self.img.scale(t[-1] / np.size(spg, axis=1), f[-1] / np.size(spg, axis=0))
        self.img.setImage(spg.T)

        # Limit panning/zooming to the spectrogram
        self.graphics_plot.setLimits(xMin=0, xMax=t[-1], yMin=0, yMax=f[-1])
Пример #9
0
import sys
import os

base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_dir)

from PyQt5.QtWidgets import QApplication

from model.experiment import Experiment
from view.main_window import MainWindow
# from view.monitor import MonitorWindow as MainWindow

experiment = Experiment()
experiment.load_config('experiment.yml')
experiment.initialize()

app = QApplication([])
window = MainWindow(experiment)
window.show()
app.exec()

experiment.finalize()