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
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()
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()
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')
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')
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()
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
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
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']) ))
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')
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'])))
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')
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()
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
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
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')
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')
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')
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 < <i>f</i> < <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
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
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')
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()
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()
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()
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")
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")
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()
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
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")
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()
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()
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()
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 + " (> 0).</span>") elif "pb" in new_labels[i].lower(): self.qlineedit[i].setToolTip( "<span>Maximum ripple (> 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
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 < <i>f</i> < <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
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()
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')
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 + " (> 0).</span>") elif "pb" in new_labels[i].lower(): self.qlineedit[i].setToolTip("<span>Maximum ripple (> 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
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")
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')
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()
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()
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()
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()
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()
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')
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()
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
def color_design_button(self, state): fb.design_filt_state = state qstyle_widget(self.butDesignFilt, state)