Exemple #1
0
    def update_UI(self, new_labels=()):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

        self.lblUnit.setText(" in " + rt_label(fb.fil[0]['freq_specs_unit']))
        num_new_labels = len(new_labels)
        # hide / show labels / create new subwidgets if neccessary:
        self._show_entries(num_new_labels)

        #        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        #---------------------------- logging -----------------------------
        logger.debug("update_UI: {0}-{1}-{2}".format(fb.fil[0]['rt'],
                                                     fb.fil[0]['fc'],
                                                     fb.fil[0]['fo']))

        f_range = " (0 &lt; <i>f</i> &lt; <i>f<sub>S </sub></i>/2)"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values
            self.qlabels[i].setText(rt_label(new_labels[i]))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID
            qstyle_widget(self.qlineedit[i], state)

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip(
                    "<span>Corner frequency for (this) stop band" + f_range +
                    ".</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip(
                    "<span>Corner frequency for (this) pass band" + f_range +
                    ".</span>")
            else:
                self.qlineedit[i].setToolTip(
                    "<span>Corner frequency for (this) band" + f_range +
                    ".</span>")

        self.n_cur_labels = num_new_labels  # update number of currently visible labels
        self.sort_dict_freqs(
        )  # sort frequency entries in dictionary and update display
Exemple #2
0
    def _construct_UI(self):
        """
        Construct the User Interface
        """
        bfont = QFont()
        bfont.setBold(True)

        lblTitle = QLabel(str(self.title), self) # field for widget title
        lblTitle.setFont(bfont)
        lblTitle.setWordWrap(True)
        self.lblUnit = QLabel(self)
        self.lblUnit.setText("in " + rt_label(fb.fil[0]['freq_specs_unit']))

        layHTitle = QHBoxLayout()
        layHTitle.addWidget(lblTitle)
        layHTitle.addWidget(self.lblUnit)
        layHTitle.addStretch(1)
        
        # Create a gridLayout consisting of QLabel and QLineEdit fields
        # for the frequency specs:
        self.layGSpecs = QGridLayout() # sublayout for spec fields
        # set the title as the first (fixed) entry in grid layout. The other
        # fields are added and hidden dynamically in _show_entries and _hide_entries()
        self.layGSpecs.addLayout(layHTitle, 0, 0, 1, 2)
        self.layGSpecs.setAlignment(Qt.AlignLeft)

        self.frmMain = QFrame(self)
        self.frmMain.setLayout(self.layGSpecs)

        self.layVMain = QVBoxLayout() # Widget main layout
        self.layVMain.addWidget(self.frmMain)#, Qt.AlignLeft)
        self.layVMain.setContentsMargins(*params['wdg_margins'])
        self.setLayout(self.layVMain)

        self.n_cur_labels = 0 # number of currently visible labels / qlineedits        
Exemple #3
0
    def update_UI(self, new_labels=[]):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels:  # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels:  # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        for i in range(num_new_labels):
            # Update ALL labels and corresponding values
            self.qlabels[i].setText(rt_label(new_labels[i]))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID

        self.n_cur_labels = num_new_labels  # update number of currently visible labels
        self.load_entries(
        )  # display rounded filter dict entries in selected unit
Exemple #4
0
    def _show_entries(self, num_new_labels):
        """
        - check whether enough subwidgets (QLabel und QLineEdit) exist for the 
          the required number of `num_new_labels`: 
              - create new ones if required 
              - initialize them with dummy information
              - install eventFilter for new QLineEdit widgets so that the filter 
                  dict is updated automatically when a QLineEdit field has been 
                  edited.
        - if enough subwidgets exist already, make enough of them visible to
          show all spec fields
        """
        num_tot_labels = len(
            self.qlabels)  # number of existing labels (vis. + invis.)

        if num_tot_labels < num_new_labels:  # new widgets need to be generated
            for i in range(num_tot_labels, num_new_labels):
                self.qlabels.append(QLabel(self))
                self.qlabels[i].setText(rt_label("dummy"))

                self.qlineedit.append(QLineEdit(""))
                self.qlineedit[i].setObjectName("dummy")
                self.qlineedit[i].installEventFilter(self)  # filter events

                self.layGSpecs.addWidget(self.qlabels[i], i, 0)
                self.layGSpecs.addWidget(self.qlineedit[i], i, 1)

        else:  # make the right number of widgets visible
            for i in range(self.n_cur_labels, num_new_labels):
                self.qlabels[i].show()
                self.qlineedit[i].show()
Exemple #5
0
    def _show_entries(self, num_new_labels):
        """
        - check whether enough subwidgets (QLabel und QLineEdit) exist for the 
          the required number of `num_new_labels`: 
              - create new ones if required 
              - initialize them with dummy information
              - install eventFilter for new QLineEdit widgets so that the filter 
                  dict is updated automatically when a QLineEdit field has been 
                  edited.
        - if enough subwidgets exist already, make enough of them visible to
          show all spec fields
        """
        num_tot_labels = len(self.qlabels) # number of existing labels / qlineedit fields

        if num_tot_labels < num_new_labels: # new widgets need to be generated
            for i in range(num_tot_labels, num_new_labels):                   
                self.qlabels.append(QLabel(self))
                self.qlabels[i].setText(rt_label("dummy"))
    
                self.qlineedit.append(QLineEdit(""))
                self.qlineedit[i].setObjectName("dummy")
                self.qlineedit[i].installEventFilter(self)  # filter events

                # first entry is title and reset button
                self.layGSpecs.addWidget(self.qlabels[i],i+1,0)
                self.layGSpecs.addWidget(self.qlineedit[i],i+1,1)

        else: # make the right number of widgets visible
            for i in range(self.n_cur_labels, num_new_labels):
                self.qlabels[i].show()
                self.qlineedit[i].show()
