def _log_clicked(self): """ Change scale and settings to log / lin when log setting is changed Update min / max settings when lineEdits have been edited """ self.log = self.chkLog.isChecked() if self.sender().objectName() == 'chkLog': # clicking chkLog triggered the slot if self.log: self.ledBottom.setText(str(self.zmin_dB)) self.zmax_dB = np.round(20 * log10(self.zmax), 2) self.ledTop.setText(str(self.zmax_dB)) self.lblTopdB.setVisible(True) self.lblBottomdB.setVisible(True) else: self.ledBottom.setText(str(self.zmin)) self.zmax = np.round(10**(self.zmax_dB / 20), 2) self.ledTop.setText(str(self.zmax)) self.lblTopdB.setVisible(False) self.lblBottomdB.setVisible(False) else: # finishing a lineEdit field triggered the slot if self.log: self.zmin_dB = safe_eval(self.ledBottom.text(), self.zmin_dB, return_type='float') self.ledBottom.setText(str(self.zmin_dB)) self.zmax_dB = safe_eval(self.ledTop.text(), self.zmax_dB, return_type='float') self.ledTop.setText(str(self.zmax_dB)) else: self.zmin = safe_eval(self.ledBottom.text(), self.zmin, return_type='float') self.ledBottom.setText(str(self.zmin)) self.zmax = safe_eval(self.ledTop.text(), self.zmax, return_type='float') self.ledTop.setText(str(self.zmax)) self.draw()
def _update_UI(self): """ Update UI when line edit field is changed (here, only the text is read and converted to integer) and resize the textfields according to content. """ self.delays = safe_eval(self.led_delays.text(), self.delays, return_type='int', sign='pos') self.led_delays.setText(str(self.delays)) self.stages = safe_eval(self.led_stages.text(), self.stages, return_type='int', sign='pos') self.led_stages.setText(str(self.stages)) self._store_entries()
def _update_UI(self): """ Update UI and info_doc when one of the comboboxes or line edits is changed. """ self.fir_window_name = str(self.cmb_firwin_win.currentText()).lower() self.alg = str(self.cmb_firwin_alg.currentText()) mod_ = import_module('scipy.signal') # mod = __import__('scipy.signal') # works, but not with the next line # construct window class, e.g. scipy.signal.boxcar : class_ = getattr(mod_, self.fir_window_name) win_doc = getattr(class_, '__doc__') # read docstring attribute from class self.info_doc = [] self.info_doc.append('firwin()\n========') self.info_doc.append(sig.firwin.__doc__) self.info_doc.append(self.fir_window_name + '()' +'\n' + '=' * (len(self.fir_window_name) + 2)) self.info_doc.append(win_doc) self.winArgs = inspect.getargspec(class_)[0] # return args of window # and remove common args for all window types ('sym' and 'M'): self.winArgs = [arg for arg in self.winArgs if arg not in {'sym', 'M'}] # make edit boxes and labels for additional parameters visible if needed # and construct self.firWindow as a tuple consisting of a string with # the window name and optionally one or two float parameters. # If there are no additional parameters, just pass the window name string. N_args = len(self.winArgs) self.lbl_firwin_1.setVisible(N_args > 0) self.led_firwin_1.setVisible(N_args > 0) self.lbl_firwin_2.setVisible(N_args > 1) self.led_firwin_2.setVisible(N_args > 1) if N_args > 1 : self.lbl_firwin_2.setText(self.winArgs[1] + ":") self.firWindow = (self.fir_window_name, safe_eval(self.led_firwin_1.text(), return_type='float'), safe_eval(self.led_firwin_2.text(), return_type='float')) elif N_args > 0 : self.lbl_firwin_1.setText(self.winArgs[0] + ":") self.firWindow = (self.fir_window_name, safe_eval(self.led_firwin_1.text(), return_type='float')) else: self.firWindow = self.fir_window_name # sig_tx -> select_filter -> filter_specs self.sig_tx.emit({'sender':__name__, 'filt_changed':'firwin'})
def _store_q_settings(self): """ Read out the settings of the quantization comboboxes and store them in the filter dict. Update the fixpoint object. """ fb.fil[0]['q_coeff'] = { 'WI':safe_eval(self.ui.ledWI.text(), self.myQ.WI, return_type='int'), 'WF':safe_eval(self.ui.ledWF.text(), self.myQ.WF, return_type='int', sign='pos'), 'quant':qstr(self.ui.cmbQuant.currentText()), 'ovfl':qstr(self.ui.cmbQOvfl.currentText()), 'frmt':qstr(self.ui.cmbFormat.currentText()), 'scale':qstr(self.ui.ledScale.text()) } self._load_q_settings() # update widgets and the fixpoint object self.myQ
def _store_entry(source): if self.spec_edited: if source.objectName() == "stimFreq1": self.f1 = safe_eval(source.text(), self.f1 * fb.fil[0]['f_S'], return_type='float') / fb.fil[0]['f_S'] source.setText(str(params['FMT'].format(self.f1 * fb.fil[0]['f_S']))) elif source.objectName() == "stimFreq2": self.f2 = safe_eval(source.text(), self.f2 * fb.fil[0]['f_S'], return_type='float') / fb.fil[0]['f_S'] source.setText(str(params['FMT'].format(self.f2 * fb.fil[0]['f_S']))) self.spec_edited = False # reset flag self.draw()
def update_N(self, dict_sig=None): """ Update values for self.N and self.N_start from the QLineEditWidget """ self.N_start = safe_eval(self.led_N_start.text(), 0, return_type='int', sign='pos') self.led_N_start.setText(str(self.N_start)) N_user = safe_eval(self.led_N_points.text(), 0, return_type='int', sign='pos') if N_user == 0: # automatic calculation self.N = self.calc_n_points(N_user) # widget remains set to 0 else: self.N = N_user self.led_N_points.setText(str(self.N)) # update widget self.N_end = self.N + self.N_start # total number of points to be calculated: N + N_start self._update_win_fft(dict_sig)
def _set_filter_order(self, enb_signal=False): """ Triggered when either ledOrderN or chkMinOrder are edited: - copy settings to fb.fil[0] - emit sigFiltChanged if enb_signal is True """ # Determine which subwidgets are _enabled_ if self.chkMinOrder.isVisible(): self.ledOrderN.setEnabled(not self.chkMinOrder.isChecked()) self.lblOrderN.setEnabled(not self.chkMinOrder.isChecked()) if self.chkMinOrder.isChecked() == True: # update in case N has been changed outside this class self.ledOrderN.setText(str(fb.fil[0]['N'])) fb.fil[0].update({'fo' : 'min'}) else: fb.fil[0].update({'fo' : 'man'}) else: self.lblOrderN.setEnabled(self.fo == 'man') self.ledOrderN.setEnabled(self.fo == 'man') # read manual filter order, convert to positive integer and store it # in filter dictionary. ordn = safe_eval(self.ledOrderN.text(), fb.fil[0]['N'], return_type='int', sign='pos') ordn = ordn if ordn > 0 else 1 self.ledOrderN.setText(str(ordn)) fb.fil[0].update({'N' : ordn}) if enb_signal: logger.debug("Emit sigFiltChanged") self.sigFiltChanged.emit() # -> filter_specs
def _W_changed(self): """ Set fractional and integer length `WF` and `WI` when wordlength Ẁ` has been changed. Try to preserve `WI` or `WF` settings depending on the number format (integer or fractional). """ # if self.ui.ledW.isModified() ... self.ui.ledW.setModified(False) W = safe_eval(self.ui.ledW.text(), self.myQ.W, return_type='int', sign='pos') if W < 2: logger.warn("W must be > 1, restoring previous value.") W = self.myQ.W # fall back to previous value self.ui.ledW.setText(str(W)) if qget_cmb_box(self.ui.cmbQFrmt) == 'qint': # integer format, preserve WI bits WI = W - self.myQ.WF - 1 self.ui.ledWI.setText(str(WI)) self.ui.ledScale.setText(str(1 << (W-1))) else: # fractional format, preserve WF bit setting WF = W - self.myQ.WI - 1 if WF < 0: self.ui.ledWI.setText(str(W - 1)) WF = 0 self.ui.ledWF.setText(str(WF)) self._store_q_settings() self._refresh_table()
def _set_eps(self): """ Set all coefficients = 0 in self.ba with a magnitude less than eps and refresh QTableWidget """ self.ui.eps = safe_eval(self.ui.ledEps.text(), return_type='float', sign='pos', alt_expr=self.ui.eps) self.ui.ledEps.setText(str(self.ui.eps))
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 _set_number_format(self): """ Set one of three number formats: Integer, fractional, normalized fractional """ qfrmt = qget_cmb_box(self.ui.cmbQFrmt) is_qfrac = False W = safe_eval(self.ui.ledW.text(), self.myQ.W, return_type='int', sign='pos') if qfrmt == 'qint': self.ui.ledWI.setText(str(W - 1)) self.ui.ledWF.setText("0") self.ui.ledScale.setText(str(1 << (W-1))) elif qfrmt == 'qnfrac': # normalized fractional format self.ui.ledWI.setText("0") self.ui.ledWF.setText(str(W - 1)) self.ui.ledScale.setText("1") else: # qfrmt == 'qfrac': is_qfrac = True self.ui.ledWI.setEnabled(is_qfrac) self.ui.lblDot.setEnabled(is_qfrac) self.ui.ledWF.setEnabled(is_qfrac) self.ui.ledW.setEnabled(not is_qfrac) self.ui.ledScale.setEnabled(is_qfrac) self._store_q_settings() self._refresh_table()
def _store_q_settings(self): """ Read out the settings of the quantization comboboxes and store them in the filter dict. Update the fixpoint object and refresh table """ fb.fil[0]['q_coeff'] = { 'WI':safe_eval(self.ui.ledWI.text(), self.myQ.WI, return_type='int'), 'WF':safe_eval(self.ui.ledWF.text(), self.myQ.WF, return_type='int', sign='pos'), 'quant':qstr(self.ui.cmbQuant.currentText()), 'ovfl':qstr(self.ui.cmbQOvfl.currentText()), 'frmt':qstr(self.ui.cmbFormat.currentText()), 'scale':qstr(self.ui.ledScale.text()) } self.sig_tx.emit({'sender':__name__, 'view_changed':'q_coeff'}) self._load_q_settings() # update widgets and the fixpoint object self.myQ 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])) self.spec_edited = False # reset flag
def _set_scale(self): """ Set scale for calculating floating point value from fixpoint representation and vice versa """ # if self.ui.ledScale.isModified() ... self.ui.ledScale.setModified(False) scale = safe_eval(self.ui.ledScale.text(), self.myQ.scale, return_type='float', sign='pos') self.ui.ledScale.setText(str(scale)) self._store_q_settings()
def _store_entry(): """ Update filter dictionary, set line edit entry with reduced precision again. """ if self.spec_edited: fb.fil[0].update({'f_S':safe_eval(source.text(), fb.fil[0]['f_S'])}) self._freq_range(emit_sig_range = False) # update plotting range self.sigSpecsChanged.emit() # -> input_widgets self.spec_edited = False # reset flag, changed entry has been saved
def _store_entry(): """ Update filter dictionary, set line edit entry with reduced precision again. """ if self.spec_edited: fb.fil[0].update({'f_S':safe_eval(source.text(), fb.fil[0]['f_S'])}) # TODO: ?! self._freq_range(emit_sig_range = False) # update plotting range self.sig_tx.emit({'sender':__name__, 'view_changed':'f_S'}) self.spec_edited = False # reset flag, changed entry has been saved
def _store_entry(self, widget): """ When the textfield of `widget` has been edited (`self.spec_edited` = True), store the weight spec in filter dict. This is triggered by `QEvent.focusOut` """ if self.spec_edited: w_label = str(widget.objectName()) w_value = safe_eval(widget.text(), fb.data_old) fb.fil[0].update({w_label:w_value}) self.sigSpecsChanged.emit() # -> filter_specs self.spec_edited = False # reset flag self.load_dict()
def frmt2cmplx(self, text, default=0.): """ Convert format defined by cmbPZFrmt to real or complex """ conv_error = False text = qstr(text).replace(" ", "") # convert to "proper" string without blanks if qget_cmb_box(self.ui.cmbPZFrmt) == 'cartesian': return safe_eval(text, default, return_type='auto') else: polar_str = text.split('*' + self.angle_char, 1) if len(polar_str) < 2: # input is real or imaginary r = safe_eval(re.sub('['+self.angle_char+'<∠°]','', text), default, return_type='auto') x = r.real y = r.imag else: r = safe_eval(polar_str[0], sign='pos') if safe_eval.err > 0: conv_error = True if "°" in polar_str[1]: scale = np.pi / 180. # angle in degrees elif re.search('π$|pi$', polar_str[1]): scale = np.pi else: scale = 1. # angle in rad # remove right-most special characters (regex $) polar_str[1] = re.sub('['+self.angle_char+'<∠°π]$|rad$|pi$', '', polar_str[1]) phi = safe_eval(polar_str[1]) * scale if safe_eval.err > 0: conv_error = True if not conv_error: x = r * np.cos(phi) y = r * np.sin(phi) else: x = default.real y = default.imag logger.error("Expression {0} could not be evaluated.".format(text)) return x + 1j * y
def cmplx2frmt(self, text, places=-1): """ Convert number "text" (real or complex or string) to the format defined by cmbPZFrmt. Returns: string """ # convert to "normal" string and prettify via safe_eval: data = safe_eval(qstr(text), return_type='auto') frmt = qget_cmb_box(self.ui.cmbPZFrmt) # get selected format if places == -1: full_prec = True else: full_prec = False if frmt == 'cartesian' or not (type(data) == complex): if full_prec: return "{0}".format(data) else: return "{0:.{plcs}g}".format(data, plcs=places) elif frmt == 'polar_rad': r, phi = np.absolute(data), np.angle(data, deg=False) if full_prec: return "{r} * {angle_char}{p} rad"\ .format(r=r, p=phi, angle_char=self.angle_char) else: return "{r:.{plcs}g} * {angle_char}{p:.{plcs}g} rad"\ .format(r=r, p=phi, plcs=places, angle_char=self.angle_char) elif frmt == 'polar_deg': r, phi = np.absolute(data), np.angle(data, deg=True) if full_prec: return "{r} * {angle_char}{p}°"\ .format(r=r, p=phi, angle_char=self.angle_char) else: return "{r:.{plcs}g} * {angle_char}{p:.{plcs}g}°"\ .format(r=r, p=phi, plcs=places, angle_char=self.angle_char) elif frmt == 'polar_pi': r, phi = np.absolute(data), np.angle(data, deg=False) / np.pi if full_prec: return "{r} * {angle_char}{p} pi"\ .format(r=r, p=phi, angle_char=self.angle_char) else: return "{r:.{plcs}g} * {angle_char}{p:.{plcs}g} pi"\ .format(r=r, p=phi, plcs=places, angle_char=self.angle_char) else: logger.error("Unknown format {0}.".format(frmt))
def _store_entry(self, event_source): """ _store_entry is triggered by `QEvent.focusOut` in the eventFilter: When the textfield of `widget` has been edited (`self.spec_edited` = True), sort and store all entries in filter dict, then reload the text fields. Finally, emit a SpecsChanged signal. """ if self.spec_edited: f_label = str(event_source.objectName()) f_value = safe_eval(event_source.text(), fb.data_old) / fb.fil[0]['f_S'] fb.fil[0].update({f_label:f_value}) self.sort_dict_freqs() self.sigSpecsChanged.emit() # -> filter_specs self.spec_edited = False # reset flag
def _log_mode_time(self): """ Select / deselect log. mode for time domain and update self.bottom_t """ log = self.ui.chk_log_time.isChecked() self.ui.lbl_log_bottom_time.setVisible(log) self.ui.led_log_bottom_time.setVisible(log) self.ui.lbl_dB_time.setVisible(log) if log: self.bottom_t = safe_eval(self.ui.led_log_bottom_time.text(), self.bottom_t, return_type='float', sign='neg') self.ui.led_log_bottom_time.setText(str(self.bottom_t)) else: self.bottom_t = 0 self.draw_impz()
def _store_entry(self, widget): """ When the textfield of `widget` has been edited (`self.spec_edited` = True), store the weight spec in filter dict. This is triggered by `QEvent.focusOut` """ if self.spec_edited: w_label = str(widget.objectName()) w_value = safe_eval(widget.text(), fb.data_old, sign='pos') if w_value < 1: w_value = 1 if w_value > 1.e6: w_value = 1.e6 fb.fil[0].update({w_label:w_value}) self.sig_tx.emit({'sender':__name__, 'specs_changed':'w_specs'}) self.spec_edited = False # reset flag self.load_dict()
def _log_mode_freq(self): """ Select / deselect log. mode for frequency domain and update self.bottom_f """ log = self.ui.chk_log_freq.isChecked() self.ui.lbl_log_bottom_freq.setVisible(log) self.ui.led_log_bottom_freq.setVisible(log) self.ui.lbl_dB_freq.setVisible(log) if log: self.bottom_f = safe_eval(self.ui.led_log_bottom_freq.text(), self.bottom_f, return_type='float', sign='neg') self.ui.led_log_bottom_freq.setText(str(self.bottom_f)) else: self.bottom_f = 0 self.draw_impz()
def _update_UI(self): """ Update UI when line edit field is changed (here, only the text is read and converted to integer) and store parameter settings in filter dictionary """ self.grid_density = safe_eval(self.led_remez_1.text(), self.grid_density, return_type='int', sign='pos' ) self.led_remez_1.setText(str(self.grid_density)) if not 'wdg_fil' in fb.fil[0]: fb.fil[0].update({'wdg_fil':{}}) fb.fil[0]['wdg_fil'].update({'equiripple': {'grid_density':self.grid_density} }) self.sigFiltChanged.emit() # -> select_filter -> filter_specs
def displayText(self, text, locale): """ Display `text` with selected fixpoint base and number of places text: string / QVariant from QTableWidget to be rendered locale: locale for the text The instance parameter myQ.ovr_flag is set to +1 or -1 for positive / negative overflows, else it is 0. """ data_str = qstr(text) # convert to "normal" string if self.parent.myQ.frmt == 'float': data = safe_eval(data_str, return_type='auto') # convert to float return "{0:.{1}g}".format(data, params['FMT_ba']) else: return "{0:>{1}}".format(self.parent.myQ.float2frmt(data_str), self.parent.myQ.places)
def _store_entry(self, source): """ When the textfield of `source` has been edited (flag `self.spec_edited` = True), transform the amplitude spec back to linear unit setting and store it in filter dict. This is triggered by `QEvent.focusOut` Spec entries are *always* stored in linear units; only the displayed values are adapted to the amplitude unit, not the dictionary! """ if self.spec_edited: unit = str(self.cmbUnitsA.currentText()) filt_type = fb.fil[0]['ft'] amp_label = str(source.objectName()) amp_value = safe_eval(source.text(), fb.data_old) fb.fil[0].update({amp_label:unit2lin(amp_value, filt_type, amp_label, unit)}) self.sigSpecsChanged.emit() # -> filter_specs self.spec_edited = False # reset flag self.load_dict()
def _copy_item(self): """ Copy the value from the current table item to self.zpk and normalize / update the gain. This is triggered every time a table item is edited. When no item was selected, only the gain is updated. Triggered by `tblPZ.cellChanged` and `cmbNorm.activated` """ col = self.tblPZ.currentIndex().column() row = self.tblPZ.currentIndex().row() item = self.tblPZ.item(row, col) if item: if item.text() != "": self.zpk[col][row] = safe_eval(item.text()) else: self.zpk[col][row] = 0. self._normalize_gain()
def _update_noi(self): """ Update type + value + label for self.noi for noise""" self.noise = qget_cmb_box(self.cmbNoise, data=False).lower() self.lblNoi.setVisible(self.noise!='none') self.ledNoi.setVisible(self.noise!='none') if self.noise!='none': self.noi = safe_eval(self.ledNoi.text(), 0, return_type='float', sign='pos') self.ledNoi.setText(str(self.noi)) if self.noise == 'gauss': self.lblNoi.setText(to_html("σ =", frmt='bi')) self.ledNoi.setToolTip("<span>Standard deviation of statistical process," "noise power is <i>P</i> = σ<sup>2</sup></span>") elif self.noise == 'uniform': self.lblNoi.setText(to_html("Δ =", frmt='bi')) self.ledNoi.setToolTip("<span>Interval size for uniformly distributed process " "(e.g. quantization step size for quantization noise), " "centered around 0. Noise power is " "<i>P</i> = Δ<sup>2</sup>/12.</span>") self.sig_tx.emit({'sender':__name__, 'data_changed':'noi'})
def _update_UI(self): """ Update UI when line edit field is changed (here, only the text is read and converted to integer) and store parameter settings in filter dictionary """ self.grid_density = safe_eval(self.led_remez_1.text(), self.grid_density, return_type='int', sign='pos') self.led_remez_1.setText(str(self.grid_density)) if not 'wdg_fil' in fb.fil[0]: fb.fil[0].update({'wdg_fil': {}}) fb.fil[0]['wdg_fil'].update( {'equiripple': { 'grid_density': self.grid_density }}) self.sigFiltChanged.emit() # -> select_filter -> filter_specs
def _store_q_settings(self): """ read out the settings of the quantization comboboxes and store them in filter dict. Update the fixpoint object. """ fb.fil[0]['q_coeff'] = { 'WI': abs(int(self.ledWI.text())), 'WF': abs(int(self.ledWF.text())), 'quant': self.cmbQQuant.currentText(), 'ovfl': self.cmbQOvfl.currentText(), 'frmt': self.cmbFormat.currentText(), 'point': self.chkRadixPoint.isChecked() } self.myQ.setQobj(fb.fil[0]['q_coeff']) self.lblLSB.setText("{0:.{1}g}".format(self.myQ.LSB, params['FMT_ba'])) self.lblMSB.setText("{0:.{1}g}".format(self.myQ.MSB, params['FMT_ba'])) self.scale = safe_eval(self.ledScale.text(), self.myQ.scale) self.ledScale.setText(str(self.scale))
def setEditorData(self, editor, index): """ Pass the data to be edited to the editor: - retrieve data with full accuracy from self.ba (in float format) - requantize data according to settings in fixpoint object - represent it in the selected format (int, hex, ...) editor: instance of e.g. QLineEdit index: instance of QModelIndex """ # data = qstr(index.data()) # get data from QTableWidget data_str = qstr(safe_eval(self.parent.ba[index.column()][index.row()], return_type="auto")) if self.parent.myQ.frmt == 'float': # floating point format: pass data with full resolution editor.setText(data_str) else: # fixpoint format with base: pass requantized data with required number of places editor.setText("{0:>{1}}".format(self.parent.myQ.float2frmt(data_str), self.parent.myQ.places))
def _load_q_settings(self): """ load the quantization settings from the filter dict and set the widgets accordingly. Update the fixpoint object. """ q_coeff = fb.fil[0]['q_coeff'] self.ledWI.setText(str(q_coeff['WI'])) self.ledWF.setText(str(q_coeff['WF'])) qset_cmb_box(self.cmbQQuant, q_coeff['quant']) qset_cmb_box(self.cmbQOvfl, q_coeff['ovfl']) qset_cmb_box(self.cmbFormat, q_coeff['frmt']) self.chkRadixPoint.setChecked(q_coeff['point']) self.lblLSB.setText("{0:.{1}g}".format(self.myQ.LSB, params['FMT_ba'])) self.lblMSB.setText("{0:.{1}g}".format(self.myQ.MSB, params['FMT_ba'])) self.scale = safe_eval(self.ledScale.text(), self.myQ.scale) self.ledScale.setText(str(self.scale)) self.myQ.setQobj(fb.fil[0]['q_coeff'])
def _restore_gain(self, source = None): """ Update QLineEdit with either full (has focus) or reduced precision (no focus) Called by eventFilter, _normalize_gain() and _refresh_table() """ if self.ui.butEnable.isChecked(): if len(self.zpk) == 3: pass elif len(self.zpk) == 2: # k is missing in zpk: self.zpk.append(1.) # use k = 1 else: logger.error("P/Z list zpk has wrong length {0}".format(len(self.zpk))) k = safe_eval(self.zpk[2], return_type='auto') if not self.ui.ledGain.hasFocus(): # no focus, round the gain self.ui.ledGain.setText(str(params['FMT'].format(k))) else: # widget has focus, show gain with full precision self.ui.ledGain.setText(str(k))
def _set_filter_order(self, enb_signal=False): """ Triggered when either ledOrderN or chkMinOrder are edited: - copy settings to fb.fil[0] - emit 'filt_changed' if enb_signal is True """ # Determine which subwidgets are _enabled_ if self.chkMinOrder.isVisible(): self.ledOrderN.setEnabled(not self.chkMinOrder.isChecked()) self.lblOrderN.setEnabled(not self.chkMinOrder.isChecked()) if self.chkMinOrder.isChecked() == True: # update in case N has been changed outside this class self.ledOrderN.setText(str(fb.fil[0]['N'])) fb.fil[0].update({'fo': 'min'}) else: fb.fil[0].update({'fo': 'man'}) else: self.lblOrderN.setEnabled(self.fo == 'man') self.ledOrderN.setEnabled(self.fo == 'man') # read manual filter order, convert to positive integer and store it # in filter dictionary. ordn = safe_eval(self.ledOrderN.text(), fb.fil[0]['N'], return_type='int', sign='pos') ordn = ordn if ordn > 0 else 1 self.ledOrderN.setText(str(ordn)) fb.fil[0].update({'N': ordn}) if enb_signal: logger.debug("Emit 'filt_changed'") self.sig_tx.emit({ 'sender': __name__, 'filt_changed': 'filter_order_widget' })
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 displayText(self, text, locale): """ Display `text` with selected fixpoint base and number of places text: string / QVariant from QTableWidget to be rendered locale: locale for the text The instance parameter myQ.ovr_flag is set to +1 or -1 for positive / negative overflows, else it is 0. """ data_str = qstr(text) # convert to "normal" string if self.parent.myQ.frmt == 'float': data = safe_eval(data_str, return_type='auto') # convert to float return "{0:.{1}g}".format(data, params['FMT_ba']) elif self.parent.myQ.frmt == 'dec' and self.parent.myQ.WF > 0: # decimal fixpoint representation with fractional part return "{0:.{1}g}".format(self.parent.myQ.float2frmt(data_str), params['FMT_ba']) else: return "{0:>{1}}".format(self.parent.myQ.float2frmt(data_str), self.parent.myQ.places)
def _update_amp1(self): """ Update value for self.A1 from QLineEditWidget""" self.A1 = safe_eval(self.ledAmp1.text(), self.A1, return_type='float') self.ledAmp1.setText(str(self.A1)) self.sig_tx.emit({'sender': __name__, 'data_changed': 'a1'})
def _update_amp2(self): """ Update value for self.A2 from the QLineEditWidget""" self.A2 = safe_eval(self.ledAmp2.text(), self.A2, return_type='float') self.ledAmp2.setText(str(self.A2)) self.sig_tx.emit({'sender': __name__, 'data_changed': 'a2'})
def displayText(self, text, locale): return "{:.{n_digits}g}".format(safe_eval(qstr(text), return_type='cmplx'), n_digits=params['FMT_pz'])
def _update_DC(self): """ Update value for self.DC from the QLineEditWidget""" self.DC = safe_eval(self.ledDC.text(), 0, return_type='float') self.ledDC.setText(str(self.DC)) self.sig_tx.emit({'sender': __name__, 'data_changed': 'dc'})
def _store_entry(source): if self.spec_edited: self.stim_freq = safe_eval(source.text()) / fb.fil[0]['f_S'] self.spec_edited = False # reset flag self.draw()
def draw_impz(self): """ (Re-)calculate h[n] and draw the figure """ log = self.chkLog.isChecked() stim = str(self.cmbStimulus.currentText()) periodic_sig = stim in {"Cos", "Sine", "Rect", "Saw"} self.lblLogBottom.setVisible(log) self.ledLogBottom.setVisible(log) self.lbldB.setVisible(log) self.lblFreq.setVisible(periodic_sig) self.ledFreq.setVisible(periodic_sig) self.lblFreqUnit.setVisible(periodic_sig) self.lblFreqUnit.setText(rt_label(fb.fil[0]['freq_specs_unit'])) self.load_dict() 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 sos = np.asarray(fb.fil[0]['sos']) antiCausal = 'zpkA' in fb.fil[0] causal = not (antiCausal) self.f_S = fb.fil[0]['f_S'] N_entry = safe_eval(self.ledNPoints.text(), 0, return_type='int', sign='pos') N = self.calc_n_points(N_entry) if N_entry != 0: # automatic calculation self.ledNPoints.setText(str(N)) self.A = safe_eval(self.ledAmp.text(), self.A, return_type='float') self.ledAmp.setText(str(self.A)) t = np.linspace(0, N / self.f_S, N, endpoint=False) title_str = r'Impulse Response' # default H_str = r'$h[n]$' # default # calculate h[n] if stim == "Pulse": x = np.zeros(N) x[0] = self.A # create dirac impulse as input signal elif stim == "Step": x = self.A * np.ones(N) # create step function title_str = r'Step Response' H_str = r'$h_{\epsilon}[n]$' elif stim == "StepErr": x = self.A * np.ones(N) # create step function title_str = r'Settling Error' H_str = r'$h_{\epsilon, \infty} - h_{\epsilon}[n]$' elif stim in {"Cos"}: x = self.A * np.cos(2 * np.pi * t * float(self.ledFreq.text())) if stim == "Cos": title_str = r'Transient Response to Cosine Signal' H_str = r'$y_{\cos}[n]$' elif stim in {"Sine", "Rect"}: x = self.A * np.sin(2 * np.pi * t * float(self.ledFreq.text())) if stim == "Sine": title_str = r'Transient Response to Sine Signal' H_str = r'$y_{\sin}[n]$' else: x = self.A * np.sign(x) title_str = r'Transient Response to Rect. Signal' H_str = r'$y_{rect}[n]$' elif stim == "Saw": x = self.A * sig.sawtooth(t * (float(self.ledFreq.text()) * 2 * np.pi)) title_str = r'Transient Response to Sawtooth Signal' H_str = r'$y_{saw}[n]$' elif stim == "RandN": x = self.A * np.random.randn(N) title_str = r'Transient Response to Gaussian Noise' H_str = r'$y_{gauss}[n]$' elif stim == "RandU": x = self.A * (np.random.rand(N) - 0.5) title_str = r'Transient Response to Uniform Noise' H_str = r'$y_{uni}[n]$' else: logger.error('Unknown stimulus "{0}"'.format(stim)) return if len(sos) > 0 and ( causal): # has second order sections and is causal h = sig.sosfilt(sos, x) elif (antiCausal): h = sig.filtfilt(self.bb, self.aa, x, -1, None) else: # no second order sections or antiCausals for current filter h = sig.lfilter(self.bb, self.aa, x) dc = sig.freqz(self.bb, self.aa, [0]) if stim == "StepErr": h = h - abs(dc[1]) # subtract DC value from response h = np.real_if_close( h, tol=1e3) # tol specified in multiples of machine eps self.cmplx = np.any(np.iscomplex(h)) if self.cmplx: h_i = h.imag h = h.real H_i_str = r'$\Im\{$' + H_str + '$\}$' H_str = r'$\Re\{$' + H_str + '$\}$' if log: self.bottom = safe_eval(self.ledLogBottom.text(), self.bottom, return_type='float') self.ledLogBottom.setText(str(self.bottom)) H_str = r'$|$ ' + H_str + '$|$ in dB' h = np.maximum(20 * np.log10(abs(h)), self.bottom) if self.cmplx: h_i = np.maximum(20 * np.log10(abs(h_i)), self.bottom) H_i_str = r'$\log$ ' + H_i_str + ' in dB' else: self.bottom = 0 self.init_axes() #================ Main Plotting Routine ========================= [ml, sl, bl] = self.ax_r.stem(t, h, bottom=self.bottom, markerfmt='o', label='$h[n]$') stem_fmt = params['mpl_stimuli'] if self.chkPltStim.isChecked(): [ms, ss, bs] = self.ax_r.stem(t, x, bottom=self.bottom, label='Stim.', **stem_fmt) ms.set_mfc(stem_fmt['mfc']) ms.set_mec(stem_fmt['mec']) ms.set_ms(stem_fmt['ms']) ms.set_alpha(stem_fmt['alpha']) for stem in ss: stem.set_linewidth(stem_fmt['lw']) stem.set_color(stem_fmt['mec']) stem.set_alpha(stem_fmt['alpha']) bs.set_visible(False) # invisible bottomline expand_lim(self.ax_r, 0.02) self.ax_r.set_title(title_str) if self.cmplx: [ml_i, sl_i, bl_i] = self.ax_i.stem(t, h_i, bottom=self.bottom, markerfmt='d', label='$h_i[n]$') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(len(t)): self.ax3d.plot([t[i], t[i]], [h[i], h[i]], [0, h_i[i]], '-', linewidth=2, alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(t, h, h_i, 'o', markersize=8, markerfacecolor='none', label='$h[n]$') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.redraw()
def _set_eps(self): """ Set tolerance value """ self.ui.eps = safe_eval(self.ui.ledEps.text(), alt_expr=self.ui.eps, sign='pos') self.ui.ledEps.setText(str(self.ui.eps))
def _update_param1(): self.ledWinPar1.setToolTip(tooltip) self.lblWinPar1.setText(to_html(txt_par1, frmt='bi')) self.param1 = safe_eval(self.ledWinPar1.text(), self.param1, return_type='float', sign='pos') self.ledWinPar1.setText(str(self.param1))
def displayText(self, text, locale): if not isinstance(text, six.text_type): # text = text.toString( ) # needed for Python 2, doesn't work with Py3 return "{:.{n_digits}g}".format(safe_eval(text), n_digits=params['FMT_pz'])
def _store_entry(source): if self.spec_edited: self.stim_freq = safe_eval(source.text(), self.stim_freq * fb.fil[0]['f_S'], return_type='float') / fb.fil[0]['f_S'] self.spec_edited = False # reset flag self.draw()