Source code for pyfda.filter_widgets.delay
# -*- coding: utf-8 -*-
#
# This file is part of the pyFDA project hosted at https://github.com/chipmuenk/pyfda
#
# Copyright © pyFDA Project Contributors
# Licensed under the terms of the MIT License
# (see file LICENSE in root directory for details)
"""
Design a simple delay for demonstrating the effect of latency and for debugging
Attention:
This class is re-instantiated dynamically every time the filter design method
is selected, calling the __init__ method.
API version info:
1.0: initial working release
"""
from pyfda.libs.compat import QWidget, QLabel, QLineEdit, pyqtSignal, QVBoxLayout, QHBoxLayout
import scipy.signal as sig
import numpy as np
import pyfda.filterbroker as fb
from pyfda.libs.pyfda_qt_lib import popup_warning
from pyfda.libs.pyfda_lib import fil_save, safe_eval
__version__ = "1.0"
classes = {'Delay':'Delay'} #: Dict containing class name : display name
[docs]
class Delay(QWidget):
FRMT = 'zpk' # output format of delay filter widget
info ="""
**Delay widget**
allows entering the number of **delays** :math:`N` :math:`T_S`. It is treated as a FIR filter,
the number of delays is directly translated to a number of poles (:math:`N > 0`)
or zeros (:math:`N < 0`).
Obviously, there is no minimum design algorithm or no design algorithm at all :-)
"""
sig_tx = pyqtSignal(object)
from pyfda.libs.pyfda_qt_lib import emit
def __init__(self):
QWidget.__init__(self)
self.N = 5
self.ft = 'FIR'
self.rt_dicts = ('com',)
self.rt_dict = {
'COM': {'man': {'fo':('a', 'N'),
'msg':('a',
"<span>Enter desired number of delays <b><i>N</i></b>.</span>")
},
},
'AP': {'man':{}
}
}
self.info_doc = []
#--------------------------------------------------------------------------
[docs]
def construct_UI(self):
"""
Create additional subwidget(s) needed for filter design:
These subwidgets are instantiated dynamically when needed in
select_filter.py using the handle to the filter instance, fb.fil_inst.
"""
pass
# =============================================================================
# self.lbl_delay = QLabel("Delays", self)
# self.lbl_delay.setObjectName('wdg_lbl_delays')
# self.led_delay = QLineEdit(self)
# self.led_delay.setText(str(self.N))
# self.led_delay.setObjectName('wdg_led_delay')
# self.led_delay.setToolTip("Number of delays, N > 0 produces poles, N < 0 zeros.")
#
# self.layHWin = QHBoxLayout()
# self.layHWin.setObjectName('wdg_layGWin')
# self.layHWin.addWidget(self.lbl_delay)
# self.layHWin.addWidget(self.led_delay)
# self.layHWin.setContentsMargins(0,0,0,0)
# # Widget containing all subwidgets (cmbBoxes, Labels, lineEdits)
# self.wdg_fil = QWidget(self)
# self.wdg_fil.setObjectName('wdg_fil')
# self.wdg_fil.setLayout(self.layHWin)
#
# #----------------------------------------------------------------------
# # SIGNALS & SLOTs
# #----------------------------------------------------------------------
# self.led_delay.editingFinished.connect(self._update_UI)
# # fires when edited line looses focus or when RETURN is pressed
# #----------------------------------------------------------------------
#
# self.dict2filter_params() # get initial / last setting from dictionary
# self._update_UI()
# =============================================================================
# =============================================================================
# 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.N = safe_eval(self.led_delay.text(), self.N,
# sign="poszero", return_type='int')
# self.led_delay.setText(str(self.N))
#
# fb.fil[0].update({'wdg_fil': {'N': self.N}})
#
# # sig_tx -> select_filter -> filter_specs
# self.emit({'filt_changed': 'delay'})
# =============================================================================
[docs]
def dict2filter_params(self):
"""
Reload parameter(s) from filter dictionary (if they exist) and set
corresponding UI elements. dict2filter_params() is called upon initialization
and when the filter is loaded from disk.
"""
if 'filter_widgets' in fb.fil[0] and 'delay' in fb.fil[0]['filter_widgets']:
wdg_fil_par = fb.fil[0]['filter_widgets']['delay']
if 'N' in wdg_fil_par:
self.N = wdg_fil_par['N']
self.led_delay.setText(str(self.N))
def _get_params(self, fil_dict):
"""
Translate parameters from the passed dictionary to instance
parameters, scaling / transforming them if needed.
"""
self.N = fil_dict['N'] # filter order is translated to numb. of delays
def _test_N(self):
"""
Warn the user if the calculated order is too high for a reasonable filter
design.
"""
if self.N > 2000:
return popup_warning(self, self.N, "Delay")
else:
return True
def _save(self, fil_dict, arg=None):
"""
Convert between poles / zeros / gain, filter coefficients (polynomes)
and second-order sections and store all available formats in the passed
dictionary 'fil_dict'.
"""
if arg is None:
arg = np.zeros(self.N)
#arg =[[0], np.zeros(self.N), 1] # crashes coeff tab
fil_save(fil_dict, arg, self.FRMT, __name__)
[docs]
def APman(self, fil_dict):
self._get_params(fil_dict)
if not self._test_N():
return -1
self._save(fil_dict)
#------------------------------------------------------------------------------
if __name__ == '__main__':
import sys
from pyfda.libs.compat import QApplication, QFrame
app = QApplication(sys.argv)
# instantiate filter widget
filt = Delay()
filt.construct_UI()
wdg_delay = getattr(filt, 'wdg_fil')
layVDynWdg = QVBoxLayout()
layVDynWdg.addWidget(wdg_delay, stretch = 1)
filt.LPman(fb.fil[0]) # design a low-pass with parameters from global dict
print(fb.fil[0][filt.FRMT]) # return results in default format
frmMain = QFrame()
frmMain.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
frmMain.setLayout(layVDynWdg)
form = frmMain
form.show()
app.exec_()
#------------------------------------------------------------------------------