Main Routines

pyfda.libs.pyfda_dirs

Handle directories in an OS-independent way, create logging directory etc. Upon import, all the variables are set. This is imported first by pyfdax, logger cannot be used yet. Hence, messages are printed to the console.

pyfda.libs.pyfda_dirs.CONF_FILE = 'pyfda.conf'

name for general configuration file

pyfda.libs.pyfda_dirs.HOME_DIR = '/home/docs'

Home dir and user name

pyfda.libs.pyfda_dirs.LOG_CONF_FILE = 'pyfda_log.conf'

name for logging configuration file

pyfda.libs.pyfda_dirs.LOG_DIR_FILE = '/tmp/.pyfda/pyfda_20240409-112853.log'

Name of the log file, can be changed in pyfdax.py

pyfda.libs.pyfda_dirs.TEMP_DIR = '/tmp'

Temp directory for constructing logging dir

pyfda.libs.pyfda_dirs.USER_DIRS = []

Placeholder for user widgets directory list, set by treebuilder

pyfda.libs.pyfda_dirs.USER_NAME = ''

Home dir and user name

pyfda.libs.pyfda_dirs.copy_conf_files(force_copy=False, logger=None)[source]

If they don’t exist, create pyfda.conf und pyfda_log.conf from template files. in the user directory where they can be edited by the user without admin rights. If they exist and force_copy=True, make a backup of the old files and then overwrite them.

Parameters:
  • force_copy (bool) – When True, make a backup and overwrite existing config files.

  • logger (logger instance) – Write info and error messages to logger when it exists, otherwise use print(). When called during the initial phase, loggers have not been created yet and print() has to be used.

Return type:

None.

pyfda.libs.pyfda_dirs.env(name)[source]

Get value for environment variable name from the OS.

Parameters:

name (str) – environment variable

Returns:

value of environment variable

Return type:

str

pyfda.libs.pyfda_dirs.get_conf_dir()[source]

Return the user’s configuration directory

pyfda.libs.pyfda_dirs.get_home_dir()[source]

Return the user’s home directory and name

pyfda.libs.pyfda_dirs.get_log_dir()[source]

Try different OS-dependent locations for creating log files and return the first suitable directory name. Only called once at startup.

see https://stackoverflow.com/questions/847850/cross-platform-way-of-getting-temp-directory-in-python

pyfda.libs.pyfda_dirs.get_yosys_dir()[source]

Try to find YOSYS path and version from environment variable or path:

pyfda.libs.pyfda_dirs.last_file_dir = '/home/docs'

Place holder for file type selected (e.g. “csv”) in last file dialog

pyfda.libs.pyfda_dirs.last_file_name = ''

Place holder for storing the directory location of the last file

pyfda.libs.pyfda_dirs.last_file_type = ''

Global handle to pop-up window for CSV options - this window must be closed before opening another pop-up window! Otherwise, the second window becomes unaccessible (?) and pyfda becomes unresponsive.

pyfda.libs.pyfda_dirs.update_conf_files(logger)[source]

Copy templates to user config and logging config files, making backups of the old versions.

pyfda.libs.pyfda_dirs.valid(path)[source]

Check whether path exists and is valid

pyfda.libs.tree_builder

Create the tree dictionaries containing information about filters, filter implementations, widgets etc. in hierarchical form

exception pyfda.libs.tree_builder.ParseError[source]
class pyfda.libs.tree_builder.Tree_Builder[source]

Read the config file and construct dictionary trees with

  • all filter combinations

  • valid combinations of filter widgets and fixpoint implementations

build_class_dict(section, subpackage='')[source]
  • Try to dynamically import the modules (= files) parsed in section reading their module level attribute classes listing the classes contained in the module.

    When classes is a dictionary, e.g. {“Cheby”:”Chebyshev 1”} where the key is the class name in the module and the value the corresponding display name (used for the combo box).

  • When classes is a string or a list, use the string resp. the list items for both class and display name.

  • Try to import the filter classes