Exemple #6
0
    def _construct_UI(self):
        """
        Construct the User Interface
        """
        self.layVMain = QVBoxLayout()  # Widget main layout
        layHTitle = QHBoxLayout()

        bfont = QFont()
        bfont.setBold(True)
        #            bfont.setWeight(75)
        lblTitle = QLabel()  # field for widget title
        lblTitle.setText(str(self.title))
        lblTitle.setFont(bfont)
        lblTitle.setWordWrap(True)
        self.lblUnit = QLabel()
        self.lblUnit.setText(" in " + rt_label(fb.fil[0]['freq_specs_unit']))

        layHTitle.addWidget(lblTitle)
        layHTitle.addWidget(self.lblUnit)
        layHTitle.addStretch(100)

        # Create a gridLayout consisting of QLabel and QLineEdit fields
        # for the frequency specs:
        self.layGSpecs = QGridLayout()  # sublayout for spec fields

        sfFrame = QFrame()
        sfFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        sfFrame.setLayout(self.layGSpecs)

        self.layVMain.addLayout(layHTitle)
        self.layVMain.addWidget(sfFrame)
        self.layVMain.setContentsMargins(1, 1, 1, 1)
        self.setLayout(self.layVMain)

        self.n_cur_labels = 0  # number of currently visible labels / qlineedits
Exemple #7
0
    def update_UI(self, new_labels = []):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
                  filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels: # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels: # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        for i in range(num_new_labels):
            # Update ALL labels and corresponding values 
            self.qlabels[i].setText(rt_label(new_labels[i]))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID
            self.qlineedit[i].setToolTip("<span>Relative weight (importance) for approximating this band.</span>")
            qstyle_widget(self.qlineedit[i], state)

        self.n_cur_labels = num_new_labels # update number of currently visible labels
        self.load_dict() # display rounded filter dict entries
Exemple #8
0
    def _construct_UI(self):
        """
        Construct the User Interface
        """
        bfont = QFont()
        bfont.setBold(True)

        lblTitle = QLabel(str(self.title), self)  # field for widget title
        lblTitle.setFont(bfont)
        lblTitle.setWordWrap(True)
        self.lblUnit = QLabel(self)
        self.lblUnit.setText("in " + rt_label(fb.fil[0]['freq_specs_unit']))

        layHTitle = QHBoxLayout()
        layHTitle.addWidget(lblTitle)
        layHTitle.addWidget(self.lblUnit)
        layHTitle.addStretch(1)

        # Create a gridLayout consisting of QLabel and QLineEdit fields
        # for the frequency specs:
        self.layGSpecs = QGridLayout()  # sublayout for spec fields
        # set the title as the first (fixed) entry in grid layout. The other
        # fields are added and hidden dynamically in _show_entries and _hide_entries()
        self.layGSpecs.addLayout(layHTitle, 0, 0, 1, 2)
        self.layGSpecs.setAlignment(Qt.AlignLeft)

        self.frmMain = QFrame(self)
        self.frmMain.setLayout(self.layGSpecs)

        self.layVMain = QVBoxLayout()  # Widget main layout
        self.layVMain.addWidget(self.frmMain)  #, Qt.AlignLeft)
        self.layVMain.setContentsMargins(*params['wdg_margins'])
        self.setLayout(self.layVMain)

        self.n_cur_labels = 0  # number of currently visible labels / qlineedits
Exemple #9
0
    def update_UI(self, new_labels = ()):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]
            
        self.lblUnit.setText(" in " + rt_label(fb.fil[0]['freq_specs_unit']))
        num_new_labels = len(new_labels)
        # hide / show labels / create new subwidgets if neccessary:
        self._show_entries(num_new_labels)

#        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        #---------------------------- logging -----------------------------
        logger.debug("update_UI: {0}-{1}-{2}".format(
                            fb.fil[0]['rt'],fb.fil[0]['fc'],fb.fil[0]['fo']))

        f_range = " (0 &lt; <i>f</i> &lt; <i>f<sub>S </sub></i>/2)"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values 
            self.qlabels[i].setText(rt_label(new_labels[i]))
            
            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID
            qstyle_widget(self.qlineedit[i], state)

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>Corner frequency for (this) stop band" + f_range + ".</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>Corner frequency for (this) pass band" + f_range + ".</span>")
            else:
                self.qlineedit[i].setToolTip("<span>Corner frequency for (this) band" + f_range + ".</span>")

        self.n_cur_labels = num_new_labels # update number of currently visible labels
        self.sort_dict_freqs() # sort frequency entries in dictionary and update display
Exemple #10
0
    def update_UI(self, new_labels=()):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

        #        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels:  # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels:  # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        tool_tipp_sb = "Min. attenuation resp. maximum level in (this) stop band"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values
            self.qlabels[i].setText(rt_label(new_labels[i]))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>" + tool_tipp_sb +
                                             " (&gt; 0).</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip(
                    "<span>Maximum ripple (&gt; 0) in (this) pass band.<span/>"
                )
            qstyle_widget(self.qlineedit[i], state)

        self.n_cur_labels = num_new_labels  # update number of currently visible labels
        self.load_dict(
        )  # display rounded filter dict entries in selected unit
Exemple #11
0
    def update_UI(self, new_labels = ()):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        state = new_labels[0]
        new_labels = new_labels[1:]

#        W_lbl = max([self.qfm.width(l) for l in new_labels]) # max. label width in pixel

        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels: # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels: # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        tool_tipp_sb = "Min. attenuation resp. maximum level in (this) stop band"
        for i in range(num_new_labels):
            # Update ALL labels and corresponding values 
            self.qlabels[i].setText(rt_label(new_labels[i]))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID

            if "sb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>" + tool_tipp_sb + " (&gt; 0).</span>")
            elif "pb" in new_labels[i].lower():
                self.qlineedit[i].setToolTip("<span>Maximum ripple (&gt; 0) in (this) pass band.<span/>")
            qstyle_widget(self.qlineedit[i], state)

        self.n_cur_labels = num_new_labels # update number of currently visible labels
        self.load_dict() # display rounded filter dict entries in selected unit
