Пример #1
0
    def setModelData(self, editor, model, index):
        """
        When editor has finished, read the updated data from the editor,
        convert it to floating point format and store it in both the model
        (= QTableWidget) and in `zpk`. Finally, refresh the table item to
        display it in the selected format (via `to be defined`) and normalize
        the gain.

        editor: instance of e.g. QLineEdit
        model:  instance of QAbstractTableModel
        index:  instance of QModelIndex
        """

        # check for different editor environments if needed and provide a default:
#        if isinstance(editor, QtGui.QTextEdit):
#            model.setData(index, editor.toPlainText())
#        elif isinstance(editor, QComboBox):
#            model.setData(index, editor.currentText())
#        else:
#            super(ItemDelegate, self).setModelData(editor, model, index)

        # convert entered string to complex, pass the old value as default
        data = self.parent.frmt2cmplx(qstr(editor.text()), 
                                      self.parent.zpk[index.column()][index.row()])
        model.setData(index, data)                          # store in QTableWidget
        self.parent.zpk[index.column()][index.row()] = data  # and in self.ba
        qstyle_widget(self.parent.ui.butSave, 'changed')
        self.parent._refresh_table_item(index.row(), index.column()) # refresh table entry
        self.parent._normalize_gain() # recalculate gain
Пример #2
0
    def _normalize_gain(self):
        """
        Normalize the gain factor so that the maximum of |H(f)| stays 1 or a
        previously stored maximum value of |H(f)|. Do this every time a P or Z
        has been changed.
        Called by setModelData() and when cmbNorm is activated

        """
        norm = qget_cmb_box(self.ui.cmbNorm, data=False)
        self.ui.ledGain.setEnabled(norm == 'None')
        if norm != self.norm_last:
            qstyle_widget(self.ui.butSave, 'changed')
        if not np.isfinite(self.zpk[2]):
            self.zpk[2] = 1.
        self.zpk[2] = np.real_if_close(self.zpk[2]).item()
        if np.iscomplex(self.zpk[2]):
            logger.warning("Casting complex to real for gain k!")
            self.zpk[2] = np.abs(self.zpk[2])

        if norm != "None":
            b, a = zpk2tf(self.zpk[0], self.zpk[1], self.zpk[2])
            [w, H] = freqz(b, a, whole=True)
            Hmax = max(abs(H))
            if not np.isfinite(Hmax) or Hmax > 1e4 or Hmax < 1e-4:
                Hmax = 1.
            if norm == "1":
                self.zpk[2] = self.zpk[2] / Hmax # normalize to 1
            elif norm == "Max":
                if norm != self.norm_last: # setting has been changed -> 'Max'
                    self.Hmax_last = Hmax # use current design to set Hmax_last
                self.zpk[2] = self.zpk[2] / Hmax * self.Hmax_last
        self.norm_last = norm # store current setting of combobox

        self._restore_gain()
Пример #3
0
    def _delete_cells(self):
        """
        Delete all selected elements by:
        - determining the indices of all selected cells in the P and Z arrays
        - deleting elements with those indices
        - equalizing the lengths of P and Z array by appending the required
          number of zeros.
        - deleting all P/Z pairs
        Finally, the table is refreshed from self.zpk.
        """
        sel = self._get_selected(self.tblPZ)['idx']  # get all selected indices
        Z = [s[1] for s in sel
             if s[0] == 0]  # all selected indices in 'Z' column
        P = [s[1] for s in sel
             if s[0] == 1]  # all selected indices in 'P' column

        # Delete array entries with selected indices. If nothing is selected
        # (Z and P are empty), delete the last row.
        if len(Z) < 1 and len(P) < 1:
            Z = [len(self.zpk[0]) - 1]
            P = [len(self.zpk[1]) - 1]
        self.zpk[0] = np.delete(self.zpk[0], Z)
        self.zpk[1] = np.delete(self.zpk[1], P)

        # test and equalize if P and Z array have different lengths:
        D = len(self.zpk[0]) - len(self.zpk[1])
        if D > 0:
            self.zpk[1] = np.append(self.zpk[1], np.zeros(D))
        elif D < 0:
            self.zpk[0] = np.append(self.zpk[0], np.zeros(-D))

        self._delete_PZ_pairs()
        self._normalize_gain()
        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #4
0
    def _delete_cells(self):
        """
        Delete all selected elements in self.ba by:
        - determining the indices of all selected cells in the P and Z arrays
        - deleting elements with those indices
        - equalizing the lengths of b and a array by appending the required
          number of zeros.
        When nothing is selected, delete the last row.
        Finally, the QTableWidget is refreshed from self.ba.
        """
        sel = qget_selected(self.tblCoeff)['sel'] # get indices of all selected cells

        if not np.any(sel) and len(self.ba[0]) > 0:
            self.ba[0] = np.delete(self.ba[0], -1)
            self.ba[1] = np.delete(self.ba[1], -1)
        else:
            self.ba[0] = np.delete(self.ba[0], sel[0])
            self.ba[1] = np.delete(self.ba[1], sel[1])

        # test and equalize if b and a array have different lengths:
        self._equalize_ba_length()
        if len(self.ba[0]) < 2:
            self._clear_table()
        else:
            self._refresh_table()
            qstyle_widget(self.ui.butSave, 'changed')
Пример #5
0
    def _save_dict(self):
        """
        Save the coefficient register `self.ba` to the filter dict `fb.fil[0]['ba']`.
        """

        logger.debug("_save_entries called")

        fb.fil[0]['N'] = max(len(self.ba[0]), len(self.ba[1])) - 1

        self._store_q_settings()

        if fb.fil[0]['ft'] == 'IIR':
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        # save, check and convert coeffs, check filter type
        fil_save(fb.fil[0], self.ba, 'ba', __name__)

        if __name__ == '__main__':
            self.load_dict() # only needed for stand-alone test

        self.sigFilterDesigned.emit() # -> filter_specs
        # -> input_tab_widgets -> pyfdax -> plt_tab_widgets.updateAll()

        qstyle_widget(self.ui.butSave, 'normal')
Пример #6
0
    def _zero_PZ(self):
        """
        Set all P/Zs = 0 with a magnitude less than eps and delete P/Z pairs
        afterwards.
        """
        changed = False
        targ_val = 0.
        test_val = 0
        sel = self._get_selected(self.tblPZ)['idx'] # get all selected indices

        if not sel: # nothing selected, check all cells
            z_close = np.logical_and(np.isclose(self.zpk[0], test_val, rtol=0, atol = self.ui.eps),
                                     (self.zpk[0] != targ_val))
            p_close = np.logical_and(np.isclose(self.zpk[1], test_val, rtol=0, atol = self.ui.eps),
                                     (self.zpk[1] != targ_val))
            if z_close.any():
                self.zpk[0] = np.where(z_close, targ_val, self.zpk[0])
                changed = True
            if p_close.any():
                self.zpk[1] = np.where(p_close, targ_val, self.zpk[1])
                changed = True
        else:
            for i in sel: # check only selected cells
                if np.logical_and(np.isclose(self.zpk[i[0]][i[1]], test_val, rtol=0, atol = self.ui.eps),
                                  (self.zpk[i[0]][i[1]] != targ_val)):
                    self.zpk[i[0]][i[1]] = targ_val
                    changed = True

        self._delete_PZ_pairs()
        self._normalize_gain()
        if changed:
            qstyle_widget(self.ui.butSave, 'changed') # mark save button as changed
        self._refresh_table()
