Package input_widgets

This package contains the widgets for entering / selecting parameters for the filter design.

input_tab_widgets

Tabbed container for all input widgets

class pyfda.input_widgets.input_tab_widgets.InputTabWidgets(parent=None, objectName='input_tab_widgets_inst')[source]

Create a tabbed widget for all input subwidgets in the list fb.input_widgets_list. This list is compiled at startup in pyfda.libs.tree_builder.Tree_Builder.

emit(dict_sig: dict = {}, sig_name: str = 'sig_tx') None

Emit a signal self.<sig_name> (defined as a class attribute) with a dict dict_sig using Qt’s emit().

  • Add the keys ‘id’ and ‘class’ with id resp. class name of the calling instance if not contained in the dict

  • If key ‘ttl’ is in the dict and its value is less than one, terminate the signal. Otherwise, reduce the value by one.

  • If the sender has passed an objectName, add it with the key “sender_name” to the dict.

log_rx(dict_sig=None)[source]

Enable self.sig_rx.connect(self.log_rx) above for debugging.

input_specs

Widget stacking all subwidgets for filter specification and design. The actual filter design is started here as well.

class pyfda.input_widgets.input_specs.Input_Specs(parent=None, objectName='input_specs_inst')[source]

Build widget for entering all filter specs

emit(dict_sig: dict = {}, sig_name: str = 'sig_tx') None

Emit a signal self.<sig_name> (defined as a class attribute) with a dict dict_sig using Qt’s emit().

  • Add the keys ‘id’ and ‘class’ with id resp. class name of the calling instance if not contained in the dict

  • If key ‘ttl’ is in the dict and its value is less than one, terminate the signal. Otherwise, reduce the value by one.

  • If the sender has passed an objectName, add it with the key “sender_name” to the dict.

load_dict()[source]

Reload info text from global dict fb.fil[0] and reset ‘DESIGN’ button

process_sig_rx(dict_sig, propagate=False)[source]

Process signals coming in via subwidgets and sig_rx

All signals terminate here unless the flag propagate=True.

The sender name of signals coming in from local subwidgets is changed to its parent widget (input_specs) to prevent infinite loops.

process_sig_rx_local(dict_sig=None)[source]

Signals coming in from local subwidgets need to be propagated, so set propagate=True and proceed with processing in process_sig_rx.

quit_program()[source]

When <QUIT> button is pressed, send ‘quit_program’

start_design_filt()[source]

Start the actual filter design process:

  • store the entries of all input widgets in the global filter dict.

  • call the design method, passing the whole dictionary as the argument: let the design method pick the needed specs

  • update the input widgets in case weights, corner frequencies etc. have been changed by the filter design method

  • the plots are updated via signal-slot connection

update_UI(dict_sig={}) None[source]

update_UI is called every time the filter design method or order (min / man) has been changed as this usually requires a different set of frequency and amplitude specs.

At this time, the actual filter object instance has been created from the name of the design method (e.g. ‘cheby1’) in select_filter.py. Its handle has been stored in fb.fil_inst.

fb.fil[0] (currently selected filter) is read, then general information for the selected filter type and order (min/man) is gathered from the filter tree [fb.fil_tree], i.e. which parameters are needed, which widgets are visible and which message shall be displayed.

Then, the UIs of all subwidgets are updated using their “update_UI” method.

update_info()[source]

Update the info field of the filter selection

pyfda.input_widgets.input_specs.classes = {'Input_Specs': 'Specs'}

display name

Type:

Dict containing class name

select_filter

Subwidget for selecting the filter, consisting of combo boxes for: - Response Type (LP, HP, Hilbert, …) - Filter Type (IIR, FIR, CIC …) - Filter Class (Butterworth, …)

class pyfda.input_widgets.select_filter.SelectFilter(parent=None, objectName='select_filter_inst')[source]

Construct and read combo boxes for selecting the filter, consisting of the following hierarchy:

  1. Response Type rt (LP, HP, Hilbert, …)

  2. Filter Type ft (IIR, FIR, CIC …)

  3. Filter Class (Butterworth, …)

Every time a combo box is changed manually, the filter tree for the selected response resp. filter type is read and the combo box(es) further down in the hierarchy are populated according to the available combinations.

sig_tx({‘filt_changed’}) is emitted and propagated to input_filter_specs.py where it triggers the recreation of all subwidgets.

emit(dict_sig: dict = {}, sig_name: str = 'sig_tx') None