Parameters:
  • section (str) – Name of the section in the configuration file to be parsed by self.parse_conf_section.

  • subpackage (str) – Name of the subpackage containing the module to be imported. Module names are prepended successively with [‘pyfda.’ + subpackage + ‘.’, ‘’, subpackage + ‘.’]

Returns:

  • classes_dict (dict)

  • A dictionary with the classes as keys; values are dicts which define

  • the options (like display name, module path, fixpoint implementations etc).

  • Each entry has the form e.g.

  • {<class name> ({‘name’:<display name>, ‘mod’:<full module name>}} e.g.)

  • .. code-block:: python

    {‘Cheby1’:{‘name’:’Chebyshev 1’,

    ’mod’:’pyfda.filter_design.cheby1’, ‘fix’: ‘IIR_cascade’, ‘opt’: [“option1”, “option2”]}

build_fil_tree(fc, rt_dict, fil_tree=None)[source]

Read attributes (ft, rt, rt:fo) from filter class fc) Attributes are stored in the design method classes in the format (example from common.py)

self.ft = 'IIR'
self.rt_dict = {
         'LP': {'man':{'fo':     ('a','N'),
                       'msg':    ('a', r"<br /><b>Note:</b> Read this!"),
                       'fspecs': ('a','F_C'),
                       'tspecs': ('u', {'frq':('u','F_PB','F_SB'),
                                       'amp':('u','A_PB','A_SB')})
                      },
               'min':{'fo':     ('d','N'),
                      'fspecs': ('d','F_C'),
                      'tspecs': ('a', {'frq':('a','F_PB','F_SB'),
                                       'amp':('a','A_PB','A_SB')})
                    }
              },
        'HP': {'man':{'fo':     ('a','N'),
                      'fspecs': ('a','F_C'),
                      'tspecs': ('u', {'frq':('u','F_SB','F_PB'),
                                       'amp':('u','A_SB','A_PB')})
                     },
               'min':{'fo':     ('d','N'),
                      'fspecs': ('d','F_C'),
                      'tspecs': ('a', {'frq':('a','F_SB','F_PB'),
                                       'amp':('a','A_SB','A_PB')})
                     }
              }
        }

Build a dictionary of all filter combinations with the following hierarchy:

response types -> filter types -> filter classes -> filter order rt (e.g. ‘LP’) ft (e.g. ‘IIR’) fc (e.g. ‘cheby1’) fo (‘min’ or ‘man’)

All attributes found for fc are arranged in a dict, e.g. for cheby1.LPman and cheby1.LPmin, listing the parameters to be displayed and whether they are active, unused, disabled or invisible for each subwidget:

'LP':{
'IIR':{
     'Cheby1':{
         'man':{'fo':     ('a','N'),
                'msg':    ('a', r"<br /><b>Note:</b> Read this!"),
                'fspecs': ('a','F_C'),
                'tspecs': ('u', {'frq':('u','F_PB','F_SB'),
                                 'amp':('u','A_PB','A_SB')})
                },
         'min':{'fo':     ('d','N'),
                'fspecs': ('d','F_C'),
                'tspecs': ('a', {'frq':('a','F_PB','F_SB'),
                                 'amp':('a','A_PB','A_SB')})
                }
             }
       }
 }, ...

Finally, the whole structure is frozen recursively to avoid inadvertedly changing the filter tree.

For a full example, see the default filter tree fb.fil_tree defined in filterbroker.py.

Parameters:

None

Returns:

filter tree

Return type:

dict

init_filters()[source]

Run at startup to populate global dictionaries and lists:

  • Read attributes (ft, rt, fo) from all valid filter classes (fc) in the global dict fb.filter_classes and store them in the filter tree dict fil_tree with the hierarchy

    rt-ft-fc-fo-subwidget:params .

Parameters:

None

Returns:

  • fb.fil_tree :

Return type:

None, but populates the following global attributes

parse_conf_file()[source]

Parse the configuration file pyfda.conf (specified in dirs.USER_CONF_DIR_FILE). This is run only once at instantiation.