Пример #7
0
    def setModelData(self, editor, model, index):
        """
        When editor has finished, read the updated data from the editor,
        convert it to complex format and store it in both the model
        (= QTableWidget) and in `zpk`. Finally, refresh the table item to
        display it in the selected format (via `to be defined`) and normalize
        the gain.

        editor: instance of e.g. QLineEdit
        model:  instance of QAbstractTableModel
        index:  instance of QModelIndex
        """

        # check for different editor environments if needed and provide a default:
        #        if isinstance(editor, QtGui.QTextEdit):
        #            model.setData(index, editor.toPlainText())
        #        elif isinstance(editor, QComboBox):
        #            model.setData(index, editor.currentText())
        #        else:
        #            super(ItemDelegate, self).setModelData(editor, model, index)

        # convert entered string to complex, pass the old value as default
        data = self.parent.frmt2cmplx(
            qstr(editor.text()), self.parent.zpk[index.column()][index.row()])
        model.setData(index, data)  # store in QTableWidget
        self.parent.zpk[index.column()][index.row()] = data  # and in self.ba
        qstyle_widget(self.parent.ui.butSave, 'changed')
        self.parent._refresh_table_item(index.row(),
                                        index.column())  # refresh table entry
        self.parent._normalize_gain()  # recalculate gain
Пример #8
0
    def setModelData(self, editor, model, index):
        """
        When editor has finished, read the updated data from the editor,
        convert it back to floating point format and store it in both the model
        (= QTableWidget) and in self.ba. Finally, refresh the table item to 
        display it in the selected format (via `float2frmt()`).

        editor: instance of e.g. QLineEdit
        model:  instance of QAbstractTableModel
        index:  instance of QModelIndex
        """

        # check for different editor environments if needed and provide a default:
#        if isinstance(editor, QtGui.QTextEdit):
#            model.setData(index, editor.toPlainText())
#        elif isinstance(editor, QComboBox):
#            model.setData(index, editor.currentText())
#        else:
#            super(ItemDelegate, self).setModelData(editor, model, index)
        if self.parent.myQ.frmt == 'float':
            data = safe_eval(qstr(editor.text()), 
                             self.parent.ba[index.column()][index.row()], return_type='auto') # raw data without fixpoint formatting
        else:
            data = self.parent.myQ.frmt2float(qstr(editor.text()),
                                    self.parent.myQ.frmt) # transform back to float

        model.setData(index, data)                          # store in QTableWidget
        self.parent.ba[index.column()][index.row()] = data  # and in self.ba
        qstyle_widget(self.parent.ui.butSave, 'changed')
        self.parent._refresh_table_item(index.row(), index.column()) # refresh table entry
Пример #9
0
    def _save_entries(self):
        """
        Save the values from self.zpk to the filter PZ dict,
        the QLineEdit for setting the gain has to be treated separately.
        """

        logger.debug("_save_entries called")

        fb.fil[0]['N'] = len(self.zpk[0])
        if np.any(self.zpk[1]): # any non-zero poles?
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        fil_save(fb.fil[0], self.zpk, 'zpk', __name__) # save with new gain

        if __name__ == '__main__':
            self.load_dict() # only needed for stand-alone test

        self.sig_tx.emit({'sender':__name__, 'data_changed':'input_pz'})
        # -> input_tab_widgets

        qstyle_widget(self.ui.butSave, 'normal')

        logger.debug("b,a = {0}\n\n"
            "zpk = {1}\n"
            .format(pformat(fb.fil[0]['ba']), pformat(fb.fil[0]['zpk'])
              ))
Пример #10
0
    def _save_entries(self):
        """
        Save the values from self.ba to the filter ba dict.
        """

        logger.debug("_save_entries called")

        fb.fil[0]['N'] = max(len(self.ba[0]), len(self.ba[1])) - 1

        fb.fil[0]["q_coeff"] = {
            'WI': int(self.ledWI.text()),
            'WF': int(self.ledWF.text()),
            'quant': self.cmbQQuant.currentText(),
            'ovfl': self.cmbQOvfl.currentText(),
            'frmt': self.cmbFormat.currentText(),
            'point': self.chkRadixPoint.isChecked()
        }

        # save, check and convert coeffs, check filter type
        fil_save(fb.fil[0], self.ba, 'ba', __name__)

        if fb.fil[0]['ft'] == 'IIR':
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        if __name__ == '__main__':
            self.load_dict()  # only needed for stand-alone test

        self.sigFilterDesigned.emit()  # -> filter_specs
        # -> input_tab_widgets -> pyfdax -> plt_tab_widgets.updateAll()

        qstyle_widget(self.butSave, 'normal')
Пример #11
0
    def _save_entries(self):
        """
        Save the values from self.zpk to the filter PZ dict,
        the QLineEdit for setting the gain has to be treated separately.
        """

        logger.debug("_save_entries called")

        fb.fil[0]['N'] = len(self.zpk[0])
        if np.any(self.zpk[1]):  # any non-zero poles?
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        fil_save(fb.fil[0], self.zpk, 'zpk', __name__)  # save with new gain

        if __name__ == '__main__':
            self.load_dict()  # only needed for stand-alone test

        self.sig_tx.emit({'sender': __name__, 'data_changed': 'input_pz'})
        # -> input_tab_widgets

        qstyle_widget(self.ui.butSave, 'normal')

        logger.debug("b,a = {0}\n\n"
                     "zpk = {1}\n".format(pformat(fb.fil[0]['ba']),
                                          pformat(fb.fil[0]['zpk'])))
Пример #12
0
    def _save_dict(self):
        """
        Save the coefficient register `self.ba` to the filter dict `fb.fil[0]['ba']`.
        """

        logger.debug("_save_dict called")

        fb.fil[0]['N'] = max(len(self.ba[0]), len(self.ba[1])) - 1

        self._store_q_settings()

        if fb.fil[0]['ft'] == 'IIR':
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        # save, check and convert coeffs, check filter type
        fil_save(fb.fil[0], self.ba, 'ba', __name__)

        if __name__ == '__main__':
            self.load_dict() # only needed for stand-alone test

        self.sig_tx.emit({'sender':__name__, 'data_changed':'input_coeffs'})
        # -> input_tab_widgets

        qstyle_widget(self.ui.butSave, 'normal')
Пример #13
0
    def _normalize_gain(self):
        """
        Normalize the gain factor so that the maximum of |H(f)| stays 1 or a
        previously stored maximum value of |H(f)|. Do this every time a P or Z
        has been changed.
        Called by setModelData() and when cmbNorm is activated

        """
        norm = qget_cmb_box(self.ui.cmbNorm, data=False)
        self.ui.ledGain.setEnabled(norm == 'None')
        if norm != self.norm_last:
            qstyle_widget(self.ui.butSave, 'changed')
        if not np.isfinite(self.zpk[2]):
            self.zpk[2] = 1.
        self.zpk[2] = np.real_if_close(self.zpk[2]).item()
        if np.iscomplex(self.zpk[2]):
            logger.warning("Casting complex to real for gain k!")
            self.zpk[2] = np.abs(self.zpk[2])

        if norm != "None":
            b, a = zpk2tf(self.zpk[0], self.zpk[1], self.zpk[2])
            [w, H] = freqz(b, a, whole=True)
            Hmax = max(abs(H))
            if not np.isfinite(Hmax) or Hmax > 1e4 or Hmax < 1e-4:
                Hmax = 1.
            if norm == "1":
                self.zpk[2] = self.zpk[2] / Hmax  # normalize to 1
            elif norm == "Max":
                if norm != self.norm_last:  # setting has been changed -> 'Max'
                    self.Hmax_last = Hmax  # use current design to set Hmax_last
                self.zpk[2] = self.zpk[2] / Hmax * self.Hmax_last
        self.norm_last = norm  # store current setting of combobox

        self._restore_gain()
