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.ui2qdict() 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 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 """ self.update_f_unit() state = new_labels[0] new_labels = new_labels[1:] 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 if fb.fil[0]['freq_specs_unit'] in {"f_S", "f_Ny"}: self.qlabels[i].setText(to_html(new_labels[i], frmt='bi')) else: # convert 'F' to 'f' for frequencies in Hz self.qlabels[i].setText( to_html(new_labels[i][0].lower() + new_labels[i][1:], 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 _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', title="Import Filter Coefficients") # returns ndarray of str if data_str is None: # file operation has been aborted or some other error 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 _store_gain(self, source): """ When the textfield of `source` has been edited (flag `self.spec_edited` = True), store it in the shadow dict. This is triggered by `QEvent.focusOut` or RETURN key. """ if self.spec_edited: self.zpk[2] = safe_eval(source.text(), alt_expr=str(self.zpk[2])) qstyle_widget(self.ui.butSave, 'changed') self.spec_edited = False # reset flag
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. `dtype=object` needs to be specified to create a numpy array from the nested lists with differing lengths without creating the deprecation warning "Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated." The filter dict fb.fil[0]['zpk'] is a list of numpy float ndarrays for z / p / k values `self.zpk` is an array of float ndarrays with different lengths of z / p / k subarrays to allow adding / deleting items. """ self.zpk = np.array(fb.fil[0]['zpk'], dtype=object) # this enforces a deep copy qstyle_widget(self.ui.butSave, 'normal') self._refresh_table()