Exemple #12
0
    def _show_entries(self, num_new_labels):
        """
        - check whether subwidgets need to be shown or hidden       
        - check whether enough subwidgets (QLabel und QLineEdit) exist for the 
          the required number of `num_new_labels`: 
              - create new ones if required 
              - initialize them with dummy information
              - install eventFilter for new QLineEdit widgets so that the filter 
                  dict is updated automatically when a QLineEdit field has been 
                  edited.
        - if enough subwidgets exist already, make enough of them visible to
          show all spec fields
        """

        num_tot_labels = len(
            self.qlabels)  # number of existing labels (vis. + invis.)

        # less new subwidgets than currently displayed -> _hide some
        if num_new_labels < self.n_cur_labels:  # less new labels/qlineedit fields than before
            for i in range(num_new_labels, num_tot_labels):
                self.qlabels[i].hide()
                self.qlineedit[i].hide()
        # enough hidden subwidgets but need to make more labels visible
        elif num_tot_labels >= num_new_labels:
            for i in range(self.n_cur_labels, num_new_labels):
                self.qlabels[i].show()
                self.qlineedit[i].show()

        else:  # new subwidgets need to be generated
            for i in range(num_tot_labels, num_new_labels):
                self.qlabels.append(QLabel(self))
                self.qlabels[i].setText(rt_label("dummy"))

                self.qlineedit.append(QLineEdit(""))
                self.qlineedit[i].setObjectName("dummy")
                self.qlineedit[i].installEventFilter(self)  # filter events

                # first entry is the title
                self.layGSpecs.addWidget(self.qlabels[i], i + 1, 0)
                self.layGSpecs.addWidget(self.qlineedit[i], i + 1, 1)
Exemple #13
0
    def _show_entries(self, num_new_labels):
        """
        - check whether subwidgets need to be shown or hidden       
        - check whether enough subwidgets (QLabel und QLineEdit) exist for the 
          the required number of `num_new_labels`: 
              - create new ones if required 
              - initialize them with dummy information
              - install eventFilter for new QLineEdit widgets so that the filter 
                  dict is updated automatically when a QLineEdit field has been 
                  edited.
        - if enough subwidgets exist already, make enough of them visible to
          show all spec fields
        """

        num_tot_labels = len(self.qlabels) # number of existing labels (vis. + invis.)

        # less new subwidgets than currently displayed -> _hide some
        if num_new_labels < self.n_cur_labels: # less new labels/qlineedit fields than before
            for i in range (num_new_labels, num_tot_labels):
                self.qlabels[i].hide()
                self.qlineedit[i].hide()
        # enough hidden subwidgets but need to make more labels visible
        elif num_tot_labels >= num_new_labels:
            for i in range(self.n_cur_labels, num_new_labels):
                self.qlabels[i].show()
                self.qlineedit[i].show()

        else: # new subwidgets need to be generated
            for i in range(num_tot_labels, num_new_labels):                   
                self.qlabels.append(QLabel(self))
                self.qlabels[i].setText(rt_label("dummy"))
    
                self.qlineedit.append(QLineEdit(""))
                self.qlineedit[i].setObjectName("dummy")
                self.qlineedit[i].installEventFilter(self)  # filter events

                # first entry is the title
                self.layGSpecs.addWidget(self.qlabels[i],i+1,0)
                self.layGSpecs.addWidget(self.qlineedit[i],i+1,1)
Exemple #14
0
    def update_UI(self, new_labels=[]):
        """
        Set labels and get corresponding values from filter dictionary.
        When number of entries has changed, the layout of subwidget is rebuilt,
        using

        - `self.qlabels`, a list with references to existing QLabel widgets,
        - `new_labels`, a list of strings from the filter_dict for the current
          filter design
        - 'num_new_labels`, their number
        - `self.n_cur_labels`, the number of currently visible labels / qlineedit
          fields
        """
        self.lblUnit.setText(" in " + str(fb.fil[0]['freq_specs_unit']))
        self.new_labels = new_labels
        num_new_labels = len(new_labels)
        if num_new_labels < self.n_cur_labels:  # less new labels/qlineedit fields than before
            self._hide_entries(num_new_labels)

        elif num_new_labels > self.n_cur_labels:  # more new labels, create / show new ones
            self._show_entries(num_new_labels)

        #---------------------------- logging -----------------------------
        logger.debug("update_UI: {0}-{1}-{2}".format(fb.fil[0]['rt'],
                                                     fb.fil[0]['fc'],
                                                     fb.fil[0]['fo']))

        for i in range(num_new_labels):
            # Update ALL labels and corresponding values
            self.qlabels[i].setText(rt_label(new_labels[i]))

            self.qlineedit[i].setText(str(fb.fil[0][new_labels[i]]))
            self.qlineedit[i].setObjectName(new_labels[i])  # update ID

        self.n_cur_labels = num_new_labels  # update number of currently visible labels
        self.sort_dict_freqs(
        )  # sort frequency entries in dictionary and update display