Пример #14
0
    def _delete_cells(self):
        """
        Delete all selected elements by:
        - determining the indices of all selected cells in the P and Z arrays
        - deleting elements with those indices
        - equalizing the lengths of P and Z array by appending the required
          number of zeros.
        - deleting all P/Z pairs
        Finally, the table is refreshed from self.zpk.
        """
        sel = self._get_selected(self.tblPZ)['idx'] # get all selected indices
        Z = [s[1] for s in sel if s[0] == 0] # all selected indices in 'Z' column
        P = [s[1] for s in sel if s[0] == 1] # all selected indices in 'P' column

        # Delete array entries with selected indices. If nothing is selected
        # (Z and P are empty), delete the last row.
        if len(Z) < 1 and len(P) < 1:
            Z = [len(self.zpk[0])-1]
            P = [len(self.zpk[1])-1]
        self.zpk[0] = np.delete(self.zpk[0], Z)
        self.zpk[1] = np.delete(self.zpk[1], P)

        # test and equalize if P and Z array have different lengths:
        D = len(self.zpk[0]) - len(self.zpk[1])
        if D > 0:
            self.zpk[1] = np.append(self.zpk[1], np.zeros(D))
        elif D < 0:
            self.zpk[0] = np.append(self.zpk[0], np.zeros(-D))

        self._delete_PZ_pairs()
        self._normalize_gain()
        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #15
0
    def _save_dict(self):
        """
        Save the coefficient register `self.ba` to the filter dict `fb.fil[0]['ba']`.
        """

        logger.debug("_save_entries called")

        fb.fil[0]['N'] = max(len(self.ba[0]), len(self.ba[1])) - 1

        self._store_q_settings()

        if fb.fil[0]['ft'] == 'IIR':
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        # save, check and convert coeffs, check filter type
        fil_save(fb.fil[0], self.ba, 'ba', __name__)

        if __name__ == '__main__':
            self.load_dict() # only needed for stand-alone test

        self.sigFilterDesigned.emit() # -> filter_specs
        # -> input_tab_widgets -> pyfdax -> plt_tab_widgets.updateAll()

        qstyle_widget(self.ui.butSave, 'normal')
