def init(self, p, zi: iterable = None) -> None: """ Initialize filter with parameter dict `p` by initialising all registers and quantizers. This needs to be done every time quantizers or coefficients are updated. Parameters ---------- p : dict dictionary with coefficients and quantizer settings (see docstring of `__init__()` for details) zi : array-like Initialize `L = len(b)` filter registers. Strictly speaking, `zi[0]` is not a register but the current input value. When `len(zi) != len(b)`, truncate or fill up with zeros. When `zi == None`, all registers are filled with zeros. Returns ------- None. """ # logger.error(p) self.p = p # parameter dictionary with coefficients etc. if 'q_mul' not in self.p or self.p['q_mul'] is None: q_mul = {'Q': '0.15', 'ovfl': 'none', 'quant': 'none'} else: q_mul = p['q_mul'] self.b = self.p['b'] # coefficients self.L = len(self.b) # filter length = number of taps # create various quantizers self.Q_mul = fx.Fixed(q_mul) # partial products self.Q_acc = fx.Fixed(self.p['QA']) # accumulator self.Q_O = fx.Fixed(self.p['QO']) # output self.N_over_filt = 0 # initialize overflow counter TODO: not used yet? # Initialize vectors (also speeds up calculation for large arrays) self.xbq = np.zeros(len(self.b)) # partial products if zi is None: self.zi = np.zeros(self.L - 1) else: # initialize filter memory and fill up with zeros if len(zi) == self.L - 1: self.zi = zi elif len(zi) < self.L - 1: self.zi = np.concatenate((zi, np.zeros(self.L - 1 - len(zi)))) else: self.zi = zi[:self.L - 1]
def setUp(self): self.q_in = { 'WI': 0, 'WF': 15, 'W': 16, 'ovfl': 'wrap', 'quant': 'round' } self.q_out = { 'WI': 0, 'WF': 15, 'W': 16, 'ovfl': 'wrap', 'quant': 'round' } if HAS_MIGEN: self.dut = DUT(self.q_in, self.q_out) self.stim = np.array([0, 1, 15, 64, 32767, -1, -64, 0]) # last zero isn't tested due to latency of 1 # initialize a pyfda fixpoint quantizer q_obj = { 'WI': 0, 'WF': 3, 'ovfl': 'sat', 'quant': 'round', 'frmt': 'dec', 'scale': 1 } self.myQ = fx.Fixed( q_obj) # instantiate fixpoint object with settings above
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 = fx.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 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['b']] # convert np.int64 to python int a = [int(x) for x in self.hdl_dict['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 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 quant_coeffs(self, q_dict: dict, coeffs: iterable, to_int: bool = False) -> list: """ 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: ----------- q_dict: dict Dictionary with quantizer settings for coefficients coeffs: iterable a list or ndarray of coefficients to be quantized Returns: -------- A list of integer coeffcients, quantized and scaled with the settings of the passed quantization dict """ # Create coefficient quantizer instance using the passed quantization parameters # dict from `input_widgets/input_coeffs.py` (and stored in the central # filter dict) Q_coeff = fx.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 with the selected scale (WI.WF), # next convert array float -> array of fixp # -> list of int (scaled by 2^WF) when `to_int == True` if to_int: return list(Q_coeff.float2frmt(coeffs) * (1 << Q_coeff.WF)) else: return list(Q_coeff.fixp(coeffs))
def _construct_UI(self): """ Intitialize the widget, consisting of: - top chkbox row - coefficient table - two bottom rows with action buttons """ # --------------------------------------------------------------------- # 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 = fx.Fixed(fb.fil[0]['fxqc']['QCB']) # 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() #---------------------------------------------------------------------- # GLOBAL SIGNALS & SLOTs #---------------------------------------------------------------------- self.sig_rx.connect(self.process_sig_rx) #---------------------------------------------------------------------- # LOCAL (UI) 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) # store new settings and refresh table self.ui.cmbFormat.currentIndexChanged.connect(self.ui2qdict) self.ui.cmbQOvfl.currentIndexChanged.connect(self.ui2qdict) self.ui.cmbQuant.currentIndexChanged.connect(self.ui2qdict) self.ui.ledWF.editingFinished.connect(self.ui2qdict) self.ui.ledWI.editingFinished.connect(self.ui2qdict) self.ui.ledW.editingFinished.connect(self._W_changed) self.ui.ledScale.editingFinished.connect(self._set_scale) self.ui.butQuant.clicked.connect(self.quant_coeffs) self.ui.sig_tx.connect(self.sig_tx)