Emit a signal self.<sig_name> (defined as a class attribute) with a dict dict_sig using Qt’s emit().

  • Add the keys ‘id’ and ‘class’ with id resp. class name of the calling instance if not contained in the dict

  • If key ‘ttl’ is in the dict and its value is less than one, terminate the signal. Otherwise, reduce the value by one.

  • If the sender has passed an objectName, add it with the key “sender_name” to the dict.

load_dict()[source]

Reload comboboxes from filter dictionary to update changed settings after loading a filter design from disk. load_dict uses the automatism of _set_response_type etc. of checking whether the previously selected filter design method is also available for the new combination.

load_filter_order(enb_signal=False)[source]
Called by set_design_method or from InputSpecs (with enb_signal = False),

load filter order setting from fb.fil[0] and update widgets

process_sig_rx(dict_sig)[source]

Process signals coming in via sig_rx

All signals terminate here.

The sender name of signals coming in from local subwidgets is changed to its parent widget to prevent infinite loops.

input_coeffs

Widget for displaying and modifying filter coefficients

class pyfda.input_widgets.input_coeffs.Input_Coeffs(parent=None)[source]

Create widget with a (sort of) model-view architecture for viewing / editing / entering data contained in self.ba which is a list of two numpy arrays:

  • self.ba[0] contains the numerator coefficients (“b”)

  • self.ba[1] contains the denominator coefficients (“a”)

The lists don’t neccessarily have the same length but they are always defined. For FIR filters, self.ba[1][0] = 1, all other elements are zero.

The length of both lists can be egalized with self._equalize_ba_length().

Views / formats are handled by the ItemDelegate() class.

clear_table()[source]

Clear self.ba: Initialize coeff for a poles and a zero @ origin, a = b = [1; 0].

Refresh QTableWidget

dict2ui()[source]
  • update the UI from the dictionary

  • Update the fixpoint quant. object

  • Update the quantized coefficient view and the overflow counter

  • Refresh the table

Triggered by:

  • process_sig_rx(): self.fx_specs_changed == True or

    dict_sig[‘fx_sim’] == ‘specs_changed’

  • self.qfrmt2dict()

  • self.fx_base2dict()

emit(dict_sig: dict = {}, sig_name: str = 'sig_tx') None

Emit a signal self.<sig_name> (defined as a class attribute) with a dict dict_sig using Qt’s emit().

  • Add the keys ‘id’ and ‘class’ with id resp. class name of the calling instance if not contained in the dict

  • If key ‘ttl’ is in the dict and its value is less than one, terminate the signal. Otherwise, reduce the value by one.

  • If the sender has passed an objectName, add it with the key “sender_name” to the dict.

export_table()[source]

Export data from coefficient table self.tblCoeff to clipboard / file in CSV format.

fx_base2dict()[source]

Read out the UI settings of self.ui.cmb_fx_base (triggering this method) which specifies the fx number base (dec, bin, …) for display and store it in fb.fil[0][‘fx_base’].

Refresh the table and update quantization widgets. Don’t emit a signal because this only influences the view not the data itself.

load_dict()[source]
  • Copy filter dict array fb.fil[0][‘ba’] to the coefficient list self.ba

  • Set quantization UI from dict, update quantized coeff. display / overflow counter

  • Update the display via self.refresh_table().

The filter dict is a “normal” 2D-numpy float array for the b and a coefficients while the coefficient list self.ba is a list of two float ndarrays to allow for different lengths of b and a subarrays while adding / deleting items.

process_sig_rx(dict_sig=None)[source]

Process signals coming from sig_rx

qfrmt2dict()[source]

Read out the UI settings of self.ui.cmb_qfrmt (triggering this method) and store it under the ‘qfrmt’ key if it is a fixpoint format. Set the fb.fil[0][‘fx_sim’] flag accordingly.

Refresh the table and update quantization widgets, finally emit a signal {‘fx_sim’: ‘specs_changed’}.

quant_coeffs_save()[source]

Triggered by pushing “Quantize button”:

  • Store selected / all quantized coefficients in self.ba

  • Refresh table (for the case that anything weird happens during quantization)

  • Reset Overflow flags self.ba_q[2] and self.ba_q[3]

  • Save quantized self.ba to filter dict (in _save_dict()). This emits {‘data_changed’: ‘input_coeffs’}

quant_coeffs_view()[source]