Пример #16
0
    def update_UI(self, new_labels = []):
        """
        Called from filter_specs.update_UI()
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
                  filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels: # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels: # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        for i in range(num_new_labels):
            # Update ALL labels and corresponding values 
            self.qlabels[i].setText(to_html(new_labels[i], frmt='bi'))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID
            self.qlineedit[i].setToolTip("<span>Relative weight (importance) for approximating this band.</span>")
            qstyle_widget(self.qlineedit[i], state)

        self.n_cur_labels = num_new_labels # update number of currently visible labels
        self.load_dict() # display rounded filter dict entries
Пример #17
0
    def _zero_PZ(self):
        """
        Set all P/Zs = 0 with a magnitude less than eps and delete P/Z pairs
        afterwards.
        """
        changed = False
        targ_val = 0.
        test_val = 0
        sel = self._get_selected(self.tblPZ)['idx'] # get all selected indices

        if not sel: # nothing selected, check all cells
            z_close = np.logical_and(np.isclose(self.zpk[0], test_val, rtol=0, atol = self.ui.eps),
                                     (self.zpk[0] != targ_val))
            p_close = np.logical_and(np.isclose(self.zpk[1], test_val, rtol=0, atol = self.ui.eps),
                                     (self.zpk[1] != targ_val))
            if z_close.any():
                self.zpk[0] = np.where(z_close, targ_val, self.zpk[0])
                changed = True
            if p_close.any():
                self.zpk[1] = np.where(p_close, targ_val, self.zpk[1])
                changed = True
        else:
            for i in sel: # check only selected cells
                if np.logical_and(np.isclose(self.zpk[i[0]][i[1]], test_val, rtol=0, atol = self.ui.eps),
                                  (self.zpk[i[0]][i[1]] != targ_val)):
                    self.zpk[i[0]][i[1]] = targ_val
                    changed = True

        self._delete_PZ_pairs()
        self._normalize_gain()
        if changed:
            qstyle_widget(self.ui.butSave, 'changed') # mark save button as changed
        self._refresh_table()
Пример #18
0
    def setModelData(self, editor, model, index):
        """
        When editor has finished, read the updated data from the editor,
        convert it back to floating point format and store it in both the model
        (= QTableWidget) and in self.ba. Finally, refresh the table item to 
        display it in the selected format (via `float2frmt()`).

        editor: instance of e.g. QLineEdit
        model:  instance of QAbstractTableModel
        index:  instance of QModelIndex
        """

        # check for different editor environments if needed and provide a default:
#        if isinstance(editor, QtGui.QTextEdit):
#            model.setData(index, editor.toPlainText())
#        elif isinstance(editor, QComboBox):
#            model.setData(index, editor.currentText())
#        else:
#            super(ItemDelegate, self).setModelData(editor, model, index)
        if self.parent.myQ.frmt == 'float':
            data = safe_eval(qstr(editor.text()), 
                             self.parent.ba[index.column()][index.row()], return_type='auto') # raw data without fixpoint formatting
        else:
            data = self.parent.myQ.frmt2float(qstr(editor.text()),
                                    self.parent.myQ.frmt) # transform back to float

        model.setData(index, data)                          # store in QTableWidget
        # if the entry is complex, convert ba (list of arrays) to complex type
        if isinstance(data, complex):
            self.parent.ba[0] = self.parent.ba[0].astype(complex)
            self.parent.ba[1] = self.parent.ba[1].astype(complex)
        self.parent.ba[index.column()][index.row()] = data  # store in self.ba
        qstyle_widget(self.parent.ui.butSave, 'changed')
        self.parent._refresh_table_item(index.row(), index.column()) # refresh table entry
Пример #19
0
    def _delete_cells(self):
        """
        Delete all selected elements in self.ba by:
        - determining the indices of all selected cells in the P and Z arrays
        - deleting elements with those indices
        - equalizing the lengths of b and a array by appending the required
          number of zeros.
        When nothing is selected, delete the last row.
        Finally, the QTableWidget is refreshed from self.ba.
        """
        sel = qget_selected(self.tblCoeff)['sel'] # get indices of all selected cells

        if not np.any(sel) and len(self.ba[0]) > 0:
            self.ba[0] = np.delete(self.ba[0], -1)
            self.ba[1] = np.delete(self.ba[1], -1)
        else:
            self.ba[0] = np.delete(self.ba[0], sel[0])
            self.ba[1] = np.delete(self.ba[1], sel[1])

        # test and equalize if b and a array have different lengths:
        self._equalize_ba_length()
        # if length is less than 2, clear the table: this ain't no filter!
        if len(self.ba[0]) < 2:
            self._clear_table() # sets 'changed' attribute
        else:
            self._refresh_table()
            qstyle_widget(self.ui.butSave, 'changed')
Пример #20
0
    def _save_dict(self):
        """
        Save the coefficient register `self.ba` to the filter dict `fb.fil[0]['ba']`.
        """

        logger.debug("_save_dict called")

        fb.fil[0]['N'] = max(len(self.ba[0]), len(self.ba[1])) - 1

        self._store_q_settings()

        if fb.fil[0]['ft'] == 'IIR':
            fb.fil[0]['fc'] = 'Manual_IIR'
        else:
            fb.fil[0]['fc'] = 'Manual_FIR'

        # save, check and convert coeffs, check filter type
        fil_save(fb.fil[0], self.ba, 'ba', __name__)

        if __name__ == '__main__':
            self.load_dict()  # only needed for stand-alone test

        self.sig_tx.emit({'sender': __name__, 'data_changed': 'input_coeffs'})
        # -> input_tab_widgets

        qstyle_widget(self.ui.butSave, 'normal')
Пример #21
0
    def setModelData(self, editor, model, index):
        """
        When editor has finished, read the updated data from the editor,
        convert it back to floating point format and store it in the model 
        (= QTableWidget) and in self.ba

        editor: instance of e.g. QLineEdit
        model:  instance of QAbstractTableModel
        index:  instance of QModelIndex
        """
        # check for different editor environments if needed and provide a default:
        #        if isinstance(editor, QtGui.QTextEdit):
        #            model.setData(index, editor.toPlainText())
        #        elif isinstance(editor, QComboBox):
        #            model.setData(index, editor.currentText())
        #        else:
        #            super(ItemDelegate, self).setModelData(editor, model, index)
        if self.parent.myQ.frmt == 'float':
            data = safe_eval(
                qstr(editor.text()),
                fb.data_old)  # raw data without fixpoint formatting
        else:
            data = self.parent.myQ.frmt2float(
                qstr(editor.text()),
                self.parent.myQ.frmt)  # transform back to float

        model.setData(index, data)  # store in QTableWidget
        self.parent.ba[index.column()][index.row()] = data  # and in self.ba
        qstyle_widget(self.parent.butSave, 'changed')
Пример #22
0
    def update_UI(self, new_labels=()):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]
        unit = fb.fil[0]['freq_specs_unit']
        if unit in {"f_S", "f_Ny"}:
            unit_frmt = 'bi'
        else:
            unit_frmt = 'b'

        self.lblUnit.setText(" in " + to_html(unit, frmt=unit_frmt))
        num_new_labels = len(new_labels)
        # hide / show labels / create new subwidgets if neccessary:
        self._show_entries(num_new_labels)

        #        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        #---------------------------- logging -----------------------------
        logger.debug("update_UI: {0}-{1}-{2}".format(fb.fil[0]['rt'],
                                                     fb.fil[0]['fc'],
                                                     fb.fil[0]['fo']))

        f_range = " (0 &lt; <i>f</i> &lt; <i>f<sub>S </sub></i>/2)"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values
            self.qlabels[i].setText(to_html(new_labels[i], frmt='bi'))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID
            qstyle_widget(self.qlineedit[i], state)

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip(
                    "<span>Corner frequency for (this) stop band" + f_range +
                    ".</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip(
                    "<span>Corner frequency for (this) pass band" + f_range +
                    ".</span>")
            else:
                self.qlineedit[i].setToolTip(
                    "<span>Corner frequency for (this) band" + f_range +
                    ".</span>")

        self.n_cur_labels = num_new_labels  # update number of currently visible labels
        self.sort_dict_freqs(
        )  # sort frequency entries in dictionary and update display
Пример #23
0
    def calc_response(self, y_fx=None):
        """
        (Re-)calculate filter response `self.y` from either stimulus `self.x`
        (float mode) or copy fixpoint response. 
        Split response into imag. and real components `self.y_i` and `self.y_r`
        and set the flag `self.cmplx`.
        """
        if self.fx_sim:  # use fixpoint simulation results instead of floating results
            if y_fx is not None:
                self.y = np.array(y_fx)
                qstyle_widget(self.ui.but_run, "normal")
            else:
                self.y = None
        else:
            # calculate response self.y_r[n] and self.y_i[n] (for complex case) =====
            self.bb = np.asarray(fb.fil[0]['ba'][0])
            self.aa = np.asarray(fb.fil[0]['ba'][1])
            if min(len(self.aa), len(self.bb)) < 2:
                logger.error(
                    'No proper filter coefficients: len(a), len(b) < 2 !')
                return

            logger.info("Coefficient area = {0}".format(np.sum(np.abs(
                self.bb))))

            sos = np.asarray(fb.fil[0]['sos'])
            antiCausal = 'zpkA' in fb.fil[0]
            causal = not (antiCausal)

            if len(sos
                   ) > 0 and causal:  # has second order sections and is causal
                y = sig.sosfilt(sos, self.x)
            elif antiCausal:
                y = sig.filtfilt(self.bb, self.aa, self.x, -1, None)
            else:  # no second order sections or antiCausals for current filter
                y = sig.lfilter(self.bb, self.aa, self.x)

            if self.ui.stim == "StepErr":
                dc = sig.freqz(self.bb, self.aa,
                               [0])  # DC response of the system
                y = y - abs(dc[1])  # subtract DC (final) value from response

            self.y = np.real_if_close(
                y, tol=1e3)  # tol specified in multiples of machine eps

        self.needs_redraw[0] = True
        self.needs_redraw[1] = True

        # Calculate imag. and real components from response
        self.cmplx = np.any(np.iscomplex(self.y))
        if self.cmplx:
            self.y_i = self.y.imag
            self.y_r = self.y.real
        else:
            self.y_r = self.y
            self.y_i = None
Пример #24
0
    def _clear_table(self):
        """
        Clear self.ba: Initialize coeff for a poles and a zero @ origin,
        a = b = [1; 0].

        Refresh QTableWidget
        """
        self.ba = [np.asarray([1, 0]), np.asarray([1, 0])]

        self._refresh_table()
        qstyle_widget(self.ui.butSave, 'changed')
Пример #25
0
    def _clear_table(self):
        """
        Clear self.ba: Initialize coeff for a poles and a zero @ origin,
        a = b = [1; 0].

        Refresh QTableWidget
        """
        self.ba = [np.asarray([1, 0]), np.asarray([1, 0])]

        self._refresh_table()
        qstyle_widget(self.ui.butSave, 'changed')
Пример #26
0
    def _clear_table(self):
        """
        Clear & initialize table and zpk for two poles and zeros @ origin,
        P = Z = [0; 0], k = 1
        """
        self.zpk = np.array([[0, 0], [0, 0], 1])
        self.Hmax_last = 1.0
        self.anti = False

        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #27
0
    def _clear_table(self):
        """
        Clear & initialize table and zpk for two poles and zeros @ origin,
        P = Z = [0; 0], k = 1
        """
        self.zpk = np.array([[0, 0], [0, 0], 1])
        self.Hmax_last = 1.0
        self.anti = False

        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #28
0
    def _copy_to_table(self):
        """
        Read data from clipboard / file and copy it to `self.ba` as float / cmplx
        # TODO: More checks for swapped row <-> col, single values, wrong data type ...
        """
        data_str = qtext2table(self, 'ba', comment="filter coefficients ")
        if data_str == -1:  # file operation has been aborted
            return

        logger.debug("importing data: dim - shape = {0} - {1} - {2}\n{3}"\
                       .format(type(data_str), np.ndim(data_str), np.shape(data_str), data_str))

        conv = self.myQ.frmt2float  # frmt2float_vec?
        frmt = self.myQ.frmt

        if np.ndim(data_str) > 1:
            num_cols, num_rows = np.shape(data_str)
            orientation_horiz = num_cols > num_rows  # need to transpose data
        elif np.ndim(data_str) == 1:
            num_rows = len(data_str)
            num_cols = 1
            orientation_horiz = False
        else:
            logger.error("Imported data is a single value or None.")
            return None
        logger.info("_copy_to_table: c x r = {0} x {1}".format(
            num_cols, num_rows))
        if orientation_horiz:
            self.ba = [[], []]
            for c in range(num_cols):
                self.ba[0].append(conv(data_str[c][0], frmt))
                if num_rows > 1:
                    self.ba[1].append(conv(data_str[c][1], frmt))
            if num_rows > 1:
                self._filter_type(ftype='IIR')
            else:
                self._filter_type(ftype='FIR')
        else:
            self.ba[0] = [conv(s, frmt) for s in data_str[0]]
            if num_cols > 1:
                self.ba[1] = [conv(s, frmt) for s in data_str[1]]
                self._filter_type(ftype='IIR')
            else:
                self.ba[1] = [1]
                self._filter_type(ftype='FIR')

        self.ba[0] = np.asarray(self.ba[0])
        self.ba[1] = np.asarray(self.ba[1])

        self._equalize_ba_length()
        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #29
0
    def quant_coeffs(self):
        """
        Quantize selected / all coefficients in self.ba and refresh QTableWidget
        """
        idx = qget_selected(self.tblCoeff)['idx'] # get all selected indices
        if not idx: # nothing selected, quantize all elements
            self.ba = self.myQ.fixp(self.ba, scaling='multdiv')
        else:
            for i in idx:
                self.ba[i[0]][i[1]] = self.myQ.fixp(self.ba[i[0]][i[1]], scaling = 'multdiv')

        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #30
0
    def quant_coeffs(self):
        """
        Quantize selected / all coefficients in self.ba and refresh QTableWidget
        """
        idx = qget_selected(self.tblCoeff)['idx'] # get all selected indices
        if not idx: # nothing selected, quantize all elements
            self.ba = self.myQ.fixp(self.ba, scaling='multdiv')
        else:
            for i in idx:
                self.ba[i[0]][i[1]] = self.myQ.fixp(self.ba[i[0]][i[1]], scaling = 'multdiv')

        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #31
0
    def wdg_dict2ui(self):
        """
        Trigger an update of the fixpoint widget UI when view (i.e. fixpoint 
        coefficient format) has been changed outside this class. Additionally,
        pass the fixpoint quantization widget to update / restore other subwidget
        settings.
        
        Set the RUN button to "changed".
        """
        if hasattr(self.fx_wdg_inst, "dict2ui"):
            self.fx_wdg_inst.dict2ui(self.fxqc_dict)

        qstyle_widget(self.butSimHDL, "changed")
Пример #32
0
    def wdg_dict2ui(self):
        """
        Trigger an update of the fixpoint widget UI when view (i.e. fixpoint 
        coefficient format) has been changed outside this class. Additionally,
        pass the fixpoint quantization widget to update / restore other subwidget
        settings.
        
        Set the RUN button to "changed".
        """
        if self.fx_wdg_found and hasattr(self.fx_wdg_inst, "dict2ui"):
            self.fx_wdg_inst.dict2ui(self.fxqc_dict)

        qstyle_widget(self.butSimHDL, "changed")
Пример #33
0
    def _copy_to_table(self):
        """
        Read data from clipboard / file and copy it to `self.ba` as float / cmplx
        # TODO: More checks for swapped row <-> col, single values, wrong data type ...
        """
        data_str = qtext2table(self, 'ba', comment="filter coefficients ")
        if data_str == -1: # file operation has been aborted
            return

        logger.debug("importing data: dim - shape = {0} - {1} - {2}\n{3}"\
                       .format(type(data_str), np.ndim(data_str), np.shape(data_str), data_str))

        conv = self.myQ.frmt2float # frmt2float_vec?
        frmt = self.myQ.frmt

        if np.ndim(data_str) > 1:
            num_cols, num_rows = np.shape(data_str)
            orientation_horiz = num_cols > num_rows # need to transpose data
        elif np.ndim(data_str) == 1:
            num_rows = len(data_str)
            num_cols = 1
            orientation_horiz = False
        else:
            logger.error("Imported data is a single value or None.")
            return None
        logger.info("_copy_to_table: c x r = {0} x {1}".format(num_cols, num_rows))
        if orientation_horiz:
            self.ba = [[],[]]
            for c in range(num_cols):
                self.ba[0].append(conv(data_str[c][0], frmt))
                if num_rows > 1:
                    self.ba[1].append(conv(data_str[c][1], frmt))
            if num_rows > 1:
                self._filter_type(ftype='IIR')
            else:
                self._filter_type(ftype='FIR')
        else:
            self.ba[0] = [conv(s, frmt) for s in data_str[0]]
            if num_cols > 1:
                self.ba[1] = [conv(s, frmt) for s in data_str[1]]
                self._filter_type(ftype='IIR')
            else:
                self.ba[1] = [1]
                self._filter_type(ftype='FIR')

        self.ba[0] = np.asarray(self.ba[0])
        self.ba[1] = np.asarray(self.ba[1])

        self._equalize_ba_length()
        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #34
0
    def calc_response(self, y_fx = None):
        """
        (Re-)calculate filter response `self.y` from either stimulus `self.x`
        (float mode) or copy fixpoint response. 
        Split response into imag. and real components `self.y_i` and `self.y_r`
        and set the flag `self.cmplx`.
        """
        if self.fx_sim: # use fixpoint simulation results instead of floating results
            if y_fx is not None:
                self.y = np.array(y_fx)
                qstyle_widget(self.ui.but_run, "normal")
            else:
                self.y = None
        else:
            # calculate response self.y_r[n] and self.y_i[n] (for complex case) =====   
            self.bb = np.asarray(fb.fil[0]['ba'][0])
            self.aa = np.asarray(fb.fil[0]['ba'][1])
            if min(len(self.aa), len(self.bb)) < 2:
                logger.error('No proper filter coefficients: len(a), len(b) < 2 !')
                return

            logger.info("Coefficient area = {0}".format(np.sum(np.abs(self.bb))))
    
            sos = np.asarray(fb.fil[0]['sos'])
            antiCausal = 'zpkA' in fb.fil[0]
            causal     = not (antiCausal)
    
            if len(sos) > 0 and causal: # has second order sections and is causal
                y = sig.sosfilt(sos, self.x)
            elif antiCausal:
                y = sig.filtfilt(self.bb, self.aa, self.x, -1, None)
            else: # no second order sections or antiCausals for current filter
                y = sig.lfilter(self.bb, self.aa, self.x)
    
            if self.ui.stim == "StepErr":
                dc = sig.freqz(self.bb, self.aa, [0]) # DC response of the system
                y = y - abs(dc[1]) # subtract DC (final) value from response
    
            self.y = np.real_if_close(y, tol = 1e3)  # tol specified in multiples of machine eps

        self.needs_redraw[0] = True
        self.needs_redraw[1] = True

        # Calculate imag. and real components from response
        self.cmplx = np.any(np.iscomplex(self.y))
        if self.cmplx:
            self.y_i = self.y.imag
            self.y_r = self.y.real
        else:
            self.y_r = self.y
            self.y_i = None
Пример #35
0
    def load_dict(self):
        """
        Reload all specs/parameters entries from global dict fb.fil[0],
        using the "load_dict" methods of the individual classes
        """
        self.sel_fil.load_dict()  # select filter widget
        self.f_units.load_dict()  # frequency units widget
        self.f_specs.load_dict()  # frequency specification widget
        self.a_specs.load_dict()  # magnitude specs with unit
        self.w_specs.load_dict()  # weight specification
        self.t_specs.load_dict()  # target specs

        fb.design_filt_state = "ok"
        qstyle_widget(self.butDesignFilt, "ok")
Пример #36
0
 def load_dict(self):
     """
     Reload all specs/parameters entries from global dict fb.fil[0],
     using the "load_dict" methods of the individual classes
     """
     self.sel_fil.load_dict() # select filter widget
     self.f_units.load_dict() # frequency units widget
     self.f_specs.load_dict() # frequency specification widget
     self.a_specs.load_dict() # magnitude specs with unit
     self.w_specs.load_dict() # weight specification
     self.t_specs.load_dict() # target specs
     
     fb.design_filt_state = "ok"            
     qstyle_widget(self.butDesignFilt, "ok")
Пример #37
0
    def load_dict(self):
        """
        Load all entries from filter dict fb.fil[0]['zpk'] into the Zero/Pole/Gain list
        self.zpk and update the display via `self._refresh_table()`.
        The explicit np.array( ... ) statement enforces a deep copy of fb.fil[0],
        otherwise the filter dict would be modified inadvertedly.

        The filter dict is a "normal" numpy float array for z / p / k values
        The ZPK register `self.zpk` should be a list of float ndarrays to allow
        for different lengths of z / p / k subarrays while adding / deleting items.?
        """
        # TODO: check the above
        self.zpk = np.array(fb.fil[0]['zpk'])  # this enforces a deep copy
        qstyle_widget(self.ui.butSave, 'normal')
        self._refresh_table()
Пример #38
0
    def load_dict(self):
        """
        Load all entries from filter dict fb.fil[0]['zpk'] into the Zero/Pole/Gain list
        self.zpk and update the display via `self._refresh_table()`.
        The explicit np.array( ... ) statement enforces a deep copy of fb.fil[0],
        otherwise the filter dict would be modified inadvertedly.

        The filter dict is a "normal" numpy float array for z / p / k values
        The ZPK register `self.zpk` should be a list of float ndarrays to allow
        for different lengths of z / p / k subarrays while adding / deleting items.?
        """
        # TODO: check the above       
        self.zpk = np.array(fb.fil[0]['zpk'])# this enforces a deep copy
        qstyle_widget(self.ui.butSave, 'normal')
        self._refresh_table()
Пример #39
0
    def fx_select(self):
        """
        Select between fixpoint and floating point simulation
        """
        self.sim_select = qget_cmb_box(self.ui.cmb_sim_select, data=False)
        self.fx_sim = (self.sim_select == 'Fixpoint')
        self.ui.but_run.setVisible(self.fx_sim)
        self.ui.chk_fx_scale.setVisible(self.fx_sim)
        self.ui.chk_fx_range.setVisible(self.fx_sim)
        self.hdl_dict = None

        if self.fx_sim:
            qstyle_widget(self.ui.but_run, "changed")
            self.fx_run()
        else:
            self.draw()
Пример #40
0
    def fx_select(self):
        """
        Select between fixpoint and floating point simulation
        """
        self.sim_select = qget_cmb_box(self.ui.cmb_sim_select, data=False)
        self.fx_sim = (self.sim_select == 'Fixpoint')
        self.ui.but_run.setVisible(self.fx_sim)
        self.ui.chk_fx_scale.setVisible(self.fx_sim)
        self.ui.chk_fx_range.setVisible(self.fx_sim)
        self.hdl_dict = None

        if self.fx_sim:
            qstyle_widget(self.ui.but_run, "changed")
            self.fx_run()
        else:
            self.draw()
Пример #41
0
    def update_UI(self, new_labels=()):
        """
        Called from filter_specs.update_UI() and target_specs.update_UI().
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

        #        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels:  # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels:  # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        tool_tipp_sb = "Min. attenuation resp. maximum level in (this) stop band"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values
            self.qlabels[i].setText(to_html(new_labels[i], frmt='bi'))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>" + tool_tipp_sb +
                                             " (&gt; 0).</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip(
                    "<span>Maximum ripple (&gt; 0) in (this) pass band.<span/>"
                )
            qstyle_widget(self.qlineedit[i], state)

        self.n_cur_labels = num_new_labels  # update number of currently visible labels
        self.load_dict(
        )  # display rounded filter dict entries in selected unit