Exemple #15
0
    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 {"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.setVisible(fb.fil[0]['freq_specs_unit'] == 'f_S')
        self.lblFreqUnit.setText(rt_label(fb.fil[0]['freq_specs_unit']))
        self.load_entry()
        
        
        self.bb = np.asarray(fb.fil[0]['ba'][0])
        self.aa = np.asarray(fb.fil[0]['ba'][1])
        sos = np.asarray(fb.fil[0]['sos'])

        self.f_S  = fb.fil[0]['f_S']
        
        N = self.calc_n_points(abs(int(self.ledNPoints.text())))

        t = np.linspace(0, N/self.f_S, N, endpoint=False)
        # calculate h[n]
        if stim == "Pulse":
            x = np.zeros(N)
            x[0] =1.0 # create dirac impulse as input signal
            title_str = r'Impulse Response'
            H_str = r'$h[n]$'
        elif stim == "Step":
            x = np.ones(N) # create step function
            title_str = r'Step Response'
            H_str = r'$h_{\epsilon}[n]$'
        elif stim == "StepErr":
            x = np.ones(N) # create step function
            title_str = r'Settling Error'
            H_str = r'$H(0) - h_{\epsilon}[n]$'
            
        elif stim in {"Sine", "Rect"}:
            x = np.sin(2 * np.pi * t * float(self.ledFreq.text()))
            if stim == "Sine":
                title_str = r'Response to Sine Signal'
                H_str = r'$h_{\sin}[n]$'
            else:
                x = np.sign(x)
                title_str = r'Response to Rect. Signal'
                H_str = r'$h_{rect}[n]$'
        else:
            x = sig.sawtooth(t * (float(self.ledFreq.text())* 2*np.pi))
            title_str = r'Response to Sawtooth Signal'
            H_str = r'$h_{saw}[n]$'

            
        if not np.any(sos): # no second order sections for current filter          
            h = sig.lfilter(self.bb, self.aa, x)
            dc = sig.freqz(self.bb, self.aa, [0])
        else:
#            print(sos)
            h = sig.sosfilt(sos, x)
            dc = sig.freqz(self.bb, self.aa, [0])
        
        if stim == "StepErr":
            h = h - abs(dc[1]) # subtract DC value from response


        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:
            bottom = float(self.ledLogBottom.text())
            H_str = r'$|$ ' + H_str + '$|$ in dB'
            h = np.maximum(20 * np.log10(abs(h)), bottom)
            if self.cmplx:
                h_i = np.maximum(20 * np.log10(abs(h_i)), bottom)
                H_i_str = r'$\log$ ' + H_i_str + ' in dB'
        else:
            bottom = 0

        self._init_axes()


        #================ Main Plotting Routine =========================
        [ml, sl, bl] = self.ax_r.stem(t, h, bottom=bottom, markerfmt='bo', linefmt='r')
        if self.chkPltStim.isChecked():
            [ms, ss, bs] = self.ax_r.stem(t, x, bottom=bottom, markerfmt='k*', linefmt='0.5')
            for stem in ss:
                stem.set_linewidth(0.5)
            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=bottom,
                                                markerfmt='rd', linefmt='b')
            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, color='b', alpha=.5)

            # plotting a circle on the top of each stem
            self.ax3d.plot(t, h, h_i, 'o', markersize=8,
                           markerfacecolor='none', color='b', label='ib')

            self.ax3d.set_xlabel('x')
            self.ax3d.set_ylabel('y')
            self.ax3d.set_zlabel('z')

        self.mplwidget.redraw()
Exemple #16
0
    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()
Exemple #17
0
    def _construct_UI(self):
        """
        Construct the User Interface
        """
        self.layVMain = QVBoxLayout()  # Widget main layout

        f_units = ['f_S', 'f_Ny', 'Hz', 'kHz', 'MHz', 'GHz']
        self.t_units = ['', '', 's', 'ms', r'$\mu$s', 'ns']

        bfont = QFont()
        bfont.setBold(True)

        self.lblUnits = QLabel(self)
        self.lblUnits.setText("Freq. Unit:")
        self.lblUnits.setFont(bfont)

        self.fs_old = fb.fil[0]['f_S']  # store current sampling frequency
        self.ledF_S = QLineEdit()
        self.ledF_S.setText(str(fb.fil[0]["f_S"]))
        self.ledF_S.setObjectName("f_S")
        self.ledF_S.installEventFilter(self)  # filter events

        self.lblF_S = QLabel(self)
        self.lblF_S.setText(rt_label("f_S"))

        self.cmbUnits = QComboBox(self)
        self.cmbUnits.setObjectName("cmbUnits")
        self.cmbUnits.addItems(f_units)
        self.cmbUnits.setToolTip(
            "Select whether frequencies are specified with respect to \n"
            "the sampling frequency f_S, to the Nyquist frequency \n"
            "f_Ny = f_S/2 or as absolute values.")
        self.cmbUnits.setCurrentIndex(0)
        #        self.cmbUnits.setItemData(0, (0,QColor("#FF333D"),Qt.BackgroundColorRole))#
        #        self.cmbUnits.setItemData(0, (QFont('Verdana', bold=True), Qt.FontRole)

        fRanges = [("0...½", "half"), ("0...1", "whole"), ("-½...½", "sym")]
        self.cmbFRange = QComboBox(self)
        self.cmbFRange.setObjectName("cmbFRange")
        for f in fRanges:
            self.cmbFRange.addItem(f[0], f[1])
        self.cmbFRange.setToolTip("Select frequency range (whole or half).")
        self.cmbFRange.setCurrentIndex(0)

        # Combobox resizes with longest entry
        self.cmbUnits.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.cmbFRange.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        self.butSort = QToolButton(self)
        self.butSort.setText("Sort")
        self.butSort.setCheckable(True)
        self.butSort.setChecked(True)
        self.butSort.setToolTip(
            "Sort frequencies in ascending order when pushed.")
        self.butSort.setStyleSheet("QToolButton:checked {font-weight:bold}")

        self.layHUnits = QHBoxLayout()
        self.layHUnits.addWidget(self.cmbUnits)
        self.layHUnits.addWidget(self.cmbFRange)
        self.layHUnits.addWidget(self.butSort)

        # Create a gridLayout consisting of QLabel and QLineEdit fields
        # for setting f_S, the units and the actual frequency specs:
        self.layGSpecWdg = QGridLayout()  # sublayout for spec fields
        self.layGSpecWdg.addWidget(self.lblF_S, 1, 0)
        self.layGSpecWdg.addWidget(self.ledF_S, 1, 1)
        self.layGSpecWdg.addWidget(self.lblUnits, 0, 0)
        self.layGSpecWdg.addLayout(self.layHUnits, 0, 1)

        frmMain = QFrame(self)
        frmMain.setLayout(self.layGSpecWdg)

        self.layVMain.addWidget(frmMain)
        self.layVMain.setContentsMargins(*params['wdg_margins'])

        self.setLayout(self.layVMain)

        #----------------------------------------------------------------------
        # SIGNALS & SLOTs
        #----------------------------------------------------------------------
        self.cmbUnits.currentIndexChanged.connect(self.update_UI)
        self.cmbFRange.currentIndexChanged.connect(self._freq_range)
        self.butSort.clicked.connect(self._store_sort_flag)
        #----------------------------------------------------------------------

        self.update_UI()  # first-time initialization