This is performed using build_class_dict() which calls parse_conf_section():

  • Try to find and import the modules specified in the corresponding sections

  • Extract and import the classes defined in each module and give back an OrderedDict with the successfully imported classes and their options (like fully qualified module names, display name, associated fixpoint widgets etc.).

  • Information for each section is stored in globally accessible OrderdDicts like`fb.filter_classes`.

The following sections are analyzed:

[Commons]:

Try to find user directories; if they exist add them to dirs.USER_DIRS and sys.path

For the other sections, OrderedDicts are returned with the class names as keys and dictionaries with options as values.

[Input Widgets]:

Store (user) input widgets in fb.input_classes

[Plot Widgets]:

Store (user) plot widgets in fb.plot_classes

[Filter Widgets]:

Store (user) filter widgets in fb.filter_classes

[Fixpoint Widgets]:

Store (user) fixpoint widgets in fb.fixpoint_classes

Parameters:

None

Return type:

None, but self.conf contains the parsed configuration file.

parse_conf_section(section)[source]

Parse section in config file conf and return an OrderedDict with the elements {key:<OPTION>} where key and <OPTION> have been read from the config file. <OPTION> has been sanitized and converted to a list or a dict.

Parameters:

section (str) – name of the section to be parsed

Returns:

section_conf_dict – Ordered dict with the keys of the config files and corresponding values

Return type:

dict

pyfda.libs.tree_builder.merge_dicts_hierarchically(d1, d2, path=None, mode='keep1')[source]

Merge the hierarchical dictionaries d1 and d2. The dict d1 is modified in place and returned

Parameters:
  • d1 (dict) – hierarchical dictionary 1

  • d2 (dict) – hierarchical dictionary 2

  • mode (str) –

    Select the behaviour when the same key is present in both dictionaries:

    • ’keep1’:

      keep the entry from d1 (default)

    • ’keep2’:

      keep the entry from d2

    • ’add1’:

      merge the entries, putting the values from d2 first (important for lists)

    • ’add2’:

      merge the entries, putting the values from d1 first ( “ )

  • path (str) – internal parameter for keeping track of hierarchy during recursive calls, it should not be set by the user

Returns:

d1 – a reference to the first dictionary, merged-in-place.

Return type:

dict

Example

>>> merge_dicts_hierarchically(fil_tree, fil_tree_add, mode='add1')

Notes

If you don’t want to modify d1 in place, call the function using:

>>> new_dict = merge_dicts_hierarchically(dict(d1), d2)

If you need to merge more than two dicts use:

>>> from functools import reduce   # only for py3
>>> reduce(merge, [d1, d2, d3...]) # add / merge all other dicts into d1

Taken with some modifications from:

http://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge

pyfda.libs.pyfda_lib

pyfda.filter_factory

Dynamic parameters and settings are exchanged via the dictionaries in this file. Importing filterbroker.py runs the module once, defining all module variables which have a global scope like class variables and can be imported like

>>> import filter_factory as ff
>>> myfil = ff.fil_factory
class pyfda.filter_factory.FilterFactory[source]

This class implements a filter factory that (re)creates the globally accessible filter instance fil_inst from module path and class name, passed as strings.

call_fil_method(method, fil_dict, fc=None)[source]

Instantiate the filter design class passed as string fc with the globally accessible handle fil_inst. If fc = None, use the previously instantiated filter design class.

Next, call the design method passed as string method of the instantiated filter design class.

Parameters:
  • method (string) – The name of the design method to be called (e.g. ‘LPmin’)

  • fil_dict (dictionary) – A dictionary with all the filter specs that is passed to the actual filter design routine. This is usually a copy of fb.fil[0] The results of the filter design routine are written back to the same dict.

  • fc (string (optional, default: None)) – The name of the filter design class to be instantiated. When nothing is specified, the last filter selection is used.

Returns:

err_code

one of the following error codes:
-1:

filter design operation has been cancelled by user

0:

filter design method exists and is callable

16:

passed method name is not a string

17:

filter design method does not exist in class

18:

filter design error containing “order is too high”

19:

filter design error containing “failure to converge”

99:

unknown error

Return type:

int

Examples

>>> call_fil_method("LPmin", fil[0], fc="cheby1")

