def _construct_table(self, rows, cols, val): """ Create a table with `rows` and `cols`, organized in sets of 3: Name (with a checkbox) - value - unit each item. Parameters ---------- rows : int number of rows cols : int number of columns (must be multiple of 3) val : str initialization value for the table Returns ------- None """ for r in range(rows): for c in range(cols): item = QTableWidgetItem(val) if c % 3 == 0: item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) if self.tbl_sel[r * 2 + c % 3]: item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) self.tbl_win_props.setItem(r, c, item)
def _init_table(self, rows, cols, val): for r in range(rows): for c in range(cols): item = QTableWidgetItem(val) if c % 3 == 0: item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) if self.tbl_sel[r * 2 + c % 3]: item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) self.tblWinProperties.setItem(r, c, item)
def _refresh_table_item(self, row, col): """ Refresh the table item with the index `row, col` from self.ba """ item = self.tblCoeff.item(row, col) if item: # does item exist? item.setText(str(self.ba[col][row]).strip('()')) else: # no, construct it: self.tblCoeff.setItem(row,col,QTableWidgetItem( str(self.ba[col][row]).strip('()'))) self.tblCoeff.item(row, col).setTextAlignment(Qt.AlignRight|Qt.AlignCenter)
def set_table_value(self, col, row, val): item = self.form.tblCoeff.item(row, col) if False: #item: # does item exist? item.setText(str(val)) else: # no, construct it: self.form.tblCoeff.setItem(row, col, QTableWidgetItem(str(val))) self.log.warning( f"Write table, return = {type(self.form.tblCoeff.item(row, col))})" ) self.log.warning(f"Row, col = {row, col})") self.log.warning( f"Row, col = {self.form.tblCoeff.rowCount(), self.form.tblCoeff.columnCount()})" ) #item_text = self.form.tblCoeff.item(1,1).text() #self.log.warning(f"Write table, return = {type(item_text)})") return
def _show_filt_perf(self): """ Print filter properties in a table at frequencies of interest. When specs are violated, colour the table entry in red. """ antiC = False def _find_min_max(self, f_start, f_stop, unit='dB'): """ Find minimum and maximum magnitude and the corresponding frequencies for the filter defined in the filter dict in a given frequency band [f_start, f_stop]. """ w = np.linspace(f_start, f_stop, params['N_FFT'])*2*np.pi [w, H] = sig.freqz(bb, aa, worN=w) # add antiCausals if we have them if (antiC): # # Evaluate transfer function of anticausal half on the same freq grid. # wa, ha = sig.freqz(bbA, aaA, worN=w) ha = ha.conjugate() # # Total transfer function is the product # H = H*ha f = w / (2.0 * pi) # frequency normalized to f_S H_abs = abs(H) H_max = max(H_abs) H_min = min(H_abs) F_max = f[np.argmax(H_abs)] # find the frequency where H_abs F_min = f[np.argmin(H_abs)] # becomes max resp. min if unit == 'dB': H_max = 20*log10(H_max) H_min = 20*log10(H_min) return F_min, H_min, F_max, H_max # ------------------------------------------------------------------ self.tblFiltPerf.setVisible(self.butFiltPerf.isChecked()) if self.butFiltPerf.isChecked(): bb = fb.fil[0]['ba'][0] aa = fb.fil[0]['ba'][1] # 'rpk' means nonCausal filter if 'rpk' in fb.fil[0]: antiC = True bbA = fb.fil[0]['baA'][0] aaA = fb.fil[0]['baA'][1] bbA = bbA.conjugate() aaA = aaA.conjugate() f_S = fb.fil[0]['f_S'] f_lbls = [] f_vals = [] a_lbls = [] a_targs = [] a_targs_dB = [] a_test = [] ft = fb.fil[0]['ft'] # get filter type ('IIR', 'FIR') unit = fb.fil[0]['amp_specs_unit'] unit = 'dB' # fix this for the moment # construct pairs of corner frequency and corresponding amplitude # labels in ascending frequency for each response type if fb.fil[0]['rt'] in {'LP', 'HP', 'BP', 'BS', 'HIL'}: if fb.fil[0]['rt'] == 'LP': f_lbls = ['F_PB', 'F_SB'] a_lbls = ['A_PB', 'A_SB'] elif fb.fil[0]['rt'] == 'HP': f_lbls = ['F_SB', 'F_PB'] a_lbls = ['A_SB', 'A_PB'] elif fb.fil[0]['rt'] == 'BP': f_lbls = ['F_SB', 'F_PB', 'F_PB2', 'F_SB2'] a_lbls = ['A_SB', 'A_PB', 'A_PB', 'A_SB2'] elif fb.fil[0]['rt'] == 'BS': f_lbls = ['F_PB', 'F_SB', 'F_SB2', 'F_PB2'] a_lbls = ['A_PB', 'A_SB', 'A_SB', 'A_PB2'] elif fb.fil[0]['rt'] == 'HIL': f_lbls = ['F_PB', 'F_PB2'] a_lbls = ['A_PB', 'A_PB'] # Try to get lists of frequency / amplitude specs from the filter dict # that correspond to the f_lbls / a_lbls pairs defined above # When one of the labels doesn't exist in the filter dict, delete # all corresponding amplitude and frequency entries. err = [False] * len(f_lbls) # initialize error list f_vals = [] a_targs = [] for i in range(len(f_lbls)): try: f = fb.fil[0][f_lbls[i]] f_vals.append(f) except KeyError as e: f_vals.append('') err[i] = True logger.debug(e) try: a = fb.fil[0][a_lbls[i]] a_dB = lin2unit(fb.fil[0][a_lbls[i]], ft, a_lbls[i], unit) a_targs.append(a) a_targs_dB.append(a_dB) except KeyError as e: a_targs.append('') a_targs_dB.append('') err[i] = True logger.debug(e) for i in range(len(f_lbls)): if err[i]: del f_lbls[i] del f_vals[i] del a_lbls[i] del a_targs[i] del a_targs_dB[i] f_vals = np.asarray(f_vals) # convert to numpy array logger.debug("F_test_labels = %s" % f_lbls) # Calculate frequency response at test frequencies [w_test, a_test] = sig.freqz(bb, aa, 2.0 * pi * f_vals.astype(float)) # add antiCausals if we have them if (antiC): wa, ha = sig.freqz(bbA, aaA, 2.0 * pi * f_vals.astype(float)) ha = ha.conjugate() a_test = a_test*ha (F_min, H_min, F_max, H_max) = _find_min_max(self, 0, 1, unit='V') # append frequencies and values for min. and max. filter reponse to # test vector f_lbls += ['Min.', 'Max.'] # QTableView does not support direct formatting, use QLabel f_vals = np.append(f_vals, [F_min, F_max]) a_targs = np.append(a_targs, [np.nan, np.nan]) a_targs_dB = np.append(a_targs_dB, [np.nan, np.nan]) a_test = np.append(a_test, [H_min, H_max]) # calculate response of test frequencies in dB a_test_dB = -20*log10(abs(a_test)) # get filter type ('IIR', 'FIR') for dB <-> lin conversion ft = fb.fil[0]['ft'] # unit = fb.fil[0]['amp_specs_unit'] unit = 'dB' # make this fixed for the moment # build a list with the corresponding target specs: a_targs_pass = [] eps = 1e-3 for i in range(len(f_lbls)): if 'PB' in f_lbls[i]: a_targs_pass.append((a_test_dB[i] - a_targs_dB[i]) < eps) a_test[i] = 1 - abs(a_test[i]) elif 'SB' in f_lbls[i]: a_targs_pass.append(a_test_dB[i] >= a_targs_dB[i]) else: a_targs_pass.append(True) self.targs_spec_passed = np.all(a_targs_pass) logger.debug( "H_targ = {0}\n" "H_test = {1}\n" "H_test_dB = {2}\n" "F_test = {3}\n" "H_targ_pass = {4}\n" "passed: {5}\n".format(a_targs, a_test, a_test_dB, f_vals, a_targs_pass, self.targs_spec_passed)) self.tblFiltPerf.setRowCount(len(a_test)) # number of table rows self.tblFiltPerf.setColumnCount(5) # number of table columns self.tblFiltPerf.setHorizontalHeaderLabels([ 'f/{0:s}'.format(fb.fil[0]['freq_specs_unit']), 'Spec\n(dB)', '|H(f)|\n(dB)', 'Spec', '|H(f)|']) self.tblFiltPerf.setVerticalHeaderLabels(f_lbls) for row in range(len(a_test)): self.tblFiltPerf.setItem( row, 0, QTableWidgetItem(str('{0:.4g}'.format(f_vals[row]*f_S)))) self.tblFiltPerf.setItem( row, 1, QTableWidgetItem(str('%2.3g'%(-a_targs_dB[row])))) self.tblFiltPerf.setItem( row, 2, QTableWidgetItem(str('%2.3f'%(-a_test_dB[row])))) if a_targs[row] < 0.01: self.tblFiltPerf.setItem( row, 3, QTableWidgetItem(str('%.3e'%(a_targs[row])))) else: self.tblFiltPerf.setItem( row, 3, QTableWidgetItem(str('%2.4f'%(a_targs[row])))) if a_test[row] < 0.01: self.tblFiltPerf.setItem( row, 4, QTableWidgetItem(str('%.3e'%(abs(a_test[row]))))) else: self.tblFiltPerf.setItem( row, 4, QTableWidgetItem(str('%.4f'%(abs(a_test[row]))))) if not a_targs_pass[row]: self.tblFiltPerf.item(row, 1).setBackground(QtGui.QColor('red')) self.tblFiltPerf.item(row, 3).setBackground(QtGui.QColor('red')) self.tblFiltPerf.resizeColumnsToContents() self.tblFiltPerf.resizeRowsToContents()