Пример #42
0
    def update_UI(self, new_labels = ()):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]
            
        self.lblUnit.setText(" in " + rt_label(fb.fil[0]['freq_specs_unit']))
        num_new_labels = len(new_labels)
        # hide / show labels / create new subwidgets if neccessary:
        self._show_entries(num_new_labels)

#        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        #---------------------------- logging -----------------------------
        logger.debug("update_UI: {0}-{1}-{2}".format(
                            fb.fil[0]['rt'],fb.fil[0]['fc'],fb.fil[0]['fo']))

        f_range = " (0 &lt; <i>f</i> &lt; <i>f<sub>S </sub></i>/2)"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values 
            self.qlabels[i].setText(rt_label(new_labels[i]))
            
            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID
            qstyle_widget(self.qlineedit[i], state)

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>Corner frequency for (this) stop band" + f_range + ".</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>Corner frequency for (this) pass band" + f_range + ".</span>")
            else:
                self.qlineedit[i].setToolTip("<span>Corner frequency for (this) band" + f_range + ".</span>")

        self.n_cur_labels = num_new_labels # update number of currently visible labels
        self.sort_dict_freqs() # sort frequency entries in dictionary and update display
Пример #43
0
    def _set_coeffs_zero(self):
        """
        Set all coefficients = 0 in self.ba with a magnitude less than eps
        and refresh QTableWidget
        """
        self._set_eps()
        idx = qget_selected(self.tblCoeff)['idx']  # get all selected indices

        test_val = 0.  # value against which array is tested
        targ_val = 0.  # value which is set when condition is true
        changed = False

        if not idx:  # nothing selected, check whole table
            b_close = np.logical_and(
                np.isclose(self.ba[0], test_val, rtol=0, atol=self.ui.eps),
                (self.ba[0] != targ_val))
            if np.any(b_close
                      ):  # found at least one coeff where condition was true
                self.ba[0] = np.where(b_close, targ_val, self.ba[0])
                changed = True

            if fb.fil[0]['ft'] == 'IIR':
                a_close = np.logical_and(
                    np.isclose(self.ba[1], test_val, rtol=0, atol=self.ui.eps),
                    (self.ba[1] != targ_val))
                if np.any(a_close):
                    self.ba[1] = np.where(a_close, targ_val, self.ba[1])
                    changed = True

        else:  # only check selected cells
            for i in idx:
                if np.logical_and(
                        np.isclose(self.ba[i[0]][i[1]],
                                   test_val,
                                   rtol=0,
                                   atol=self.ui.eps),
                    (self.ba[i[0]][i[1]] != targ_val)):
                    self.ba[i[0]][i[1]] = targ_val
                    changed = True
        if changed:
            qstyle_widget(self.ui.butSave,
                          'changed')  # mark save button as changed

        self._refresh_table()