Exemple #18
0
    def __init__(self, parent):
        """
        Pass instance `parent` of parent class (FilterCoeffs)
        """
        super(FilterPZ_UI, self).__init__(parent)
#        self.parent = parent # instance of the parent (not the base) class
        self.eps = 1.e-4 # # tolerance value for e.g. setting P/Z to zero
        
        """
        Intitialize the widget, consisting of:
        - top chkbox row
        - coefficient table
        - two bottom rows with action buttons
        """
        
        self.bfont = QFont()
        self.bfont.setBold(True)
        self.bifont = QFont()
        self.bifont.setBold(True)
        self.bifont.setItalic(True)
#        q_icon_size = QSize(20, 20) # optional, size is derived from butEnable

        # ---------------------------------------------
        # UI Elements for controlling the display
        # ---------------------------------------------
        
        self.butEnable = QPushButton(self)
        self.butEnable.setIcon(QIcon(':/circle-x.svg'))
        q_icon_size = self.butEnable.iconSize() # <- set this for manual icon sizing
        self.butEnable.setIconSize(q_icon_size)
        self.butEnable.setCheckable(True)
        self.butEnable.setChecked(True)
        self.butEnable.setToolTip("<span>Show / hide poles and zeros in an editable table."
                " For high order systems, the table display might be slow.</span>")

        self.cmbPZFrmt = QComboBox(self)
        pz_formats = [('Cartesian', 'cartesian'), ('Polar (rad)', 'polar_rad'),
                      ('Polar (pi)', 'polar_pi'), ('Polar (°)', 'polar_deg')] # display text, data
        # π: u'3C0, °: u'B0, ∠: u'2220
        for pz in pz_formats:
            self.cmbPZFrmt.addItem(*pz)
        self.cmbPZFrmt.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        # self.cmbPZFrmt.setEnabled(False)
        self.cmbPZFrmt.setToolTip("<span>Set display format for poles and zeros to"
                                  " either cartesian (x + jy) or polar (r * &ang; &Omega;)."
                                  " Type 'o' for '&deg;', '&lt;' for '&ang;' and 'pi' for '&pi;'.</span>")

        self.spnDigits = QSpinBox(self)
        self.spnDigits.setRange(0,16)
        self.spnDigits.setToolTip("Number of digits to display.")
        self.lblDigits = QLabel("Digits", self)
        self.lblDigits.setFont(self.bifont)
        
        self.cmbCausal = QComboBox(self)
        causal_types = ['Causal', 'Acausal', 'Anticausal']
        for cs in causal_types:
            self.cmbCausal.addItem(cs)

        qset_cmb_box(self.cmbCausal, 'Causal')
        self.cmbCausal.setToolTip('<span>Set the system type. Not implemented yet.</span>')
        self.cmbCausal.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.cmbCausal.setEnabled(False)
            
        layHDisplay = QHBoxLayout()
        layHDisplay.setAlignment(Qt.AlignLeft)
        layHDisplay.addWidget(self.butEnable)
        layHDisplay.addWidget(self.cmbPZFrmt)
        layHDisplay.addWidget(self.spnDigits)
        layHDisplay.addWidget(self.lblDigits)
        layHDisplay.addWidget(self.cmbCausal)
        layHDisplay.addStretch()

        # ---------------------------------------------
        # UI Elements for setting the gain
        # ---------------------------------------------
        self.lblNorm = QLabel(rt_label("Normalize"), self)
        self.cmbNorm = QComboBox(self)
        self.cmbNorm.addItems(["None", "1", "Max"])
        self.cmbNorm.setToolTip("<span>Set the gain <i>k</i> so that H(f)<sub>max</sub> is "
                                "either 1 or the max. of the previous system.</span>")

        self.lblGain = QLabel(rt_label("k = "), self)
        self.ledGain = QLineEdit(self)
        self.ledGain.setToolTip("<span>Specify gain factor <i>k</i>"
                                " (only possible for Normalize = 'None').</span>")
        self.ledGain.setText(str(1.))
        self.ledGain.setObjectName("ledGain")
        
        layHGain = QHBoxLayout()
        layHGain.addWidget(self.lblNorm)
        layHGain.addWidget(self.cmbNorm)
        layHGain.addWidget(self.lblGain)
        layHGain.addWidget(self.ledGain)
        layHGain.addStretch()

        # ---------------------------------------------
        # UI Elements for loading / storing / manipulating cells and rows
        # ---------------------------------------------

