def setupHDL(self, file_name = "", dir_name = ""): """ Setup instance of myHDL object with word lengths and coefficients """ # get a dict with the coefficients and fixpoint settings from fixpoint widget self.hdl_dict = self.fx_wdg_inst.get_hdl_dict() self.q_i = fx.Fixed(self.hdl_dict['QI']) # setup quantizer for input quantization self.q_i.setQobj({'frmt':'dec'})#, 'scale':'int'}) # use integer decimal format self.q_o = fx.Fixed(self.hdl_dict['QO']) # setup quantizer for output quantization b = [ int(x) for x in self.hdl_dict['QC']['b']] # convert np.int64 to python int a = [ int(x) for x in self.hdl_dict['QC']['a']] # convert np.int64 to python int # call setup method of filter widget - this is not implemented (yet) # self.fx_wdg_inst.setup_HDL(self.hdl_dict) if fb.fil[0]['ft'] == 'FIR': self.hdlfilter = FilterFIR() # Standard DF1 filter - hdl_dict should be passed here self.hdlfilter.set_coefficients(coeff_b = b) # Coefficients for the filter elif fb.fil[0]['ft'] == 'IIR': self.hdlfilter = FilterIIR() # Standard DF1 filter - hdl_dict should be passed here self.hdlfilter.set_coefficients(coeff_b = b, coeff_a = a) # Coefficients for the filter else: logger.error("Unknown filter type {0}".format(fb.fil[0]['ft'])) # pass wordlength for coeffs, input, output self.hdlfilter.set_word_format( (self.hdl_dict['QC']['W'], self.hdl_dict['QC']['WI'], self.hdl_dict['QC']['WF']), (self.hdl_dict['QI']['W'], self.hdl_dict['QI']['WI'], self.hdl_dict['QI']['WF']), (self.hdl_dict['QO']['W'], self.hdl_dict['QO']['WI'], self.hdl_dict['QO']['WF']) )
def update_hdl_filter(self): """ Update the HDL filter object with new coefficients, quantization settings etc. when - it is constructed - filter design and hence coefficients change - quantization settings are updated in this widget """ # setup input and output quantizers self.q_i = fx.Fixed(self.hdl_dict['QI']) # setup quantizer for input quantization self.q_i.setQobj({'frmt':'dec'})#, 'scale':'int'}) # use integer decimal format self.q_o = fx.Fixed(self.hdl_dict['QO']) # setup quantizer for output quantization b = [ int(x) for x in self.hdl_dict['QC']['b']] # convert np.int64 to python int a = [ int(x) for x in self.hdl_dict['QC']['a']] # convert np.int64 to python int # call setup method of filter widget - this is not implemented (yet) # self.fx_wdg_inst.setup_HDL(self.hdl_dict) self.hdlfilter.set_coefficients(coeff_b = b, coeff_a = a) # Coefficients for the filter # pass wordlength for coeffs, input, output # TODO: directly pass the hdl_dict here: self.hdlfilter.set_word_format( (self.hdl_dict['QC']['W'], self.hdl_dict['QC']['WI'], self.hdl_dict['QC']['WF']), (self.hdl_dict['QI']['W'], self.hdl_dict['QI']['WI'], self.hdl_dict['QI']['WF']), (self.hdl_dict['QO']['W'], self.hdl_dict['QO']['WI'], self.hdl_dict['QO']['WF']) )
def setupHDL(self, filename = ""): """ Setup instance of myHDL object with word lengths and coefficients """ qI_i = int(self.ledQIInput.text()) qF_i = int(self.ledQFInput.text()) qI_o = int(self.ledQIOutput.text()) qF_o = int(self.ledQFOutput.text()) qQuant_o = self.cmbQuant_o.currentText() qOvfl_o = self.cmbOvfl_o.currentText() q_obj_o = {'QI':qI_o, 'QF': qF_o, 'quant': qQuant_o, 'ovfl': qOvfl_o} myQ_o = fix.Fixed(q_obj_o) # instantiate fixed-point object self.W = (qI_i + qF_i + 1, 0) # Matlab format: (W,WF) # get filter coefficients etc. from filter dict coeffs = fb.fil[0]['ba'] zpk = fb.fil[0]['zpk'] sos = fb.fil[0]['sos'] # =============== adapted from C. Feltons SIIR example ============= self.flt = SIIR(W = self.W, b = np.array(coeffs[0][0:3]), a = np.array(coeffs[1][0:3]))
def quant_coeffs(self, q_dict, coeffs): """ Quantize the coefficients, scale and convert them to integer and return them as a list of integers This is called every time one of the coefficient subwidgets is edited or changed. Parameters: ----------- None Returns: -------- A list of integer coeffcients, quantized and scaled with the settings of the passed quantization dict """ # Create coefficient quantizer instances using the quantization parameters dict # collected in `input_widgets/input_coeffs.py` (and stored in the central filter dict) Q_coeff = fix.Fixed(q_dict) Q_coeff.frmt = 'dec' # always use decimal format for coefficients if coeffs is None: logger.error("Coeffs empty!") # quantize floating point coefficients and convert them to the # selected numeric format (hex, bin, dec ...) with the selected scale (WI.WF), # next convert array float -> array of fixp - > list of int (scaled by 2^WF) return list(Q_coeff.float2frmt(coeffs) * (1 << Q_coeff.WF))
def save_file_coe(self, file_name): """ Save filter coefficients in Xilinx coefficient format, specifying the number base and the quantized coefficients """ frmt = fb.fil[0]['q_coeff']['frmt'] # store old format fb.fil[0]['q_coeff']['frmt'] = 'dec' # 'hex' qc = fix_lib.Fixed(fb.fil[0]['q_coeff']) bq = qc.fix(fb.fil[0]['ba'][0]) # Quantize coefficients to integer format coe_width = qc.QF + qc.QI + 1 # quantized word length; Int. + Frac. + Sign bit if fb.fil[0]['q_coeff']['frmt'] == 'dec': coe_radix = 10 else: coe_radix = 16 fb.fil[0]['q_coeff']['frmt'] = frmt # restore old coefficient format info_str = ( "; #############################################################################\n" ";\n; XILINX CORE Generator(tm) Distributed Arithmetic FIR filter coefficient (.COE) file\n" ";\n; Generated by pyFDA 0.1 (https://github.com/chipmuenk/pyfda)\n;\n; ") date_str = datetime.datetime.now().strftime("%d-%B-%Y %H:%M:%S") file_name.write(info_str + date_str + "\n;\n") filt_str = "; Filter order = %d, type: %s\n" %(fb.fil[0]["N"], fb.fil[0]['rt']) file_name.write(filt_str) file_name.write("; #############################################################################\n") file_name.write("Radix = %d;\n" %coe_radix) file_name.write("Coefficient_width = %d;\n" %coe_width) coeff_str = "CoefData = " for b in bq: coeff_str += str(b) + ",\n" file_name.write(coeff_str[:-2] + ";") # replace last "," by ";"
def quant_coeffs(self): """ Quantize all coefficients """ # define + instantiate fixed-point object myQ = fix.Fixed({ 'QI': int(self.ledQuantI.text()), 'QF': int(self.ledQuantF.text()), 'quant': self.cmbQQuant.currentText(), 'ovfl': self.cmbQOvfl.currentText(), 'frmt': self.cmbQFormat.currentText() }) num_rows, num_cols = self.tblCoeff.rowCount(),\ self.tblCoeff.columnCount() for col in range(num_cols): for row in range(num_rows): item = self.tblCoeff.item(row, col) if item: item.setText(str(myQ.fix(simple_eval(item.text())))) else: self.tblCoeff.setItem(row, col, QtGui.QTableWidgetItem("0.0")) self.tblCoeff.resizeColumnsToContents() self.tblCoeff.resizeRowsToContents()
def build_coeff_dict(frmt=None): """ Read and quantize the coefficients and return them as a dictionary. This is called every time one of the coefficient subwidgets is edited or changed. Parameters: ----------- frmt: string One of the following options: 'dec' (default), 'hex', 'bin', 'csd' Returns: -------- A dictionary with the followig keys and values: - WI: integer - WF: integer - scale: float - frmt: string - f_fix: np.array - a_fix: np.array """ bf = fb.fil[0]['ba'][0] # get coefficients from af = fb.fil[0]['ba'][1] # filter dict in float form # Create a coefficient quantizer instance using the quantization parameters dict # collected in `input_widgets/input_coeffs.py` (and stored in the central filter dict) Q_coeff = fix.Fixed(fb.fil[0]["q_coeff"]) #Q_coeff.setQobj(fb.fil[0]['q_coeff']) # alternative: explicitly call setter if not frmt: Q_coeff.frmt = 'dec' # use decimal format for coefficients by default else: Q_coeff.frmt = frmt # use the function argument # quantize floating point coefficients and convert them to the # selected numeric format (hex, bin, dec ...) with the selected scale (WI.WF) c_dict = {} # convert list of float -> dec (np.int64). # item() converts np.int64 -> int c_dict.update({'b': [b.item() for b in Q_coeff.float2frmt(bf)] }) # convert float -> fixp and c_dict.update({'a': [a.item() for a in Q_coeff.float2frmt(af)] }) # format it as bin, hex, ... c_dict.update({'WF': Q_coeff.WF}) # read parameters from quantizer instance c_dict.update({'WI': Q_coeff.WI}) # and pass them to the coefficient dict c_dict.update({'W': Q_coeff.W}) c_dict.update({'scale': Q_coeff.scale}) # for later use c_dict.update({'frmt': Q_coeff.frmt}) return c_dict
def setupHDL(self, file_name="", dir_name=""): """ Setup instance of myHDL object with word lengths and coefficients """ self.qI_i = safe_eval(self.ledWIInput.text(), return_type='int', sign='pos') self.qF_i = safe_eval(self.ledWFInput.text(), return_type='int', sign='pos') self.ledWIInput.setText(qstr(self.qI_i)) self.ledWFInput.setText(qstr(self.qF_i)) self.qI_o = safe_eval(self.ledWIOutput.text(), return_type='int', sign='pos') self.qF_o = safe_eval(self.ledWFOutput.text(), return_type='int', sign='pos') self.ledWIOutput.setText(qstr(self.qI_o)) self.ledWFOutput.setText(qstr(self.qF_o)) qQuant_o = self.cmbQuant_o.currentText() qOvfl_o = self.cmbOvfl_o.currentText() q_obj_o = { 'WI': self.qI_o, 'WF': self.qF_o, 'quant': qQuant_o, 'ovfl': qOvfl_o } myQ_o = fix.Fixed(q_obj_o) # instantiate fixed-point object self.W = (self.qI_i + self.qF_i + 1, self.qF_i ) # Matlab format: (W,WF) # @todo: always use sos? The filter object is setup to always # @todo: generate a second order filter # get filter coefficients etc. from filter dict coeffs = fb.fil[0]['ba'] zpk = fb.fil[0]['zpk'] sos = fb.fil[0]['sos'] logger.info("W = {0}".format(self.W)) logger.info('b = {0}'.format(coeffs[0][0:3])) logger.info('a = {0}'.format(coeffs[1][0:3])) # =============== adapted from C. Felton's SIIR example ============= self.flt = FilterIIR( b=np.array(coeffs[0][0:3]), a=np.array(coeffs[1][0:3]), #sos = sos, doesn't work yet word_format=(self.W[0], 0, self.W[1])) self.flt.hdl_name = file_name self.flt.hdl_directory = dir_name
def update_fxqc_dict(self): """ Update the fxqc dictionary before simulation / HDL generation starts. """ if self.fx_wdg_found: # get a dict with the coefficients and fixpoint settings from fixpoint widget if hasattr(self.fx_wdg_inst, "ui2dict"): self.fxqc_dict.update(self.fx_wdg_inst.ui2dict()) self.q_i = fx.Fixed( self.fxqc_dict['QI']) # setup quantizer for input quantization self.q_i.setQobj({ 'frmt': 'dec' }) #, 'scale':'int'}) # always use integer decimal format self.q_o = fx.Fixed(self.fxqc_dict['QO'] ) # setup quantizer for output quantization # TODO: is the output quantizer really needed? Isn't it part of the migen implementation? else: logger.error("No fixpoint widget found!")
def update_fxqc_dict(self): """ Update the fxqc dictionary before simulation / HDL generation starts. It is NOT updated each time one of the relevant widgets changes ("lazy update"). This avoids having to connect and disconnect all sorts of signals and slots. """ if self.fx_wdg_found: # get a dict with the coefficients and fixpoint settings from fixpoint widget if hasattr(self.fx_wdg_inst, "ui2dict"): self.fxqc_dict.update(self.fx_wdg_inst.ui2dict()) # update the fxqc_dict with the settings of the input quantizer self.fxqc_dict.update({ 'QI': { 'WI': self.wdg_w_input.WI, 'WF': self.wdg_w_input.WF, 'W': self.wdg_w_input.W, 'ovfl': self.wdg_q_input.ovfl, 'quant': self.wdg_q_input.quant } }) # output quantization parameters self.fxqc_dict.update({ 'QO': { 'WI': self.wdg_w_output.WI, 'WF': self.wdg_w_output.WF, 'W': self.wdg_w_output.W, 'ovfl': self.wdg_q_output.ovfl, 'quant': self.wdg_q_output.quant } }) self.q_i = fx.Fixed( self.fxqc_dict['QI']) # setup quantizer for input quantization self.q_i.setQobj({ 'frmt': 'dec' }) #, 'scale':'int'}) # always use integer decimal format self.q_o = fx.Fixed(self.fxqc_dict['QO'] ) # setup quantizer for output quantization else: logger.error("No fixpoint widget found!")
def build_coeff_dict(frmt=None): """ Read and quantize the coefficients and return them as a dictionary Parameters: ----------- frmt: string One of the following options: 'dec' (default), 'hex', 'bin', 'csd' Returns: -------- A dictionary with the followig keys and values: - WI: integer - WF: integer - scale: - frmt: - f_fix: np.array - a_fix: np.array """ b = fb.fil[0]['ba'][0] a = fb.fil[0]['ba'][1] # update the coefficient quantizer object Q_coeff = fix.Fixed(fb.fil[0]["q_coeff"]) #Q_coeff.setQobj(fb.fil[0]['q_coeff']) if not frmt: Q_coeff.frmt = 'dec' # use decimal format for coefficients by default else: Q_coeff.frmt = frmt # use the function argument # quantize floating point coefficients and converts them to the # selected numeric format (hex, bin, dec ...) c_dict = {} c_dict.update({'b':list(Q_coeff.float2frmt(b))}) c_dict.update({'a':list(Q_coeff.float2frmt(a))}) c_dict.update({'WF':Q_coeff.WF}) c_dict.update({'WI':Q_coeff.WI}) c_dict.update({'scale':Q_coeff.scale}) c_dict.update({'frmt':Q_coeff.frmt}) return c_dict
def export_coe_microsemi(f): """ Save FIR filter coefficients in Actel coefficient format as file '\*.txt'. Coefficients have to be in integer format, the last line has to be empty. For (anti)aymmetric filter only one half of the coefficients must be specified? """ qc = fix_lib.Fixed(fb.fil[0]['q_coeff']) # instantiate fixpoint object qc.setQobj({'frmt':'dec'}) # select decimal format in all other cases # Quantize coefficients to decimal integer format, returning an array of strings bq = qc.float2frmt(fb.fil[0]['ba'][0]) coeff_str = "coefficient_set_1\n" for b in bq: coeff_str += str(b) + "\n" f.write(coeff_str)
def export_coe_xilinx(f): """ Save FIR filter coefficients in Xilinx coefficient format as file '\*.coe', specifying the number base and the quantized coefficients (decimal or hex integer). """ qc = fix_lib.Fixed(fb.fil[0]['q_coeff']) # instantiate fixpoint object if qc.frmt == 'hex': # select hex format coe_radix = 16 else: qc.setQobj({'frmt': 'dec'}) # select decimal format in all other cases coe_radix = 10 # Quantize coefficients to decimal / hex integer format, returning an array of strings bq = qc.float2frmt(fb.fil[0]['ba'][0]) date_frmt = "%d-%B-%Y %H:%M:%S" # select date format xil_str = ( "; #############################################################################\n" ";\n; XILINX CORE Generator(tm) Distributed Arithmetic FIR filter coefficient (.COE) file\n" ";\n; Generated by pyFDA 0.1 (https://github.com/chipmuenk/pyfda)\n;\n" ) xil_str += "; Designed:\t{0}\n".format( datetime.datetime.fromtimestamp(int( fb.fil[0]['timestamp'])).strftime(date_frmt)) xil_str += "; Saved:\t{0}\n;\n".format( datetime.datetime.now().strftime(date_frmt)) xil_str += "; Filter order = {0}, type: {1}\n".format( fb.fil[0]["N"], fb.fil[0]['rt']) xil_str += "; Params:\t f_S = {0}\n".format(fb.fil[0]["f_S"]) xil_str += "; #############################################################################\n" xil_str += "Radix = {0};\n".format(coe_radix) xil_str += "Coefficient_width = {0};\n".format( qc.W) # quantized wordlength coeff_str = "CoefData = " for b in bq: coeff_str += str(b) + ",\n" xil_str += coeff_str[:-2] + ";" # replace last "," by ";" f.write(unicode_23(xil_str)) # convert to unicode for Python 2
def setUp(self): q_obj = { 'WI': 0, 'WF': 3, 'ovfl': 'sat', 'quant': 'round', 'frmt': 'dec', 'scale': 1 } self.myQ = fix_lib.Fixed( q_obj) # instantiate fixpoint object with settings above self.y_list = [-1.1, -1.0, -0.5, 0, 0.5, 0.9, 0.99, 1.0, 1.1] self.y_list_cmplx = [ -1.1j + 0.1, -1.0 - 0.3j, -0.5 - 0.5j, 0j, 0.5j, 0.9, 0.99 + 0.3j, 1j, 1.1 ] # list with various invalid strings self.y_list_validate = [ '1.1.1', 'xxx', '123', '1.23', '', 1.23j + 3.21, '3.21 + 1.23 j' ]
def _construct_UI(self): """ Intitialize the widget, consisting of: - top chkbox row - coefficient table - two bottom rows with action buttons """ # handle to central clipboard instance self.clipboard = fb.clipboard # --------------------------------------------------------------------- # Coefficient table widget # --------------------------------------------------------------------- self.tblCoeff = QTableWidget(self) self.tblCoeff.setAlternatingRowColors(True) self.tblCoeff.horizontalHeader().setHighlightSections(True) # highlight when selected self.tblCoeff.horizontalHeader().setFont(self.ui.bfont) # self.tblCoeff.QItemSelectionModel.Clear self.tblCoeff.setDragEnabled(True) # self.tblCoeff.setDragDropMode(QAbstractItemView.InternalMove) # doesn't work like intended self.tblCoeff.setItemDelegate(ItemDelegate(self)) # ============== Main UI Layout ===================================== layVMain = QVBoxLayout() layVMain.setAlignment(Qt.AlignTop) # this affects only the first widget (intended here) layVMain.addWidget(self.ui) layVMain.addWidget(self.tblCoeff) layVMain.setContentsMargins(*params['wdg_margins']) self.setLayout(layVMain) self.myQ = fix.Fixed(fb.fil[0]["q_coeff"]) # initialize fixpoint object self.load_dict() # initialize + refresh table with default values from filter dict # TODO: this needs to be optimized - self._refresh is being called in both routines self._set_number_format() # ============== Signals & Slots ================================ # wdg.textChanged() is emitted when contents of widget changes # wdg.textEdited() is only emitted for user changes # wdg.editingFinished() is only emitted for user changes self.ui.butEnable.clicked.connect(self._refresh_table) self.ui.spnDigits.editingFinished.connect(self._refresh_table) self.ui.cmbQFrmt.currentIndexChanged.connect(self._set_number_format) self.ui.butFromTable.clicked.connect(self._copy_from_table) self.ui.butToTable.clicked.connect(self._copy_to_table) self.ui.cmbFilterType.currentIndexChanged.connect(self._filter_type) self.ui.butDelCells.clicked.connect(self._delete_cells) self.ui.butAddCells.clicked.connect(self._add_cells) self.ui.butLoad.clicked.connect(self.load_dict) self.ui.butSave.clicked.connect(self._save_dict) self.ui.butClear.clicked.connect(self._clear_table) self.ui.ledEps.editingFinished.connect(self._set_eps) self.ui.butSetZero.clicked.connect(self._set_coeffs_zero) # refresh table after storing new settings self.ui.cmbFormat.currentIndexChanged.connect(self._refresh_table) self.ui.cmbQOvfl.currentIndexChanged.connect(self._refresh_table) self.ui.cmbQuant.currentIndexChanged.connect(self._refresh_table) self.ui.ledWF.editingFinished.connect(self._WIWF_changed) self.ui.ledWI.editingFinished.connect(self._WIWF_changed) self.ui.ledW.editingFinished.connect(self._W_changed) self.ui.ledScale.editingFinished.connect(self._set_scale) self.ui.butQuant.clicked.connect(self.quant_coeffs)
def _construct_UI(self): """ Intitialize the widget, consisting of: - top chkbox row - coefficient table - two bottom rows with action buttons """ self.bfont = QFont() self.bfont.setBold(True) self.bifont = QFont() self.bifont.setBold(True) self.bifont.setItalic(True) # q_icon_size = QSize(20, 20) # optional, size is derived from butEnable #============================================================================== # #Which Button holds the longest Text? # MaxTextlen = 0 # longestText = "" # ButLength = 0 # butTexts = ["Add", "Delete", "Save", "Load", "Clear", "Set Zero", "< Q >"] # # # Find the longest text + padding for subsequent bounding box calculation # for item in butTexts: # if len(item) > MaxTextlen: # MaxTextlen = len(item) # longestText = item + "mm" # this is the longest text + padding for # # #Calculate the length for the buttons based on the longest ButtonText # #ButLength = butAddRow.fontMetrics().boundingRect(longestText).width() # butDelCell.setText(butTexts[1]) # butDelCell.setMaximumWidth(ButLength) # #============================================================================== # --------------------------------------------- # UI Elements for controlling the display # --------------------------------------------- self.butEnable = QPushButton(self) self.butEnable.setIcon(QIcon(':/circle-check.svg')) q_icon_size = self.butEnable.iconSize( ) # <- uncomment this for manual sizing self.butEnable.setIconSize(q_icon_size) self.butEnable.setCheckable(True) self.butEnable.setChecked(True) self.butEnable.setToolTip( "<span>Show filter coefficients as an editable table." "For high order systems, this might be slow.</span>") self.cmbFormat = QComboBox(self) # self.cmbFormat.addItem('Float') qFormat = ['Float', 'Dec', 'Hex', 'Bin', 'CSD'] self.cmbFormat.addItems(qFormat) self.cmbFormat.insertSeparator(1) self.cmbFormat.setCurrentIndex(0) # 'float' self.cmbFormat.setToolTip('Set the display format.') self.cmbFormat.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.lblRound = QLabel("Digits = ", self) self.spnRound = QSpinBox(self) self.spnRound.setRange(0, 16) self.spnRound.setValue(params['FMT_ba']) self.spnRound.setToolTip("Display <i>d</i> digits.") self.chkRadixPoint = QCheckBox("Radix point", self) self.chkRadixPoint.setToolTip( "<span>Show and use radix point (= decimal" " point for base 10) for fixpoint formats (still disabled).</span>" ) self.chkRadixPoint.setChecked(False) self.chkRadixPoint.setCheckable(True) layHDisplay = QHBoxLayout() layHDisplay.setAlignment(Qt.AlignLeft) layHDisplay.addWidget(self.butEnable) layHDisplay.addWidget(self.cmbFormat) layHDisplay.addWidget(self.lblRound) layHDisplay.addWidget(self.spnRound) layHDisplay.addWidget(self.chkRadixPoint) layHDisplay.addStretch() # --------------------------------------------- # UI Elements for loading / storing # --------------------------------------------- self.cmbFilterType = QComboBox(self) self.cmbFilterType.setObjectName("comboFilterType") self.cmbFilterType.setToolTip( "Select between IIR and FIR filte for manual entry.") self.cmbFilterType.addItems(["FIR", "IIR"]) self.cmbFilterType.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.tblCoeff = QTableWidget(self) self.tblCoeff.setAlternatingRowColors(True) self.tblCoeff.horizontalHeader().setHighlightSections( True) # highlight when selected self.tblCoeff.horizontalHeader().setFont(self.bfont) # self.tblCoeff.QItemSelectionModel.Clear self.tblCoeff.setDragEnabled(True) # self.tblCoeff.setDragDropMode(QAbstractItemView.InternalMove) # doesn't work like intended self.tblCoeff.setItemDelegate(ItemDelegate(self)) butAddCells = QPushButton(self) butAddCells.setIcon(QIcon(':/plus.svg')) butAddCells.setIconSize(q_icon_size) butAddCells.setToolTip( "<SPAN>Select cells to insert a new cell above each selected cell. " "Use <SHIFT> or <CTRL> to select multiple cells. " "When nothing is selected, add a row at the end.</SPAN>") butDelCells = QPushButton(self) butDelCells.setIcon(QIcon(':/minus.svg')) butDelCells.setIconSize(q_icon_size) butDelCells.setToolTip( "<SPAN>Delete selected cell(s) from the table. " "Use <SHIFT> or <CTRL> to select multiple cells. " "When nothing is selected, delete the last row.</SPAN>") butQuant = QPushButton(self) butQuant.setToolTip( "<span>Quantize selected coefficients with specified settings. " "When nothing is selected, quantize the whole table.</span>") # butQuant.setText("Q!") butQuant.setIcon(QIcon(':/quantize.svg')) butQuant.setIconSize(q_icon_size) self.butSave = QPushButton(self) self.butSave.setIcon(QIcon(':/upload.svg')) self.butSave.setIconSize(q_icon_size) self.butSave.setToolTip( "<span>Save coefficients and update all plots. " "No modifications are saved before!</span>") butLoad = QPushButton(self) butLoad.setIcon(QIcon(':/download.svg')) butLoad.setIconSize(q_icon_size) butLoad.setToolTip("Reload coefficients.") butClear = QPushButton(self) butClear.setIcon(QIcon(':/trash.svg')) butClear.setIconSize(q_icon_size) butClear.setToolTip("Clear all entries.") self.butClipboard = QPushButton(self) self.butClipboard.setIcon(QIcon(':/clipboard.svg')) self.butClipboard.setIconSize(q_icon_size) self.butClipboard.setToolTip( "<span>Copy table to clipboard, selected items are copied as " "displayed. When nothing is selected, the whole table " "is copied with full precision in decimal format. </span>") layHButtonsCoeffs1 = QHBoxLayout() layHButtonsCoeffs1.addWidget(butAddCells) layHButtonsCoeffs1.addWidget(butDelCells) layHButtonsCoeffs1.addWidget(butQuant) layHButtonsCoeffs1.addWidget(butClear) layHButtonsCoeffs1.addWidget(self.butSave) layHButtonsCoeffs1.addWidget(butLoad) layHButtonsCoeffs1.addWidget(self.butClipboard) layHButtonsCoeffs1.addWidget(self.cmbFilterType) layHButtonsCoeffs1.addStretch() #--------------------------------------------------------- butSetZero = QPushButton("= 0", self) butSetZero.setToolTip( "<span>Set selected coefficients = 0 with a magnitude < ε. " "When nothing is selected, test the whole table.</span>") butSetZero.setIconSize(q_icon_size) self.lblEps = QLabel(self) self.lblEps.setText("for b, a <") self.ledSetEps = QLineEdit(self) self.ledSetEps.setToolTip("Specify eps value.") self.ledSetEps.setText(str(1e-6)) self.lblWIWF = QLabel("W = ") self.lblWIWF.setFont(self.bifont) self.lblQOvfl = QLabel("Ovfl.:") self.lblQuant = QLabel("Quant.:") self.ledW = QLineEdit(self) self.ledW.setToolTip("Specify wordlength.") self.ledW.setText("16") self.ledW.setMaxLength(2) # maximum of 2 digits self.ledW.setFixedWidth(30) # width of lineedit in points(?) self.ledWI = QLineEdit(self) self.ledWI.setToolTip("Specify number of integer bits.") self.ledWI.setText("0") self.ledWI.setMaxLength(2) # maximum of 2 digits self.ledWI.setFixedWidth(30) # width of lineedit in points(?) self.lblDot = QLabel(self) self.lblDot.setText(".") self.ledWF = QLineEdit(self) self.ledWF.setToolTip("Specify number of fractional bits.") self.ledWF.setText("15") self.ledWF.setMaxLength(2) # maximum of 2 digits # self.ledWF.setFixedWidth(30) # width of lineedit in points(?) self.ledWF.setMaximumWidth(30) self.lblScale = QLabel("Scale = ", self) self.ledScale = QLineEdit(self) self.ledScale.setToolTip( "Set the scale for converting float to fixpoint representation.") self.ledScale.setText(str(1)) self.lblLSBtxt = QLabel(self) self.lblLSBtxt.setText("LSB =") self.lblLSBtxt.setFont(self.bifont) self.lblLSB = QLabel(self) self.lblMSBtxt = QLabel(self) self.lblMSBtxt.setText("MSB =") self.lblMSBtxt.setFont(self.bifont) self.lblMSB = QLabel(self) self.cmbQQuant = QComboBox(self) qQuant = ['none', 'round', 'fix', 'floor'] self.cmbQQuant.addItems(qQuant) self.cmbQQuant.setCurrentIndex(1) # 'round' self.cmbQQuant.setToolTip("Select the kind of quantization.") self.cmbQOvfl = QComboBox(self) qOvfl = ['none', 'wrap', 'sat'] self.cmbQOvfl.addItems(qOvfl) self.cmbQOvfl.setCurrentIndex(2) # 'sat' self.cmbQOvfl.setToolTip("Select overflow behaviour.") # ComboBox size is adjusted automatically to fit the longest element self.cmbQQuant.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.cmbQOvfl.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.clipboard = QApplication.clipboard() # ============== UI Layout ===================================== layHButtonsCoeffs2 = QHBoxLayout() layHButtonsCoeffs2.addWidget(butSetZero) layHButtonsCoeffs2.addWidget(self.lblEps) layHButtonsCoeffs2.addWidget(self.ledSetEps) layHButtonsCoeffs2.addStretch() layHCoeffs_W = QHBoxLayout() layHCoeffs_W.addWidget(self.lblWIWF) layHCoeffs_W.addWidget(self.ledW) layHCoeffs_W.addWidget(self.ledWI) layHCoeffs_W.addWidget(self.lblDot) layHCoeffs_W.addWidget(self.ledWF) layHCoeffs_W.addWidget(self.lblScale) layHCoeffs_W.addWidget(self.ledScale) layHCoeffs_W.addStretch() layHCoeffsQOpt = QHBoxLayout() layHCoeffsQOpt.addWidget(self.lblQOvfl) layHCoeffsQOpt.addWidget(self.cmbQOvfl) layHCoeffsQOpt.addWidget(self.lblQuant) layHCoeffsQOpt.addWidget(self.cmbQQuant) layHCoeffsQOpt.addStretch() layHCoeffs_MSB_LSB = QHBoxLayout() layHCoeffs_MSB_LSB.addWidget(self.lblMSBtxt) layHCoeffs_MSB_LSB.addWidget(self.lblMSB) layHCoeffs_MSB_LSB.addStretch() layHCoeffs_MSB_LSB.addWidget(self.lblLSBtxt) layHCoeffs_MSB_LSB.addWidget(self.lblLSB) layHCoeffs_MSB_LSB.addStretch() layVButtonsQ = QVBoxLayout() layVButtonsQ.addLayout(layHCoeffs_W) layVButtonsQ.addLayout(layHCoeffsQOpt) layVButtonsQ.addLayout(layHCoeffs_MSB_LSB) layVButtonsQ.setContentsMargins(0, 5, 0, 0) # This frame encompasses the Quantization Settings self.frmQSettings = QFrame(self) self.frmQSettings.setLayout(layVButtonsQ) layVBtns = QVBoxLayout() layVBtns.addLayout(layHDisplay) layVBtns.addLayout(layHButtonsCoeffs1) layVBtns.addLayout(layHButtonsCoeffs2) layVBtns.addWidget(self.frmQSettings) # This frame encompasses all the buttons frmMain = QFrame(self) frmMain.setLayout(layVBtns) layVMain = QVBoxLayout() layVMain.setAlignment( Qt.AlignTop) # this affects only the first widget (intended here) layVMain.addWidget(frmMain) layVMain.addWidget(self.tblCoeff) layVMain.setContentsMargins(*params['wdg_margins']) # layVMain.addStretch(1) self.setLayout(layVMain) # ============== Signals & Slots ================================ # self.tblCoeff.itemActivated.connect(self.save_coeffs) # nothing happens # this works but fires multiple times _and_ fires every time cell is # changed by program as well! # self.tblCoeff.itemChanged.connect(self.save_coeffs) # self.tblCoeff.selectionModel().currentChanged.connect(self.save_coeffs) self.butEnable.clicked.connect(self._refresh_table) self.spnRound.editingFinished.connect(self._refresh_table) self.chkRadixPoint.clicked.connect(self._radix_point) self.butClipboard.clicked.connect(self._copy_to_clipboard) self.cmbFilterType.currentIndexChanged.connect(self._filter_type) butDelCells.clicked.connect(self._delete_cells) butAddCells.clicked.connect(self._add_cells) butLoad.clicked.connect(self.load_dict) self.butSave.clicked.connect(self._save_entries) butClear.clicked.connect(self._clear_table) butSetZero.clicked.connect(self._set_coeffs_zero) # refresh table after storing new settings self.cmbFormat.currentIndexChanged.connect(self._refresh_table) self.cmbQOvfl.currentIndexChanged.connect(self._refresh_table) self.cmbQQuant.currentIndexChanged.connect(self._refresh_table) self.ledWF.editingFinished.connect(self._WIWF_changed) self.ledWI.editingFinished.connect(self._WIWF_changed) self.ledW.editingFinished.connect(self._W_changed) self.ledScale.editingFinished.connect(self._refresh_table) butQuant.clicked.connect(self.quant_coeffs) self.myQ = fix.Fixed( fb.fil[0]["q_coeff"]) # initialize fixpoint object self.load_dict( ) # initialize + refresh table with default values from filter dict # TODO: this needs to be optimized - self._refresh is being called in both routines self._radix_point()