Пример #44
0
    def load_dict(self):
        """
        Load all entries from filter dict `fb.fil[0]['ba']` into the coefficient
        list `self.ba` and update the display via `self._refresh_table()`.

        The filter dict is a "normal" 2D-numpy float array for the b and a coefficients
        while the coefficient register `self.ba` is a list of two float ndarrays to allow
        for different lengths of b and a subarrays while adding / deleting items.
        """

        self.ba = [0., 0.] # initial list with two elements
        self.ba[0] = np.array(fb.fil[0]['ba'][0]) # deep copy from filter dict to
        self.ba[1] = np.array(fb.fil[0]['ba'][1]) # coefficient register

        # set comboBoxes from dictionary
        self._load_q_settings()

        self._refresh_table()
        qstyle_widget(self.ui.butSave, 'normal')
Пример #45
0
    def load_dict(self):
        """
        Load all entries from filter dict `fb.fil[0]['ba']` into the coefficient
        list `self.ba` and update the display via `self._refresh_table()`.

        The filter dict is a "normal" 2D-numpy float array for the b and a coefficients
        while the coefficient register `self.ba` is a list of two float ndarrays to allow
        for different lengths of b and a subarrays while adding / deleting items.
        """

        self.ba = [0., 0.] # initial list with two elements
        self.ba[0] = np.array(fb.fil[0]['ba'][0]) # deep copy from filter dict to
        self.ba[1] = np.array(fb.fil[0]['ba'][1]) # coefficient register

        # set comboBoxes from dictionary
        self._load_q_settings()

        self._refresh_table()
        qstyle_widget(self.ui.butSave, 'normal')