#        self.cmbFilterType = QComboBox(self)
#        self.cmbFilterType.setObjectName("comboFilterType")
#        self.cmbFilterType.setToolTip("Select between IIR and FIR filte for manual entry.")
#        self.cmbFilterType.addItems(["FIR","IIR"])
#        self.cmbFilterType.setSizeAdjustPolicy(QComboBox.AdjustToContents)


        self.butAddCells = QPushButton(self)
        self.butAddCells.setIcon(QIcon(':/row_insert_above.svg'))
        self.butAddCells.setIconSize(q_icon_size)
        self.butAddCells.setToolTip("<SPAN>Select cells to insert a new cell above each selected cell. "
                                "Use &lt;SHIFT&gt; or &lt;CTRL&gt; to select multiple cells. "
                                "When nothing is selected, add a row at the end.</SPAN>")

        self.butDelCells = QPushButton(self)
        self.butDelCells.setIcon(QIcon(':/row_delete.svg'))
        self.butDelCells.setIconSize(q_icon_size)
        self.butDelCells.setToolTip("<SPAN>Delete selected cell(s) from the table. "
                "Use &lt;SHIFT&gt; or &lt;CTRL&gt; to select multiple cells. "
                "When nothing is selected, delete the last row.</SPAN>")

        self.butSave = QPushButton(self)
        self.butSave.setIcon(QIcon(':/upload.svg'))
        self.butSave.setIconSize(q_icon_size)
        self.butSave.setToolTip("<span>Save coefficients and update all plots. "
                                "No modifications are saved before!</span>")

        self.butLoad = QPushButton(self)
        self.butLoad.setIcon(QIcon(':/download.svg'))
        self.butLoad.setIconSize(q_icon_size)
        self.butLoad.setToolTip("Reload coefficients.")

        self.butClear = QPushButton(self)
        self.butClear.setIcon(QIcon(':/trash.svg'))
        self.butClear.setIconSize(q_icon_size)
        self.butClear.setToolTip("Clear all entries.")


        self.butFromTable = QPushButton(self)
        self.butFromTable.setIcon(QIcon(':/to_clipboard.svg'))
        self.butFromTable.setIconSize(q_icon_size)
        self.butFromTable.setToolTip("<span>"
                            "Copy table to clipboard / file, SELECTED items are copied as "
                            "displayed. When nothing is selected, the whole table "
                            "is copied with full precision in decimal format.</span>")
        
        self.butToTable = QPushButton(self)
        self.butToTable.setIcon(QIcon(':/from_clipboard.svg'))
        self.butToTable.setIconSize(q_icon_size)
        self.butToTable.setToolTip("<span>Copy clipboard / file to table.</span>")

        butSettingsClipboard = QPushButton(self)
        butSettingsClipboard.setIcon(QIcon(':/settings.svg'))
        butSettingsClipboard.setIconSize(q_icon_size)
        butSettingsClipboard.setToolTip("<span>Adjust settings for CSV format and whether "
                                "to copy to/from clipboard or file.</span>")

        layHButtonsCoeffs1 = QHBoxLayout()
#        layHButtonsCoeffs1.addWidget(self.cmbFilterType)
        layHButtonsCoeffs1.addWidget(self.butAddCells)
        layHButtonsCoeffs1.addWidget(self.butDelCells)
        layHButtonsCoeffs1.addWidget(self.butClear)
        layHButtonsCoeffs1.addWidget(self.butSave)
        layHButtonsCoeffs1.addWidget(self.butLoad)
        layHButtonsCoeffs1.addWidget(self.butFromTable)
        layHButtonsCoeffs1.addWidget(self.butToTable)
        layHButtonsCoeffs1.addWidget(butSettingsClipboard)
        layHButtonsCoeffs1.addStretch()

        #-------------------------------------------------------------------
        #   Eps / set zero settings
        # ---------------------------------------------------------------------
        self.butSetZero = QPushButton("= 0", self)
        self.butSetZero.setToolTip("<span>Set selected poles / zeros = 0 with a magnitude &lt; &epsilon;. "
        "When nothing is selected, test the whole table.</span>")
        self.butSetZero.setIconSize(q_icon_size)

        lblEps = QLabel(self)
        lblEps.setText("<b><i>for &epsilon;</i> &lt;</b>")

        self.ledEps = QLineEdit(self)
        self.ledEps.setToolTip("Specify tolerance value.")

        layHButtonsCoeffs2 = QHBoxLayout()
        layHButtonsCoeffs2.addWidget(self.butSetZero)
        layHButtonsCoeffs2.addWidget(lblEps)
        layHButtonsCoeffs2.addWidget(self.ledEps)
        layHButtonsCoeffs2.addStretch()

        # ########################  Main UI Layout ############################
        # layout for frame (UI widget)
        layVMainF = QVBoxLayout()
        layVMainF.addLayout(layHDisplay)
        layVMainF.addLayout(layHGain)
        layVMainF.addLayout(layHButtonsCoeffs1)
        layVMainF.addLayout(layHButtonsCoeffs2)
        # This frame encompasses all UI elements
        frmMain = QFrame(self)
        frmMain.setLayout(layVMainF)

        layVMain = QVBoxLayout()
        layVMain.setAlignment(Qt.AlignTop) # this affects only the first widget (intended here)
        layVMain.addWidget(frmMain)
        layVMain.setContentsMargins(*params['wdg_margins'])
        self.setLayout(layVMain)
        
        #--- set initial values from dict / signal slot connections------------
        self.spnDigits.setValue(params['FMT_pz'])
        self.ledEps.setText(str(self.eps))
        butSettingsClipboard.clicked.connect(self._copy_options)