The example first creates an instance of the filter class ‘cheby1’ and then performs the actual filter design by calling the method ‘LPmin’, passing the global filter dictionary fil[0] as the parameter.

create_fil_inst(fc, mod=None)[source]

Create an instance of the filter design class passed as a string fc from the module found in fb.filter_classes[fc]. This dictionary has been collected by tree_builder.py.

The instance can afterwards be globally referenced as fil_inst.

Parameters:
  • fc (str) – The name of the filter design class to be instantiated (e.g. ‘cheby1’ or ‘equiripple’)

  • mod (str (optional, default = None)) – Fully qualified name of the filter module. When not specified, it is read from the global dict fb.filter_classes[fc]['mod']

Returns:

err_code

one of the following error codes:
-1:

filter design class was instantiated successfully

0:

filter instance exists, no re-instantiation necessary

1:

filter module not found by FilterTreeBuilder

2:

filter module found by FilterTreeBuilder but could not be imported

3:

filter class could not be instantiated

4:

unknown error during instantiation

Return type:

int

Examples

>>> create_fil_instance('cheby1')
>>> fil_inst.LPmin(fil[0])

The example first creates an instance of the filter class ‘cheby1’ and then performs the actual filter design by calling the method ‘LPmin’, passing the global filter dictionary fil[0] as the parameter.

pyfda.filter_factory.fil_factory = <pyfda.filter_factory.FilterFactory object>

Class instance of FilterFactory that can be accessed in other modules

pyfda.filter_factory.fil_inst = None

Instance of current filter design class (e.g. “cheby1”), globally accessible

>>> import filter_factory as ff
>>> ff.fil_factory.create_fil_instance('cheby1') # create instance of dynamic class
>>> ff.fil_inst.LPmin(fil[0]) # design a filter

pyfda.filterbroker

Dynamic parameters and settings are exchanged via the dictionaries in this file. Importing filterbroker.py runs the module once, defining all module variables which have a global scope like class variables and can be imported like

>>> import filterbroker as fb
>>> myfil = fb.fil[0]

The entries in this file are only used as initial / default entries and to demonstrate the structure of the global dicts and lists. These initial values are also handy for module-level testing where some useful settings of the variables is required.

Notes

Alternative approaches for data persistence could be the packages shelve or pickleshare More info on data persistence and storing / accessing global variables:

pyfda.filterbroker.base_dir = ''

Project base directory

pyfda.filterbroker.clipboard = None

Handle to central clipboard instance

pyfda.filterbroker.filter_classes = {'Bessel': {'mod': 'pyfda.filter_widgets.bessel', 'name': 'Bessel'}, 'Butter': {'mod': 'pyfda.filter_widgets.butter', 'name': 'Butterworth'}, 'Cheby1': {'mod': 'pyfda.filter_widgets.cheby1', 'name': 'Chebyshev 1'}, 'Cheby2': {'mod': 'pyfda.filter_widgets.cheby2', 'name': 'Chebyshev 2'}, 'Ellip': {'mod': 'pyfda.filter_widgets.ellip', 'name': 'Elliptic'}, 'EllipZeroPhz': {'mod': 'pyfda.filter_widgets.ellip_zero', 'name': 'EllipZeroPhz'}, 'Equiripple': {'mod': 'pyfda.filter_widgets.equiripple', 'name': 'Equiripple'}, 'Firwin': {'mod': 'pyfda.filter_widgets.firwin', 'name': 'Windowed FIR'}, 'MA': {'mod': 'pyfda.filter_widgets.ma', 'name': 'Moving Average'}, 'Manual_FIR': {'mod': 'pyfda.filter_widgets.manual', 'name': 'Manual'}, 'Manual_IIR': {'mod': 'pyfda.filter_widgets.manual', 'name': 'Manual'}}

The keys of this dictionary are the names of all found filter classes, the values are the name to be displayed e.g. in the comboboxes and the fully qualified name of the module containing the class.

pyfda.filterbroker.redo()[source]

Store current filter to undo memory fil_undo

pyfda.filterbroker.undo()[source]

Restore current filter from undo memory fil_undo

pyfda.libs.pyfda_io_lib