Пример #46
0
    def update_UI(self, new_labels = ()):
        """
        Called from filter_specs.update_UI() and target_specs.update_UI().
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

#        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels: # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels: # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        tool_tipp_sb = "Min. attenuation resp. maximum level in (this) stop band"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values 
            self.qlabels[i].setText(to_html(new_labels[i], frmt='bi'))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>" + tool_tipp_sb + " (&gt; 0).</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>Maximum ripple (&gt; 0) in (this) pass band.<span/>")
            qstyle_widget(self.qlineedit[i], state)

        self.n_cur_labels = num_new_labels # update number of currently visible labels
        self.load_dict() # display rounded filter dict entries in selected unit
Пример #47
0
    def wdg_dict2ui(self):
        """
        Trigger an update of the fixpoint widget UI when view (i.e. fixpoint 
        coefficient format) or data have been changed outside this class. Additionally,
        pass the fixpoint quantization widget to update / restore other subwidget
        settings.
        
        Set the RUN button to "changed".
        """
        #        fb.fil[0]['fxqc']['QCB'].update({'scale':(1 << fb.fil[0]['fxqc']['QCB']['W'])})
        self.wdg_q_input.dict2ui(fb.fil[0]['fxqc']['QI'])
        self.wdg_q_output.dict2ui(fb.fil[0]['fxqc']['QO'])
        self.wdg_w_input.dict2ui(fb.fil[0]['fxqc']['QI'])
        self.wdg_w_output.dict2ui(fb.fil[0]['fxqc']['QO'])
        if self.fx_wdg_found and hasattr(self.fx_wdg_inst, "dict2ui"):
            self.fx_wdg_inst.dict2ui()
#            dict_sig = {'sender':__name__, 'fx_sim':'specs_changed'}
#            self.sig_tx.emit(dict_sig)

        qstyle_widget(self.butSimHDL, "changed")
Пример #48
0
    def load_dict(self):
        """
        Load all entries from filter dict fb.fil[0]['ba'] into the shadow
        register self.ba and update the display.

        The shadow register is a list of two ndarrays to allow different
        lengths for b and a subarrays while adding / deleting items.
        The explicit np.array( ... ) statement enforces a deep copy of fb.fil[0],
        otherwise the filter dict would be modified inadvertedly. 
        """

        self.ba = [0., 0.]
        self.ba[0] = np.array(fb.fil[0]['ba'][0])
        self.ba[1] = np.array(fb.fil[0]['ba'][1])

        # set comboBoxes from dictionary
        self._load_q_settings()

        self._refresh_table()
        qstyle_widget(self.butSave, 'normal')
Пример #49
0
    def quant_coeffs(self):
        """
        Quantize selected / all coefficients in self.ba and refresh QTableWidget
        """

        self._store_q_settings() # read comboboxes and store setting in filter dict
        # always save quantized coefficients in fractional format
        # -> change output format to 'float' before quantizing and storing in self.ba

        self.myQ.frmt = 'float'

        idx = qget_selected(self.tblCoeff)['idx'] # get all selected indices
        if not idx: # nothing selected, quantize all elements
            self.ba = self.myQ.fixp(self.ba, scaling='div')
        else:
            for i in idx:
                self.ba[i[0]][i[1]] = self.myQ.fixp(self.ba[i[0]][i[1]], scaling = 'div')

        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #50
0
    def _copy_to_table(self):
        """
        Read data from clipboard / file and copy it to `self.zpk` as array of complex
        # TODO: More checks for swapped row <-> col, single values, wrong data type ...
        """
        data_str = qtext2table(self, 'zpk', comment="poles / zeros ")
        if data_str == -1:  # file operation has been aborted
            return

        conv = self.frmt2cmplx  # routine for converting to cartesian coordinates

        if np.ndim(data_str) > 1:
            num_cols, num_rows = np.shape(data_str)
            orientation_horiz = num_cols > num_rows  # need to transpose data
        elif np.ndim(data_str) == 1:
            num_rows = len(data_str)
            num_cols = 1
            orientation_horiz = False
        else:
            logger.error("Imported data is a single value or None.")
            return None
        logger.debug("_copy_to_table: c x r:", num_cols, num_rows)
        if orientation_horiz:
            self.zpk = [[], []]
            for c in range(num_cols):
                self.zpk[0].append(conv(data_str[c][0]))
                if num_rows > 1:
                    self.zpk[1].append(conv(data_str[c][1]))
        else:
            self.zpk[0] = [conv(s) for s in data_str[0]]
            if num_cols > 1:
                self.zpk[1] = [conv(s) for s in data_str[1]]
            else:
                self.zpk[1] = [1]

        self.zpk[0] = np.asarray(self.zpk[0])
        self.zpk[1] = np.asarray(self.zpk[1])

        self._equalize_columns()
        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #51
0
    def _copy_to_table(self):
        """
        Read data from clipboard / file and copy it to `self.zpk` as array of complex
        # TODO: More checks for swapped row <-> col, single values, wrong data type ...
        """
        data_str = qtext2table(self, 'zpk', comment="poles / zeros ")
        if data_str == -1: # file operation has been aborted
            return
        
        conv = self.frmt2cmplx # routine for converting to cartesian coordinates

        if np.ndim(data_str) > 1:
            num_cols, num_rows = np.shape(data_str)
            orientation_horiz = num_cols > num_rows # need to transpose data
        elif np.ndim(data_str) == 1:
            num_rows = len(data_str)
            num_cols = 1
            orientation_horiz = False
        else:
            logger.error("Imported data is a single value or None.")
            return None
        logger.debug("_copy_to_table: c x r:", num_cols, num_rows)
        if orientation_horiz:
            self.zpk = [[],[]]
            for c in range(num_cols):
                self.zpk[0].append(conv(data_str[c][0]))
                if num_rows > 1:
                    self.zpk[1].append(conv(data_str[c][1]))
        else:
            self.zpk[0] = [conv(s) for s in data_str[0]]
            if num_cols > 1:
                self.zpk[1] = [conv(s) for s in data_str[1]]
            else:
                self.zpk[1] = [1]

        self.zpk[0] = np.asarray(self.zpk[0])
        self.zpk[1] = np.asarray(self.zpk[1])

        self._equalize_columns()
        qstyle_widget(self.ui.butSave, 'changed')
        self._refresh_table()
Пример #52
0
    def quant_coeffs(self):
        """
        Quantize selected / all coefficients in self.ba and refresh QTableWidget
        """

        self._store_q_settings(
        )  # read comboboxes and store setting in filter dict
        # always save quantized coefficients in fractional format
        # -> change output format to 'float' before quantizing and storing in self.ba
        self.myQ.frmt = 'float'

        idx = qget_selected(self.tblCoeff)['idx']  # get all selected indices
        if not idx:  # nothing selected, quantize all elements
            self.ba = self.myQ.fix(self.ba, to_float=True)
        else:
            for i in idx:
                self.ba[i[0]][i[1]] = self.myQ.fix(self.ba[i[0]][i[1]],
                                                   to_float=True)

        qstyle_widget(self.butSave, 'changed')
        self._refresh_table()
Пример #53
0
    def _set_coeffs_zero(self):
        """
        Set all coefficients = 0 in self.ba with a magnitude less than eps
        and refresh QTableWidget
        """
        eps = float(self.ledSetEps.text())
        idx = qget_selected(self.tblCoeff)['idx']  # get all selected indices

        test_val = 0.  # value against which array is tested
        targ_val = 0.  # value which is set when condition is true

        if not idx:  # nothing selected, check whole table
            b_0 = np.isclose(self.ba[0], test_val, rtol=0, atol=eps)
            if np.any(
                    b_0):  # found at least one coeff where condition was true
                self.ba[0] = self.ba[0] * np.logical_not(b_0)
                qstyle_widget(self.butSave, 'changed')

            if fb.fil[0]['ft'] == 'IIR':
                a_0 = np.isclose(self.ba[1], test_val, rtol=0, atol=eps)
                if np.any(a_0):
                    self.ba[1] = self.ba[1] * np.logical_not(a_0)
                    qstyle_widget(self.butSave, 'changed')

        else:  # only check selected cells
            changed = False
            for i in idx:
                if np.isclose(self.ba[i[0]][i[1]], test_val, rtol=0, atol=eps):
                    self.ba[i[0]][i[1]] = targ_val
                    changed = True
            if changed:
                # mark save button as changed
                qstyle_widget(self.butSave, 'changed')
        self._refresh_table()
Пример #54
0
    def _add_cells(self):
        """
        Add the number of selected rows to self.ba and fill new cells with
        zeros from the bottom. If nothing is selected, add one row at the bottom.
        Refresh QTableWidget.
        """
        # get indices of all selected cells
        sel = qget_selected(self.tblCoeff)['sel']

        if not np.any(sel): # nothing selected, append zeros to table
            self.ba[0] = np.append(self.ba[0], 0)
            self.ba[1] = np.append(self.ba[1], 0)
        else:
            self.ba[0] = np.insert(self.ba[0], sel[0], 0)
            self.ba[1] = np.insert(self.ba[1], sel[1], 0)

        # insert 'sel' contiguous rows  before 'row':
        # self.ba[0] = np.insert(self.ba[0], row, np.zeros(sel))

        self._equalize_ba_length()
        self._refresh_table()
        # don't tag as 'changed' when only zeros have been added at the end
        if np.any(sel):
            qstyle_widget(self.ui.butSave, 'changed')
Пример #55
0
    def _set_coeffs_zero(self):
        """
        Set all coefficients = 0 in self.ba with a magnitude less than eps
        and refresh QTableWidget
        """
        self._set_eps()
        idx = qget_selected(self.tblCoeff)['idx'] # get all selected indices

        test_val = 0. # value against which array is tested
        targ_val = 0. # value which is set when condition is true
        changed = False

        if not idx: # nothing selected, check whole table
            b_close = np.logical_and(np.isclose(self.ba[0], test_val, rtol=0, atol=self.ui.eps),
                                    (self.ba[0] != targ_val))
            if np.any(b_close): # found at least one coeff where condition was true
                self.ba[0] = np.where(b_close, targ_val, self.ba[0])
                changed = True

            if  fb.fil[0]['ft'] == 'IIR':
                a_close = np.logical_and(np.isclose(self.ba[1], test_val, rtol=0, atol=self.ui.eps),
                                    (self.ba[1] != targ_val))
                if np.any(a_close):
                    self.ba[1] = np.where(a_close, targ_val, self.ba[1])
                    changed = True

        else: # only check selected cells
            for i in idx:
                if np.logical_and(np.isclose(self.ba[i[0]][i[1]], test_val, rtol=0, atol=self.ui.eps),
                                  (self.ba[i[0]][i[1]] != targ_val)):
                    self.ba[i[0]][i[1]] = targ_val
                    changed = True
        if changed:
            qstyle_widget(self.ui.butSave, 'changed') # mark save button as changed

        self._refresh_table()
Пример #56
0
    def fx_sim_set_stimulus(self, dict_sig):
        """
        - Get fixpoint stimulus from ``dict_sig``
        
        - Quantize the stimulus with the selected input quantization settings
        
		- Scale it with the input word length, i.e. with 2**(W-1) (input) to obtain
          integer values
          
        - Pass it to the fixpoint filter and calculate the fixpoint response
        
        - Send the reponse to the plotting widget
        """
        try:
            self.stim = self.q_i.fixp(dict_sig['fx_stimulus']) * (1 << self.q_i.W-1)
            logger.info("\n\n stim W={0}|q={1}\nstim:{2}\nstimq:{3}\n".format(self.q_i.W, self.q_i.q_obj, 
                        dict_sig['fx_stimulus'][0:9], self.stim[0:9]))

            self.hdl_filter_inst.set_stimulus(self.stim)    # Set the simulation input
            self.hdl_filter_inst.run_sim()         # Run the simulation
            logger.info("Start fixpoint simulation with stimulus from {0}.".format(dict_sig['sender']))

            # Get the response from the simulation in integer
            self.fx_results = self.hdl_filter_inst.get_response()
            logger.info("\n\n resp {0}\n".format(self.fx_results[0:9]))
            #TODO: fixed point / integer to float conversion?
            #TODO: color push-button to show state of simulation
            #TODO: add QTimer single shot
#            self.timer_id = QtCore.QTimer()
#            self.timer_id.setSingleShot(True)
#            # kill simulation after some idle time, also add a button for this
#            self.timer_id.timeout.connect(self.kill_sim)

        except myhdl.SimulationError as e:
            logger.warning("Simulation failed:\n{0}".format(e))
            self.fx_results = None
            qstyle_widget(self.butSimHDL, "error")
            return
        except ValueError as e:
            logger.warning("Overflow error {0}".format(e))
            self.fx_results = None
            qstyle_widget(self.butSimHDL, "error")
            return

        logger.info("Fixpoint plotting started")
        dict_sig = {'sender':__name__, 'fx_sim':'set_results', 
                    'fx_results':self.fx_results }            
        self.sig_tx.emit(dict_sig)
        qstyle_widget(self.butSimHDL, "normal")
        
        logger.info("Fixpoint plotting finished")        
            
        return
Пример #57
0
 def color_design_button(self, state):
     fb.design_filt_state = state
     qstyle_widget(self.butDesignFilt, state)