Exemple #19
0
    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 {"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'])

        self.f_S = fb.fil[0]['f_S']

        N = self.calc_n_points(abs(int(self.ledNPoints.text())))

        t = np.linspace(0, N / self.f_S, N, endpoint=False)
        # calculate h[n]
        if stim == "Pulse":
            x = np.zeros(N)
            x[0] = 1.0  # create dirac impulse as input signal
            title_str = r'Impulse Response'
            H_str = r'$h[n]$'
        elif stim == "Step":
            x = np.ones(N)  # create step function
            title_str = r'Step Response'
            H_str = r'$h_{\epsilon}[n]$'
        elif stim == "StepErr":
            x = np.ones(N)  # create step function
            title_str = r'Settling Error'
            H_str = r'$h_{\epsilon, \infty} - h_{\epsilon}[n]$'

        elif stim in {"Sine", "Rect"}:
            x = 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 = np.sign(x)
                title_str = r'Transient Response to Rect. Signal'
                H_str = r'$y_{rect}[n]$'

        elif stim == "Saw":
            x = 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 = np.random.randn(N)
            title_str = r'Transient Response to Gaussian Noise'
            H_str = r'$y_{gauss}[n]$'

        elif stim == "RandU":
            x = 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:  # has second order sections
            h = sig.sosfilt(sos, x)
            dc = sig.freqz(self.bb, self.aa, [0])
        else:  # no second order sections 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

        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:
            bottom = float(self.ledLogBottom.text())
            H_str = r'$|$ ' + H_str + '$|$ in dB'
            h = np.maximum(20 * np.log10(abs(h)), bottom)
            if self.cmplx:
                h_i = np.maximum(20 * np.log10(abs(h_i)), bottom)
                H_i_str = r'$\log$ ' + H_i_str + ' in dB'
        else:
            bottom = 0

        self._init_axes()

        #================ Main Plotting Routine =========================
        [ml, sl, bl] = self.ax_r.stem(t,
                                      h,
                                      bottom=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=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=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()
Exemple #20
0
    def _construct_UI(self):
        """
        Intitialize the widget, consisting of:
        """
        bfont = QFont()
        bfont.setBold(True)

        # Find which button holds the longest text:
        MaxTextlen = 0
        longestText = ""
        ButLength = 0
        butTexts = ["Add", "Delete", "Save", "Load", "Clear", "Set 0"]

        for item in butTexts:
            if len(item) > MaxTextlen:
                MaxTextlen = len(item)
                longestText = item + "mm"

        butAddRow = QPushButton(butTexts[0], self)
        ButLength = butAddRow.fontMetrics().boundingRect(longestText).width()

        self.chkPZList = QCheckBox("Show table", self)
        self.chkPZList.setChecked(True)
        self.chkPZList.setToolTip(
            "<span>Show filter Poles / Zeros as an editable table. "
            "For high order systems, this might be slow. </span>")

        lblRound = QLabel("Digits = ", self)
        self.spnRound = QSpinBox(self)
        self.spnRound.setRange(0, 9)
        self.spnRound.setValue(params['FMT_pz'])
        self.spnRound.setToolTip("Display d digits.")

        self.lblNorm = QLabel("Normalize", self)
        self.cmbNorm = QComboBox(self)
        self.cmbNorm.addItems(["None", "1", "Max"])
        self.cmbNorm.setToolTip(
            "<span>Set the gain <i>k</i> so that H(f)<sub>max</sub> is "
            "either 1 or the max. of the previous system.</span>")

        self.lblGain = QLabel(rt_label("k = "), self)
        self.ledGain = QLineEdit(self)
        self.ledGain.setToolTip("Specify gain factor <i>k</i>.")
        self.ledGain.setText(str(1.))
        self.ledGain.setObjectName("ledGain")
        #        self.ledGain.setFixedSize(W8, H)
        self.ledGain.installEventFilter(self)

        self.tblPZ = QTableWidget(self)
        #        self.tblPZ.setEditTriggers(QTableWidget.AllEditTriggers) # make everything editable
        self.tblPZ.setAlternatingRowColors(True)  # alternating row colors)
        self.tblPZ.setObjectName("tblPZ")

        self.tblPZ.horizontalHeader().setHighlightSections(
            True)  # highlight when selected
        self.tblPZ.horizontalHeader().setFont(bfont)

        self.tblPZ.verticalHeader().setHighlightSections(True)
        self.tblPZ.verticalHeader().setFont(bfont)
        self.tblPZ.setColumnCount(2)
        self.tblPZ.setItemDelegate(ItemDelegate(self))

        butAddRow.setToolTip(
            "<SPAN>Select <i>N</i> existing rows "
            "to insert <i>N</i> new rows above last selected cell. "
            "When nothing is selected, add a row at the end.</SPAN>")
        butAddRow.setMaximumWidth(ButLength)

        butDelCell = QPushButton(butTexts[1], self)
        butDelCell.setToolTip(
            "<span>Delete selected cell(s) from the table. "
            "Use &lt;SHIFT&gt; or &lt;CTRL&gt; to select multiple cells. "
            "If nothing is selected, delete the last row.</span>")
        butDelCell.setMaximumWidth(ButLength)

        butClear = QPushButton(butTexts[4], self)
        butClear.setToolTip("Clear all entries.")
        butClear.setMaximumWidth(ButLength)

        butSave = QPushButton(butTexts[2], self)
        butSave.setToolTip("<span>Save P/Z and update all plots. "
                           "No modifications are saved before!</span>")
        butSave.setMaximumWidth(ButLength)

        butLoad = QPushButton(butTexts[3], self)
        butLoad.setToolTip("Reload P / Z.")
        butLoad.setMaximumWidth(ButLength)

        butSetZero = QPushButton(butTexts[5], self)
        butSetZero.setToolTip(
            "<SPAN>Set selected cells = 0 when magnitude "
            "&lt; &epsilon;. When nothing is selected, apply to "
            "all cells.</SPAN>")
        butSetZero.setMaximumWidth(ButLength)

        self.lblEps = QLabel("for " + rt_label("&epsilon; &lt;"), self)
        self.ledSetEps = QLineEdit(self)
        self.ledSetEps.setToolTip("<SPAN>Specify tolerance.</SPAN>")
        self.ledSetEps.setText(str(1e-6))
        #        self.ledSetEps.setFixedSize(W8, H)

        # ============== UI Layout =====================================
        layHChkBoxes = QHBoxLayout()
        layHChkBoxes.addWidget(self.chkPZList)
        layHChkBoxes.addStretch(1)
        layHChkBoxes.addWidget(lblRound)
        layHChkBoxes.addWidget(self.spnRound)

        layHGain = QHBoxLayout()
        layHGain.addWidget(self.lblGain)
        layHGain.addWidget(self.ledGain)
        #        layHChkBoxes.addStretch(1)
        layHGain.addWidget(self.lblNorm)
        layHGain.addWidget(self.cmbNorm)
        layHGain.addStretch()

        layHButtonsPZs1 = QHBoxLayout()
        layHButtonsPZs1.addWidget(butAddRow)
        layHButtonsPZs1.addWidget(butDelCell)
        layHButtonsPZs1.addWidget(butSave)
        layHButtonsPZs1.addWidget(butLoad)
        layHButtonsPZs1.addStretch()

        layHButtonsPZs2 = QHBoxLayout()
        layHButtonsPZs2.addWidget(butClear)
        layHButtonsPZs2.addWidget(butSetZero)
        layHButtonsPZs2.addWidget(self.lblEps)
        layHButtonsPZs2.addWidget(self.ledSetEps)
        layHButtonsPZs2.addStretch()

        layVBtns = QVBoxLayout()
        layVBtns.addLayout(layHChkBoxes)
        layVBtns.addLayout(layHGain)
        layVBtns.addLayout(layHButtonsPZs1)
        layVBtns.addLayout(layHButtonsPZs2)

        # This frame encompasses all the buttons
        frmMain = QFrame(self)
        frmMain.setLayout(layVBtns)

        layVMain = QVBoxLayout()
        layVMain.setAlignment(
            Qt.AlignTop)  # this affects only the first widget (intended here)
        layVMain.addWidget(frmMain)
        layVMain.addWidget(self.tblPZ)

        layVMain.setContentsMargins(*params['wdg_margins'])

        self.setLayout(layVMain)

        self.load_dict()  # initialize table from filterbroker
        self._refresh_table()

        #----------------------------------------------------------------------
        # SIGNALS & SLOTs
        #----------------------------------------------------------------------
        self.spnRound.editingFinished.connect(self._refresh_table)
        butLoad.clicked.connect(self.load_dict)
        self.chkPZList.clicked.connect(self.load_dict)

        butSave.clicked.connect(self._save_entries)

        butDelCell.clicked.connect(self._delete_cells)
        butAddRow.clicked.connect(self._add_rows)
        butClear.clicked.connect(self._clear_table)

        butSetZero.clicked.connect(self._zero_PZ)
        # signal itemChanged is also triggered programmatically,
        # itemSelectionChanged is only triggered when entering cell
        # self.tblPZ.itemSelectionChanged.connect(self._copy_item)

        self.tblPZ.cellChanged.connect(self._copy_item)
        self.cmbNorm.activated.connect(self._copy_item)
Exemple #21
0
    def _construct_UI(self):
        """
        Construct the User Interface
        """
        self.layVMain = QVBoxLayout() # Widget main layout

        f_units = ['f_S', 'f_Ny', 'Hz', 'kHz', 'MHz', 'GHz']
        self.t_units = ['', '', 's', 'ms', r'$\mu$s', 'ns']

        bfont = QFont()
        bfont.setBold(True)

        self.lblUnits=QLabel(self)
        self.lblUnits.setText("Freq. Unit:")
        self.lblUnits.setFont(bfont)

        self.fs_old = fb.fil[0]['f_S'] # store current sampling frequency
        self.ledF_S = QLineEdit()
        self.ledF_S.setText(str(fb.fil[0]["f_S"]))
        self.ledF_S.setObjectName("f_S")
        self.ledF_S.installEventFilter(self)  # filter events

        self.lblF_S = QLabel(self)
        self.lblF_S.setText(rt_label("f_S"))

        self.cmbUnits = QComboBox(self)
        self.cmbUnits.setObjectName("cmbUnits")
        self.cmbUnits.addItems(f_units)
        self.cmbUnits.setToolTip(
        "Select whether frequencies are specified with respect to \n"
        "the sampling frequency f_S, to the Nyquist frequency \n"
        "f_Ny = f_S/2 or as absolute values.")
        self.cmbUnits.setCurrentIndex(0)
#        self.cmbUnits.setItemData(0, (0,QColor("#FF333D"),Qt.BackgroundColorRole))#
#        self.cmbUnits.setItemData(0, (QFont('Verdana', bold=True), Qt.FontRole)

        fRanges = [("0...½", "half"), ("0...1","whole"), ("-½...½", "sym")]
        self.cmbFRange = QComboBox(self)
        self.cmbFRange.setObjectName("cmbFRange")
        for f in fRanges:
            self.cmbFRange.addItem(f[0],f[1])
        self.cmbFRange.setToolTip("Select frequency range (whole or half).")
        self.cmbFRange.setCurrentIndex(0)

        # Combobox resizes with longest entry
        self.cmbUnits.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.cmbFRange.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        self.butSort = QToolButton(self)
        self.butSort.setText("Sort")
        self.butSort.setCheckable(True)
        self.butSort.setChecked(True)
        self.butSort.setToolTip("Sort frequencies in ascending order when pushed.")
        self.butSort.setStyleSheet("QToolButton:checked {font-weight:bold}")

        self.layHUnits = QHBoxLayout()
        self.layHUnits.addWidget(self.cmbUnits)
        self.layHUnits.addWidget(self.cmbFRange)
        self.layHUnits.addWidget(self.butSort)

        # Create a gridLayout consisting of QLabel and QLineEdit fields
        # for setting f_S, the units and the actual frequency specs:
        self.layGSpecWdg = QGridLayout() # sublayout for spec fields
        self.layGSpecWdg.addWidget(self.lblF_S,1,0)
        self.layGSpecWdg.addWidget(self.ledF_S,1,1)
        self.layGSpecWdg.addWidget(self.lblUnits,0,0)
        self.layGSpecWdg.addLayout(self.layHUnits,0,1)

        frmMain = QFrame(self)
        frmMain.setLayout(self.layGSpecWdg)

        self.layVMain.addWidget(frmMain)
        self.layVMain.setContentsMargins(*params['wdg_margins'])

        self.setLayout(self.layVMain)

        #----------------------------------------------------------------------
        # SIGNALS & SLOTs
        #----------------------------------------------------------------------
        self.cmbUnits.currentIndexChanged.connect(self.update_UI)
        self.cmbFRange.currentIndexChanged.connect(self._freq_range)
        self.butSort.clicked.connect(self._store_sort_flag)
        #----------------------------------------------------------------------

        self.update_UI() # first-time initialization