This method only creates a view on the quantized coefficients and stores it in self.ba_q, the actual coefficients in self.ba remain unchanged!

  • Reset overflow counters

  • Quantize filter coefficients self.ba with quantizer objects self.Q[0] and self.Q[1] for b and a coefficients respectively and store them in the array self.ba_q. Depending on the number base (float, dec, hex, …) the result can be of type float or string.

  • Store pos. / neg. overflows in the 3rd and 4th column of self.ba_q as 0 or +/- 1.

refresh_table()[source]

Update self.ba_q from self.ba (list with 2 one-dimensional numpy arrays), i.e. requantize displayed values (not self.ba) and overflow counters.

Refresh the table from it. Data is displayed via ItemDelegate.displayText() in the number format set by fb.fil[0][‘fx_base’].

  • self.ba[0] -> b coefficients

  • self.ba[1] -> a coefficients

The table dimensions are set according to the filter type set in fb.fil[0][‘ft’] which is either ‘FIR’ or ‘IIR’ and by the number of rows in self.ba.

Called at the end of nearly every method.

class pyfda.input_widgets.input_coeffs.ItemDelegate(parent)[source]

The following methods are subclassed to replace display and editor of the QTableWidget.

  • displayText() displays the data stored in the table in various number formats

  • createEditor() creates a line edit instance for editing table entries

  • setEditorData() pass data with full precision and in selected format to editor

  • setModelData() pass edited data back to model (self.ba)

Editing the table triggers setModelData() but does not emit a signal outside this class, only the ui.butSave button is highlighted. When it is pressed, a signal with ‘data_changed’:’input_coeffs’ is produced in class Input_Coeffs. Additionally, a signal is emitted with ‘fx_sim’: ‘specs_changed’

createEditor(parent, options, index)[source]

Neet to set editor explicitly, otherwise QDoubleSpinBox instance is created when space is not sufficient?! editor: instance of e.g. QLineEdit (default) index: instance of QModelIndex options: instance of QStyleOptionViewItemV4

displayText(text, locale) str[source]

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 Q[c].ovr_flag is set to +1 or -1 for

positive / negative overflows, else it is 0.

initStyleOption(option, index)[source]

Initialize option with the values using the index index. When the item (0,1) is processed, it is styled especially. All other items are passed to the original initStyleOption() which then calls displayText(). Afterwards, check whether an fixpoint overflow has occured and color item background accordingly.

setEditorData(editor, index)[source]

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

setModelData(editor, model, index) None[source]

When editing has finished, read the updated data from the editor (= QTableWidget), and store it in self.ba as float / complex for fb.fil[0][‘fx_sim’] == False.

For all other formats, convert data back to floating point format via frmt2float() and store it in self.ba as float / complex. Next, use float2frmt() to quantize data and and store it in parent.ba_q. Finally, refresh the table item to display it in the selected format via _refresh_table_item().

editor: instance of e.g. QLineEdit model: instance of QAbstractTableModel index: instance of QModelIndex

text(item) str[source]

Return item text as string transformed by self.displayText()

This is used a.o. by pyfda_io_lib.qtable2csv() and libs.pyfda_fix_lib to read out a table in text mode, e.g. text = table.itemDelegate().text(item)

pyfda.input_widgets.input_coeffs.classes = {'Input_Coeffs': 'b,a'}

display name

Type:

Dict containing class name

input_pz

Widget for displaying and modifying filter Poles and Zeros

class pyfda.input_widgets.input_pz.Input_PZ(parent=None)[source]

Create the window for entering exporting / importing and saving / loading data

cmplx2frmt(text, places=-1)[source]

Convert number “text” (real or complex or string) to the format defined by cmbPZFrmt.

Returns:

string

emit(dict_sig: dict = {}, sig_name: str = 'sig_tx') None

Emit a signal self.<sig_name> (defined as a class attribute) with a dict dict_sig using Qt’s emit().

  • Add the keys ‘id’ and ‘class’ with id resp. class name of the calling instance if not contained in the dict

  • If key ‘ttl’ is in the dict and its value is less than one, terminate the signal. Otherwise, reduce the value by one.

  • If the sender has passed an objectName, add it with the key “sender_name” to the dict.

eventFilter(source, event)[source]

Filter all events generated by the QLineEdit widgets. Source and type of all events generated by monitored objects are passed to this eventFilter, evaluated and passed on to the next hierarchy level.

  • When a QLineEdit widget gains input focus (QEvent.FocusIn), display the stored value from filter dict with full precision

  • When a key is pressed inside the text field, set the spec_edited flag to True.

  • When a QLineEdit widget loses input focus (QEvent.FocusOut), store current value in linear format with full precision (only if spec_edited == True) and display the stored value in selected format

export_table()[source]

Export data from coefficient table self.tblCoeff to clipboard in CSV format or to file using a selected format

frmt2cmplx(string: str, default: float = 0.0) complex[source]

Convert string to real or complex, try to find out the format (cartesian, polar with various angle formats)

load_dict()[source]

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.

Format is: [array[zeros, …], array[poles, …], k]

process_sig_rx(dict_sig=None)[source]

Process signals coming from sig_rx

class pyfda.input_widgets.input_pz.ItemDelegate(parent)[source]

The following methods are subclassed to replace display and editor of the QTableWidget.

  • displayText() displays the data stored in the table in various number formats

  • createEditor() creates a line edit instance for editing table entries

  • setEditorData() pass data with full precision and in selected format to editor

  • setModelData() pass edited data back to model (self.zpk)

createEditor(parent, options, index)[source]

Neet to set editor explicitly, otherwise QDoubleSpinBox instance is created when space is not sufficient?! editor: instance of e.g. QLineEdit (default) index: instance of QModelIndex options: instance of QStyleOptionViewItemV4

displayText(text, locale)[source]

Display text with selected format (cartesian / polar) and number of places

text: string / QVariant from QTableWidget to be rendered locale: locale for the text

initStyleOption(option, index)[source]

Initialize option with the values using the index index. All items are passed to the original initStyleOption() which then calls displayText().

Afterwards, check whether a pole (index.column() == 1 )is outside the UC and color item background accordingly (not implemented yet).

setEditorData(editor, index)[source]

Pass the data to be edited to the editor: - retrieve data with full accuracy (places=-1) from zpk (in float format) - represent it in the selected format (Cartesian, polar, …)

editor: instance of e.g. QLineEdit index: instance of QModelIndex

setModelData(editor, model, index)[source]

When editor has finished, read the updated data from the editor, convert it to complex format and store it in both the model (= QTableWidget) and in zpk. Finally, refresh the table item to display it in the selected format (via to be defined) and normalize the gain.

editor: instance of e.g. QLineEdit model: instance of QAbstractTableModel index: instance of QModelIndex

text(item)[source]

Return item text as string transformed by self.displayText()

pyfda.input_widgets.input_pz.classes = {'Input_PZ': 'P/Z'}

display name

Type:

Dict containing class name

input_info

Widget for displaying infos about filter and filter design method and debugging infos

class pyfda.input_widgets.input_info.Input_Info(parent=None)[source]

Create widget for displaying infos about filter specs and filter design method

emit(dict_sig: dict = {}, sig_name: str = 'sig_tx') None

Emit a signal self.<sig_name> (defined as a class attribute) with a dict dict_sig using Qt’s emit().

  • Add the keys ‘id’ and ‘class’ with id resp. class name of the calling instance if not contained in the dict

  • If key ‘ttl’ is in the dict and its value is less than one, terminate the signal. Otherwise, reduce the value by one.

  • If the sender has passed an objectName, add it with the key “sender_name” to the dict.

load_dict()[source]

update docs and filter performance

process_sig_rx(dict_sig=None)[source]

Process signals coming from sig_rx

pyfda.input_widgets.input_info.classes = {'Input_Info': 'Info'}

display name

Type:

Dict containing class name

input_fixpoint_specs

The configuration file libs.pyfda_template.conf lists which fixpoint classes (e.g. FIR_DF and IIR_DF1) can be used with which filter design algorithm. libs.tree_builder parses this file and writes all fixpoint modules into the list fb.fixpoint_widgets_list. The input widget pyfda.input_widgets.input_fixpoint_specs constructs a combo box from this list with references to all successfully imported fixpoint modules. The currently selected fixpoint widget (e.g. FIR_DF) is imported from Package fixpoint_widgets together with the referenced picture.

Each fixpoint module / class contains a widget that is constructed using helper classes from fixpoint_widgets.fixpoint_helpers.py. The widgets allow entering fixpoint specifications like word lengths and formats for input, output and internal structures (like an accumulator) for each class. It also contains a reference to a picture showing the filter topology.

Details of the mechanism and the module are described in input_widgets.input_fixpoint_specs.